Convex Backend Bootstrap
Status note
This doc captures the initial Convex backend slice landed for #54, plus the first profile foundation slices from #9 through #13.
It is intentionally narrow: enough structure to run Convex locally, generate typed backend helpers, prove the backend is wired, and define profile identity/authority contracts without prematurely locking auth providers, account links, public write flows, billing, or rich presentation features.
Locked decision
- the first backend surface lives in the repo-root
convex/directory - the initial bootstrap should stay schema-light and friendly to anonymous local development
- generated Convex types under
convex/_generated/should be committed
Current implementation
convex/schema.tsdefines the first durableprofilestable for people and communitiesconvex/health.tsexposes a minimal public query,health:status, that confirms the backend is reachable without hard-coding early product domain recordsconvex.jsonpins Convex to Node22so local backend runtime expectations stay aligned with the repo's current Node baselineconvex/tsconfig.jsonprovides the TypeScript settings Convex uses to typecheck backend source files- the web app consumes
health:statusas the first realNext.js -> Convexruntime path, mounting a client-side provider baseline and surfacing the result in the homepage without inventing early product schema - the web app also exposes
/server-status, where a server component usesfetchQueryagainst the samehealth:statusfunction as the initial server-side baseline
Local workflow
- Install dependencies with
pnpm install. - Bootstrap an anonymous local deployment and verify the health query with
pnpm bootstrap:backend:local. - Keep
pnpm dev:backend:localrunning while editing backend files. - Run
pnpm run:backend:health:localfrom a second terminal when you want the same one-shot placeholder health check without using the verify script name directly. - Run
pnpm dev:webif you want to confirm the homepage can render the livehealth:statusresponse through the web app. - Run
pnpm typecheck:backendbefore shipping backend edits. - Run
pnpm check:backend:generatedbefore pushing schema or function changes that may affectconvex/_generated/.
If you want the full repo gate, use pnpm verify. If you only need the web app checks, keep using pnpm verify:web.
Notes:
- Convex writes deployment configuration to the repo-root
.env.localfile. - The local Convex wrapper mirrors the repo-root
CONVEX_URLintoapps/web/.env.localasNEXT_PUBLIC_CONVEX_URLso the web app can follow the normal client-side Convex + Next.js convention without leaking a non-public variable through server props. - That same
NEXT_PUBLIC_CONVEX_URLvalue is also whatfetchQueryuses for the current server-side baseline route, so local client and server reads share one deployment setting. - Anonymous local backend state for this repo is kept under
.convex-home/and.convex-tmp/so the bootstrap does not collide with other Convex projects on the same machine. - Production Convex deploys run from the baseline GitHub Actions workflow when
CONVEX_DEPLOY_KEYis configured; otherwise the deploy job records a skip summary and exits cleanly. - Deploy-time data backfills are declared with
@convex-dev/migrationsand run throughmigrations:runAllafter production function deploys. - Committed files in
convex/_generated/are treated as checked-in build artifacts and should remain diff-free afterpnpm check:backend:generated.
Structure rule
Keep the initial backend slice simple:
- add new schema and functions under
convex/ - avoid introducing product tables until the relevant issue defines the domain slice
- prefer small, typed functions over placeholder complexity
Follow-on issues
#55wires the web app to the first Convex client/runtime path usinghealth:status#64adds the first server-sideNext.js -> Convexdata path withfetchQueryon/server-status- profile schema, auth, billing, and production deployment posture should land in their own issues instead of bloating the bootstrap
#9adds the first product table,profiles#10through#13add profile slugs, type-aware fields, permission contracts, and claim-state helpers while keeping auth/account links deferred
App Router baseline
The current rule is intentionally narrow:
- use
useQueryinside client components when the UI should stay reactive after first render - use
fetchQueryinside server components when the page only needs a server-side read - defer
preloadQueryuntil a real feature needs server-rendered first paint plus a hydrated reactive handoff
This keeps the first App Router pattern copyable without introducing multiple competing baselines before auth and domain work arrive.