Skip to main content

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.ts defines the first durable profiles table for people and communities
  • convex/health.ts exposes a minimal public query, health:status, that confirms the backend is reachable without hard-coding early product domain records
  • convex.json pins Convex to Node 22 so local backend runtime expectations stay aligned with the repo's current Node baseline
  • convex/tsconfig.json provides the TypeScript settings Convex uses to typecheck backend source files
  • the web app consumes health:status as the first real Next.js -> Convex runtime path, mounting a client-side provider baseline and surfacing the result in the homepage without inventing early product schema

Local workflow

  1. Install dependencies with pnpm install.
  2. Bootstrap an anonymous local deployment and verify the health query with pnpm bootstrap:backend:local.
  3. Keep pnpm dev:backend:local running while editing backend files.
  4. Run pnpm run:backend:health:local from a second terminal when you want the same one-shot placeholder health check without using the verify script name directly.
  5. Run pnpm dev:web if you want to confirm the homepage can render the live health:status response through the web app.
  6. Run pnpm typecheck:backend before shipping backend edits.
  7. Run pnpm check:backend:generated before pushing schema or function changes that may affect convex/_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.local file.
  • The local Convex wrapper mirrors the repo-root CONVEX_URL into apps/web/.env.local as NEXT_PUBLIC_CONVEX_URL so the web app can follow the normal client-side Convex + Next.js convention without leaking a non-public variable through server props.
  • 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_KEY is configured; otherwise the deploy job records a skip summary and exits cleanly.
  • Deploy-time data backfills are declared with @convex-dev/migrations and run through migrations:runAll after production function deploys.
  • Committed files in convex/_generated/ are treated as checked-in build artifacts and should remain diff-free after pnpm 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

  • #55 wires the web app to the first Convex client/runtime path using health:status
  • profile schema, auth, billing, and production deployment posture should land in their own issues instead of bloating the bootstrap
  • #9 adds the first product table, profiles
  • #10 through #13 add 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 useQuery inside client components when the UI should stay reactive after first render
  • use fetchQuery inside server components when the page only needs a server-side read
  • defer preloadQuery until 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.