Files
Reactive-Resume/AGENTS.md
T

7.8 KiB

AGENTS.md

Cursor Cloud specific instructions

Overview

Reactive Resume is a pnpm monorepo (Turborepo) with a single full-stack web app at apps/web (TanStack Start / React 19 / Vite) and ~15 internal packages under packages/. It runs as a single Node.js process on port 3000.

Internal packages are source-consumed through package.json export maps that point at src files. Do not assume package-local dist output exists unless a package explicitly adds it.

Prerequisites

  • Node.js 24 (matches Dockerfile ARG NODE_VERSION=24). Use nvm install 24 && nvm use 24 if needed.
  • Docker is required to run PostgreSQL. Start it with sudo dockerd & if the daemon isn't running.
  • pnpm 11.0.9 is managed via corepack (corepack enable).

Codebase map

  • apps/web is the only app. It owns TanStack Start routes, Vite/Nitro config, PWA setup, oRPC client wiring, route-level server handlers, and the resume builder UI.
  • packages/api contains oRPC routers, services, DTOs, storage, resume access policy, statistics, AI services, and rate limiting. The web route apps/web/src/routes/api/rpc.$.ts exposes these routers at /api/rpc.
  • packages/auth contains Better Auth config, auth helper functions, and exported auth types. The web route apps/web/src/routes/api/auth.$.ts delegates to auth.handler.
  • packages/db contains the Drizzle client and schema. Migration files live at the repo root in migrations/.
  • packages/env defines server environment validation and auto-loads the root .env for app/server code.
  • packages/schema contains Zod schemas and typed resume/page/template models.
  • packages/pdf contains the React PDF document, font registration, shared template primitives, and template implementations.
  • packages/ui contains shared Base UI/shadcn-style components and hooks.
  • packages/fonts, packages/email, packages/import, packages/ai, packages/utils, packages/scripts, packages/config, and packages/runtime-externals provide focused support surfaces. Prefer their existing exports over adding cross-package shortcuts.

Web app conventions

  • Routes are file-based under apps/web/src/routes. Do not hand-edit apps/web/src/routeTree.gen.ts; it is generated by TanStack Router tooling.
  • Server-only route handlers use route server.handlers blocks, for example api/rpc.$.ts, api/auth.$.ts, api/health.ts, uploads, schema, OpenAPI, MCP, and .well-known routes.
  • apps/web/src/router.tsx initializes router context with queryClient, orpc, theme, locale, session, and flags. Reuse route context where possible instead of refetching these concerns ad hoc.
  • The builder shell lives under apps/web/src/routes/builder/$resumeId. The nested preview route is client-only (ssr: false), while the public resume route apps/web/src/routes/$username/$slug.tsx uses ssr: "data-only".
  • Browser-only resume preview code is split across apps/web/src/components/resume/preview.tsx, preview.browser.tsx, pdf-canvas.tsx, and shared helpers. Keep PDF.js/canvas/browser APIs out of SSR paths.
  • The isomorphic oRPC client is in apps/web/src/libs/orpc/client.ts; server calls use an in-process router client and browser calls use /api/rpc with credentials included.

Package and feature boundaries

  • Add new API procedures in packages/api/src/routers/* and keep business logic in packages/api/src/services/* or helpers. Prefer protectedProcedure from packages/api/src/context.ts for authenticated procedures.
  • Add database columns/tables in packages/db/src/schema/*, then generate root-level migrations with pnpm db:generate.
  • Add or change resume data shape in packages/schema/src/resume/* first, then update API DTOs, importers, PDF rendering, and web forms that consume that shape.
  • Add or rename templates in all relevant places: packages/schema/src/templates.ts, packages/pdf/src/templates/index.ts, template source under packages/pdf/src/templates/<name>/, and static previews under apps/web/public/templates/{jpg,pdf}.
  • Shared PDF section filtering lives in packages/pdf/src/templates/shared/filtering.ts. Keep template-specific visual exceptions in the owning template directory unless multiple templates need the same behavior.
  • packages/pdf/src/hooks/use-register-fonts.ts owns React PDF font registration, standard PDF font handling, CJK fallback stacks, and global hyphenation behavior.
  • packages/utils has narrowly exported helpers. If another package needs a utility, add an explicit export path instead of importing private files.

Database

PostgreSQL runs via Docker Compose:

sudo docker compose -f compose.dev.yml up -d postgres

The dev default connection string is postgresql://postgres:postgres@localhost:5432/postgres.

Important: drizzle-kit (used by pnpm db:migrate) reads DATABASE_URL from process.env directly — it does not auto-load the .env file. You must export DATABASE_URL=... before running migration commands, or set it in your shell profile.

The web app also runs migrations during Nitro startup via apps/web/plugins/1.migrate.ts. Manual pnpm db:migrate is mainly for first setup, migration debugging, or applying migrations without starting the app.

Environment

Copy .env.example to .env. The three required variables are:

  • APP_URL (default http://localhost:3000)
  • DATABASE_URL (default postgresql://postgres:postgres@localhost:5432/postgres)
  • AUTH_SECRET (any non-empty string)

S3/SeaweedFS is optional. If S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, and S3_BUCKET are all set, the app uses S3-compatible storage. The checked-in .env.example sets SeaweedFS defaults, so either start the seaweedfs compose service too or comment out those S3 vars to use local filesystem storage under <workspace>/data. LOCAL_STORAGE_PATH must be absolute when set.

Common commands

Task Command
Install deps pnpm install
Start Postgres only sudo docker compose -f compose.dev.yml up -d postgres
Start Postgres + SeaweedFS sudo docker compose -f compose.dev.yml up -d postgres seaweedfs seaweedfs_create_bucket
Generate migrations DATABASE_URL="postgresql://postgres:postgres@localhost:5432/postgres" pnpm db:generate
Run migrations DATABASE_URL="postgresql://postgres:postgres@localhost:5432/postgres" pnpm db:migrate
Dev server pnpm dev (starts on port 3000)
Web dev server only pnpm dev:web
Lint/format pnpm check (Biome)
Tests pnpm test (Vitest)
Build pnpm build
Typecheck pnpm typecheck

For focused validation, prefer package filters before repo-wide commands, for example:

pnpm --filter web typecheck
pnpm --filter @reactive-resume/pdf test
pnpm --filter @reactive-resume/api test

Vitest test paths are package-relative when running through pnpm --filter <package> test -- <path>.

Gotchas

  • The dev server (pnpm dev) auto-runs migrations on startup via Nitro, so pnpm db:migrate is only strictly needed for first-time setup or after pulling new migration files.
  • Email sending requires SMTP config; without it, emails are logged to console. This is fine for dev — the app still functions, but email verification links appear in server logs.
  • The lefthook.yml pre-commit hook runs biome check on staged files. Run pnpm check before committing to avoid hook failures.
  • pnpm check is write-capable (biome check --write --unsafe .). Call that out when using it, and use narrower Biome commands if you need a non-mutating inspection.
  • Biome uses tabs, double quotes, line width 120, organized import groups, and sorted Tailwind classes for clsx, cva, and cn.
  • Most packages use tsgo --noEmit for typechecking and vitest run --passWithNoTests for tests.
  • There may be unrelated local edits in the worktree. Inspect git status --short first and avoid reverting files you did not touch.