Build Status
Live state of the dashboard build, broken into Infrastructure / Frontend / Backend / Database tables. Each row is Done, Planned, Stub only, or a freeform note. Last updated 2026-06-26 (hosting moved to Vercel per D20; /projects service-role read fix).
Infrastructure
| Area | Status |
|---|---|
| GitHub repo | Live — aj-225/aj-dashboard |
| DigitalOcean droplet | Provisioned — 8GB/160GB, SYD1, Node 22 |
| Caddy config | Done — dashboard.finchmax.com block added |
| DNS (A record) | Done — dashboard.finchmax.com → 209.38.85.129, propagating |
| systemd service | Live 2026-05-23 — setup-droplet.sh run; aj-dashboard.service active on the droplet, serving the built Next.js app on port 3000 behind Caddy. |
| Hosting | Vercel as of 2026-06-26 (D20). Production /projects etc. served from Vercel. The droplet stays up for OpenClaw but no longer serves aj-dashboard. |
| GitHub Actions deploy | Disabled 2026-06-26 (D20) — droplet auto-deploy turned off; on: trigger in .github/workflows/deploy.yml commented out (job body retained). Was live 2026-05-23 (droplet SSH deploy, commit 72ffe78); superseded by Vercel. |
| First deploy | Complete 2026-05-23 — initial droplet deploy of dashboard.finchmax.com (historical; hosting since moved to Vercel). |
| SSL/HTTPS | Live — on Vercel for the dashboard; Caddy on the droplet (now dashboard-dormant) still holds the historical cert. |
Frontend
| Area | Status |
|---|---|
| Project scaffold | Committed — Next.js 15, Tailwind, shadcn/ui, all configs |
| Design handoff bundle | Committed — design/handoff/ with all Claude Design outputs |
| Brand spec (BRAND.md) | Committed — 8 rules, 5 primitives, acceptance criteria |
| Design tokens (globals.css) | Committed — CSS variables, do not edit |
| Tailwind config | Committed — theme mapping to CSS vars |
| Mock data | Committed — complete data for Today, Tasks, BC tabs |
| Root layout + sidebar | Done — next/font wired to --ar-font-*, sidebar matches Direction A (forest-deep, ExtensaMark, sub-brand tiles, copper active rail) |
| Today page | Done — Direction A build at /today. All 7 numbered sections (calendar, priority, cash 2x2, waiting-on, since-yesterday, 7-day events). / redirects to /today. |
| Tasks page | Done — Direction A build at /tasks. Quadrant/Delegation tab toggle, entity colour filter (multi-select), 2x2 quadrant grid, delegation flat table. |
| Bright Connect page | Done — Direction A build at /bright-connect. Hero (LogoMark + heading + balance), bank balance + projection chart with 7D/1M/3M/6M/12M toggle, OKRs, HubSpot revenue-by-rep, HubSpot pipeline-by-stage, 30-day events row. |
| TQC page | Done — same shape as BC at /tqc. Hero with TQC LogoMark + "The Quote Company + LMS", declining-trend chart, OKRs (cashflow/conversion/referral), HubSpot lead flow (5 stages), LMS-iframe placeholder card (awaiting Steven Miles' PHP hook), 30-day events. |
| TCE page | Done — same shape as BC at /tce. Hero with TCE LogoMark + "Take Charge Energy", recovery-trend chart, OKRs (Karratha backlog/install margin/WA fleet), HubSpot sales manager (3 reps with copper-tipped leader), HubSpot install lead flow, 30-day events. Runway flagged red (19 days). |
| Personal Finance page | Done — at /personal-finance. Net wealth hero ($959,090 = cash $160k + investments $799k), net wealth chart with period toggle, personal OKRs (super cap, emergency fund), bank-accounts list (Westpac/Macquarie/ANZ Amex with red negative balance), investments list (Vanguard Family Trust + SMSF with 30D deltas), 60-day finance calendar. |
| Personal & Health page | Done — at /personal-life. Hero "Off-the-clock, still tracked", upcoming health appointments with copper italic dates, household task list with done items struck through, 60-day personal events row. |
| Lists page | Done — at /lists. Three side-by-side panels (Books, Films, Restaurants) with NOW/NEXT/DONE status pills (copper for now, forest for next, muted strikethrough for done). |
| Brand primitives | Done — ExtensaMark, Card, EntityBadge (3 variants), StatusDot, Eyebrow, RegMarks, LogoMark (square-only after compliance audit), Quadrant, Spark (with responsive prop), HBar, Progress, OwnerChip. Demo at /brand-demo. |
| Entity-tab shared components | Done 2026-05-06 — components/entity/ exposes EntityHero, ProjectionChartCard (owns its own period-toggle state — only piece needing 'use client'), OkrsCard, EventsCard. BC/TQC/TCE/PF all refactored to use them. Pages went from ~290 LOC avg to ~120 LOC avg; client-bundle dropped ~50% (3.46-3.79 kB → 1.82 kB) because the pages themselves are now server components. Future entity tabs (e.g. Solar Market split, Source Energy) inherit the structure. |
| Brand-compliance audit | Done 2026-05-05 — static + visual sweep of all 9 routes; lib/fmt.ts canonicalised; mock-data formatter duplicates removed; inline date parsing centralised on TODAY_DAY_SHORT; BC hardcoded $ strings replaced; ! glyph swapped for ×; LogoMark hardcoded radius + rounded-full variant removed |
| Cmd+K search | Done — global ⌘K/Ctrl+K command palette mounted in root layout. Fuzzy search across 100 indexed items (tasks, meetings, entities, contacts, waiting-on, since-yesterday feed, events, lists). Brand-styled dialog: forest-deep header, copper-rail focus, Newsreader input, Plex Mono captions, RegMarks. Esc / backdrop click closes. Enter navigates to the item's route. See lib/search.ts for the index builder and components/search/command-palette.tsx for the UI. |
| Test runner | Done — Vitest 4 + jsdom (env switched 2026-05-06 per D17). npm test / test:watch / typecheck scripts. 77 assertions across 6 files: lib/__tests__/{fmt,search}.test.ts and components/entity/__tests__/{hero,projection-chart-card,okrs-card,events-card}.test.tsx. @testing-library/react + @testing-library/jest-dom adopted (D17 supersedes D16's RTL deferral). Suite runs in under 2 s. |
| Accessibility (Lighthouse a11y target) | Done 2026-05-06 — axe-core 4.10 against all 9 routes goes from 69 nodes of WCAG AA violations to zero on the 8 user-facing routes (brand-demo retains 5 deliberate showcase variants). Skip-to-main link added; <main id="main"> target. role="tab" + aria-selected on period and view toggles. CashTile, palette, calendar NOW indicator, sub-brand row all carry the right ARIA semantics. Brand co-designed with a11y per D18 — small-caption copper → copper-2, fg-4 → fg-3, sidebar monograms → plain colour squares, hero LogoMark → bold to qualify for WCAG "large text" 3:1. |
| Mobile breakpoint | Done 2026-05-06 — /today now ships a pixel-precise mobile branch matching A_TodayMobile from design/handoff/option-a.jsx. Forest-deep header strip with greeting + Extensa wordmark + lede, paper meta strip, horizontal-scrolling cash row with fmtAUDCompact (≥$100k → "$Xk", smaller stays full), compact 4-meeting calendar with "+N more →", trimmed priority and waiting-on lists. Renders alongside the desktop tree, swapped via Tailwind lg:hidden / hidden lg:flex. Other routes still use the responsive-grid collapse from the original pass; bespoke mobile design is /today-only for now. |
| Pre-commit hooks | Done 2026-05-09 — husky + lint-staged wired (D19). pre-commit runs lint-staged (eslint --fix --max-warnings=0 on staged TS/TSX); pre-push runs npm run typecheck && npm test. eslint.config.mjs (flat config) consumes next/core-web-vitals + next/typescript via FlatCompat, with tightened @typescript-eslint/no-unused-vars (_-prefix allowed) and design/handoff/** ignored. Baseline sweep cleared 2 errors + 3 warnings: any in tce-revenue route → typed unknown narrowing; unescaped ' in /tqc → ’; unused within/LogoMark imports removed. package.json lint script switched from deprecated next lint → eslint .. Redundant .gitkeep files in components/{brand,layout,tasks,today}/ removed (those dirs now hold real components). |
| Projects tab (MED-017) | Complete 2026-05-10 — PR #1 squash-merged to main (commit 4d19860); production deploy via scripts/deploy.sh verified (/projects + /projects/aj-dashboard both 200, systemd active, leading paragraph rendering from live Supabase, latest cron run 2026-05-10 15:45 UTC succeeded). Phase 6a (2026-05-09): /projects + /projects/[slug] shipped against a node:fs mock-data layer reading the dashboard's own docs/ folder. Card grid composes EntityBadge + StatusBadge + tech stack + relative-time last-update caption. Detail page composes ProjectDetailHeader + ProjectDocRail (groups from INDEX.md) + ProjectDocRenderer (react-markdown + remark-gfm + rehype-sanitize, brand-token component overrides, no inline hex). Active doc via ?doc=…. lib/projects/ module: types.ts, parse-leading-paragraph.ts, parse-index.ts, mock-data.ts, fetch.ts. Phase 6b (2026-05-10): fetch.ts switched to Supabase. Both /projects routes flagged force-dynamic so doc edits surface as soon as the next sync writes to the DB (cron every 15 min, manual invoke ~5s). Toggle behind NEXT_PUBLIC_USE_MOCK_PROJECTS=true for offline dev. Migration 002_projects.sql applied to Personal Supabase ref jxbxqjpzcuovnmsmkhjq with anon SELECT RLS policies and a commit_etag column for the Edge Function fast-path. Edge Function sync-project-docs deployed and scheduled via pg_cron; first-run upserted 9 files in ~5s with no errors. Handover: sync runs every 15 min via pg_cron in Personal Supabase (cron.job jobname sync-project-docs, schedule */15 * * * *); register a new project by inserting into public.projects (next tick picks it up — no redeploy); offline UI work via NEXT_PUBLIC_USE_MOCK_PROJECTS=true in .env.local; manual invoke: POST the function URL with the project's anon JWT as Authorization: Bearer …. Inline edit (2026-05-22): project names on /projects cards are click-to-edit (hover-revealed pencil; Enter saves, Escape cancels) via server action app/projects/actions.ts#updateProjectName → supabasePersonalAdmin service-role client (RLS is anon-SELECT only, so writes must use service-role). Auth gate validates the Supabase session cookie if present (must be aj@finchmax.com); allows local dev when no session yet — tightens to deny-by-default in production once M365 SSO is live. New env var SUPABASE_PERSONAL_SERVICE_ROLE_KEY required for writes. Reads fixed (2026-06-26): all lib/projects/fetch.ts reads (getProjects / getProjectBySlug / getProjectDocs) now go through getSupabasePersonalAdmin() too — the anon path 500'd in production with permission denied for table projects (42501) because 002_projects.sql created an anon RLS SELECT policy but no table GRANT. Both /projects routes are server components so the service-role key stays server-side. supabaseBC/supabaseSM also made lazy getters in the same change. See GOTCHAS. |
Backend / API Routes
| Area | Status |
|---|---|
| HubSpot TCE Revenue | Fully implemented — proven query pattern from POC |
| HubSpot BC Marketing | Stub only |
| HubSpot BC Sales | Stub only |
| HubSpot TQC Leads | Stub only |
| HubSpot TCE Leads | Stub only |
| Banking sync (Basiq) | Stub only — cron endpoint exists |
| Calendar (Graph API) | Stub only |
| LMS token auth | Stub only |
| Supabase BC proxy | Stub only |
| Supabase SM proxy | Stub only |
Database
| Area | Status |
|---|---|
| Personal org migration SQL | 001_core_tables.sql written, not yet run. 002_projects.sql + seed run 2026-05-10 against jxbxqjpzcuovnmsmkhjq — projects + project_doc_snapshots populated for the dashboard project. |
| Personal org Edge Functions | sync-project-docs deployed 2026-05-10 (verify_jwt:true). pg_cron schedule */15 * * * * active. |
| BC org migration SQL | Written — not yet run |
| SM org migration SQL | Written — not yet run |
| Supabase Auth (M365 SSO) | Not configured |
Next up
Phase 2 — Frontend Shell — COMPLETE 2026-05-04:
Today page, sidebar, brand primitivesMobile breakpoint(graceful collapse)Tasks/Covey page (MED-002)Bright Connect entity tab (MED-004)TQC entity tab (MED-005)TCE entity tab (MED-006)Personal Finance (MED-007), Personal & Health (MED-008), Lists (MED-009)
All 9 user-facing routes built. All compile clean. Bundle sizes 102 kB shared First Load JS, 3-3.7 kB per client page (the ones with toggle state).
Next up:
- Visual review pass against
design/handoff/option-a.jsxfor BC/Tasks (the only screens the design fully specs); confirm TQC/TCE/PF/PH/Lists are acceptable since the design doesn't pixel-spec them - Sub-agent integrations — wire MED-003 Integration Spec → Phase 3 data layer
- SML-001 / SML-002 — droplet secrets + first deploy (currently the deploy workflow is
workflow_dispatchonly; see deploy.yml header comment to re-enable push trigger)
After that (Phase 3 — Data Layer):
- Run Supabase migrations
- Connect Personal Supabase — wire CRUD
- API routes for BC and SM orgs
Deferred:
- Phase 4 integrations (M365 SSO, Basiq, HubSpot x5, LMS) — requires Integration Spec
- Phase 5 polish (notifications, Cmd+K search, performance)