Frontend & routes
Every route, what it renders, and what it needs.
docs/FRONTEND.md
@verjson/web — Next.js App Router. No database driver, no database credentials. Everything comes
over HTTP from @verjson/api, and the boundary is a lint rule rather than a convention.
Route groups
Groups exist so each set of pages ships only the JavaScript it needs.
| Group | Auth | Ships | Purpose |
|---|---|---|---|
(marketing) | none | no providers | The landing page |
(docs) | none | markdown renderer | /docs — this site |
(board) | none | dashboard only | /dashboard, the build board |
(auth) | none | query + auth + toasts | Login, signup, OAuth callback |
(app) | required | query + auth + toasts + shell | The product |
The board sits outside the guard on purpose: it is an internal build board, and requiring a session to read the roadmap would be friction with no security benefit.
Routes
| Route | Renders | Status |
|---|---|---|
/ | Landing. Build status read from data/dashboard/, so it cannot claim progress the board disagrees with | ✅ |
/docs · /docs/[slug] | This documentation, driven by data/docs/manifest.json | ✅ |
/dashboard | Seven-tab command centre | ✅ |
/style-guide | Live retheming; dev-only save back into globals.css | ✅ |
/login · /signup · /auth/callback | Session entry | ✅ |
/projects | Project list with budget roll-ups | ✅ |
/projects/[id] | Marketing mix picker and the budget table | ✅ |
/approvals | The queue humans and agents converge on | ✅ |
/billing | Plan, usage against limits, Stripe portal | ✅ |
/calendar | Marketing calendar | 🔲 |
/campaigns | Campaign list and live control | 🔲 |
/kpis | One KPI surface | 🔲 |
/integrations | Connect channels, ad accounts, OpenSEO, GitHub, WhatsApp | 🔲 |
Responsive contract
Three real layouts, not one that scrolls sideways.
| Width | Navigation | Content |
|---|---|---|
< md (768) | Drawer behind a menu button | Single column; cards stack |
md–lg | Icons only, label as tooltip and accessible name | Two columns where it helps |
≥ lg (1024) | Icon + label | Full layout; docs and dashboard get a sidebar |
The page body never scrolls horizontally. Anything intrinsically wide — a table, a mermaid diagram, a code block — scrolls inside its own container. A nav that "fits" by hiding items behind a horizontal scroll is not responsive; it is broken at a width nobody tested. That was B-003.
Data access
| Layer | Rule |
|---|---|
lib/api.ts | The only module that knows the API's address. axios + transparent 401 refresh |
lib/*.ts hooks | React Query per feature. Types imported from @verjson/contracts |
| Server components | May read data/ and docs/ from disk. Never the database |
no-restricted-imports | Prisma, @verjson/api and DB drivers are lint errors here |