{"owner":"amruthpillai","repo":"reactive-resume","hasSkills":true,"hasMcp":false,"mcpConfig":null,"found":["AGENTS.md"],"files":{"AGENTS.md":"# AGENTS.md\n\n## Cursor Cloud specific instructions\n\n### Overview\n\nReactive Resume is a pnpm monorepo (Turborepo) with two deployable apps: `apps/web` (TanStack Start / React 19 / Vite) and `apps/server` (Hono / Node.js). The production Docker image runs a single Node.js process on port 3000, with `apps/server` mounting the API/auth/MCP/static routes and serving the built web app.\n\nInternal 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.\n\n### Prerequisites\n\n- **Node.js 24** (matches Dockerfile `ARG NODE_VERSION=24`). Use `nvm install 24 && nvm use 24` if needed.\n- **Docker** is required to run PostgreSQL. Start it with `sudo dockerd &` if the daemon isn't running.\n- **pnpm 11.21.0**. Install pnpm directly using the [official installation guide](https://pnpm.io/installation).\n\n### Codebase map\n\n- `apps/web` owns TanStack Start routes, Vite config, PWA setup, oRPC browser client wiring, web features, and the resume builder UI.\n- `apps/server` owns the production Hono app, route composition, auth/RPC/MCP/OpenAPI handlers, static uploads, schema JSON, web-dist fallback serving, and startup checks.\n- `packages/api` contains oRPC routers, DTOs, rate limiting, and feature-owned API modules under `packages/api/src/features/*`. The router export at `@reactive-resume/api/routers` aggregates those feature routers for `/api/rpc`.\n- `packages/auth` contains Better Auth config, auth helper functions, and exported auth types. The server auth adapter in `apps/server/src/http/auth.ts` delegates to `auth.handler`.\n- `packages/db` contains the Drizzle client and schema. Migration files live at the repo root in `migrations/`.\n- `packages/env` defines server environment validation and auto-loads the root `.env` for app/server code.\n- `packages/schema` contains Zod schemas and typed resume/page/template models.\n- `packages/pdf` contains the React PDF document, font registration, shared template primitives, template implementations, and browser/server PDF generation adapters. PDF.js viewer UI stays in `apps/web`.\n- `packages/resume` contains pure resume-domain behavior such as JSON Patch helpers and social-network icon mapping.\n- `packages/docx` contains DOCX export generation.\n- `packages/mcp` contains MCP tools, prompts, resources, server-card generation, and tool metadata.\n- `packages/ui` contains shared Base UI/shadcn-style components and hooks.\n- `packages/fonts`, `packages/email`, `packages/import`, `packages/ai`, `packages/utils`, and `packages/config` provide focused support surfaces. Prefer their existing exports over adding cross-package shortcuts.\n- Development-only scripts live in `tooling/`, not under `packages/`, so packages only contain code bundled by the app/runtime.\n\n### Web app conventions\n\n- 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.\n- Server-owned HTTP behavior lives in `apps/server/src/{http,rpc,mcp,openapi,static,startup}`. Keep API/RPC/auth/MCP/static route wiring in `apps/server`, not in web routes.\n- `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.\n- 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\"`.\n- Browser-only resume preview code lives under `apps/web/src/features/resume/preview`, and public resume PDF viewer code lives under `apps/web/src/features/resume/public`. Keep PDF.js/canvas/browser APIs out of SSR paths and out of `packages/pdf`.\n- 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.\n- For React components with explicit props, prefer a named TypeScript props type over inline object annotations in the function signature, especially once the props include more than one field or generics. For example:\n\n```ts\ntype IntentSelectFieldProps<TValue extends string> = {\n\tlabel: string;\n\tid: string;\n\tvalue: TValue | undefined;\n\toptions: readonly ComboboxOption<TValue>[];\n\tonChange: (value: TValue | undefined) => void;\n};\n\nfunction IntentSelectField<TValue extends string>(props: IntentSelectFieldProps<TValue>) {\n\t// ...\n}\n```\n\n### Package and feature boundaries\n\n- Workspace dependencies must go through package names and package export maps. Do not import another workspace's `src` tree through repository paths, `@reactive-resume/*/src/*`, or TypeScript path aliases.\n- `turbo boundaries` is the executable package-boundary check. Workspace-level `turbo.json` files declare coarse tags:\n  - `app:web` for the TanStack Start app.\n  - `app:server` and `runtime:server` for the Node/Hono process.\n  - `runtime:server` for server-only packages such as API/auth/db/env/email/MCP.\n  - `runtime:browser` for browser-only shared UI.\n  - `runtime:universal` for environment-neutral domain packages.\n  - `role:domain`, `role:infra`, `role:adapter`, `role:api`, `role:rendering`, and `role:tooling` for package intent.\n- Browser/server runtime-specific code should live behind explicit export subpaths such as `@reactive-resume/pdf/browser`, `@reactive-resume/pdf/server`, or `@reactive-resume/env/server`. Keep root exports environment-neutral unless the package is intentionally server-only.\n- Wildcard exports are allowed only for leaf libraries whose public surface is intentionally file-like, currently `@reactive-resume/ui/components/*`, `@reactive-resume/ui/hooks/*`, and schema resume model files. Prefer explicit exports for packages that own runtime behavior.\n- Add new API procedures and business logic inside the owning `packages/api/src/features/*` module. Keep route wiring, DTO usage, helpers, and services colocated by feature/capability, then expose only intentional public surfaces through `packages/api/package.json`. Prefer `protectedProcedure` from `packages/api/src/context.ts` for authenticated procedures.\n- Add database columns/tables in `packages/db/src/schema/*`, then generate root-level migrations with `dotenvx run -f .env.local -- pnpm db:generate`.\n- 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.\n- 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}`.\n- Resume JSON Patch behavior belongs in `@reactive-resume/resume/patch`; do not put resume-domain helpers in `@reactive-resume/utils`.\n- DOCX export behavior belongs in `@reactive-resume/docx`; do not put DOCX builders in `@reactive-resume/utils`.\n- 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.\n- `packages/pdf/src/hooks/use-register-fonts.ts` owns React PDF font registration, standard PDF font handling, CJK fallback stacks, and global hyphenation behavior.\n- PDF generation helpers live behind `@reactive-resume/pdf/browser` and `@reactive-resume/pdf/server`; locale-specific section-title resolution stays in the caller.\n- MCP implementation belongs in `@reactive-resume/mcp`; app packages must not import MCP implementation from another app's source tree.\n- `packages/utils` has narrowly exported helpers. If another package needs a utility, add an explicit export path instead of importing private files.\n\nPlacement decision tree:\n\n1. If the change is a web route, route loader, or user-facing web workflow, start in `apps/web/src/routes` or `apps/web/src/features`.\n2. If the change is a server HTTP route/adapter, startup check, static handler, MCP transport, or OpenAPI/well-known handler, start in `apps/server/src`.\n3. If it is authenticated API behavior, put the contract and implementation in the owning `packages/api/src/features/*` module.\n4. If it is pure resume data behavior with no DB, HTTP, DOM, or PDF renderer dependency, put it in `packages/resume`.\n5. If it renders resume PDFs, put shared React PDF/template code in `packages/pdf`; put PDF.js viewer/canvas UI in `apps/web/src/features/resume`.\n6. If it creates DOCX exports, put it in `packages/docx`.\n7. If it exposes MCP tools/prompts/resources, put it in `packages/mcp`.\n8. If it is a generic UI primitive or hook, put it in `packages/ui`; if it is workflow-specific UI, keep it in the owning web feature.\n9. If it is a narrow cross-cutting helper, add an explicit `packages/utils` export only after checking that no domain package is a better owner.\n\n### Database\n\nPostgreSQL runs via Docker Compose:\n\n```\nsudo docker compose -f compose.dev.yml up -d postgres\n```\n\nThe dev default connection string is `postgresql://postgres:postgres@localhost:5432/postgres`.\n\n**Important**: `drizzle-kit` (used by `pnpm db:migrate`) reads `DATABASE_URL` from `process.env` directly — it does **not** auto-load the `.env` file. Run migration commands through `dotenvx`, for example `dotenvx run -f .env.local -- pnpm db:migrate`, so `DATABASE_URL` is present in the process environment.\n\nThe production server runs migrations during startup before serving traffic. Manual `pnpm db:migrate` is mainly for first setup, migration debugging, or applying migrations without starting the app.\n\n### Environment\n\nCopy `.env.example` to `.env.local`. The three required variables are:\n\n- `APP_URL` (default `http://localhost:3000`)\n- `DATABASE_URL` (default `postgresql://postgres:postgres@localhost:5432/postgres`)\n- `AUTH_SECRET` (any non-empty string)\n\nS3/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.\n\n`REDIS_URL` and `ENCRYPTION_SECRET` are optional for core resume flows, but both are required for saved AI providers and the authenticated `/agent` workspace. Start the `redis` compose service and set both vars in `.env.local` when working on those features. For host-run development, use `REDIS_URL=redis://localhost:6379`; the container-run app uses `REDIS_URL=redis://redis:6379`.\n\nWhen running dev servers or migration commands, prefix the command with `dotenvx run -f .env.local --`. For example: `dotenvx run -f .env.local -- pnpm dev`. Tests, typechecks, linters, boundary checks, and `pnpm build` do not need this prefix by default. If one of those commands fails because a specific environment variable is required, rerun it with the `dotenvx run -f .env.local --` prefix.\n\n### Common commands\n\n| Task | Command |\n|------|---------|\n| Install deps | `pnpm install` |\n| Start Postgres only | `sudo docker compose -f compose.dev.yml up -d postgres` |\n| Start Postgres + SeaweedFS | `sudo docker compose -f compose.dev.yml up -d postgres seaweedfs seaweedfs_create_bucket` |\n| Start full dev infrastructure | `sudo docker compose -f compose.dev.yml up -d postgres redis seaweedfs seaweedfs_create_bucket` |\n| Generate migrations | `dotenvx run -f .env.local -- pnpm db:generate` |\n| Run migrations | `dotenvx run -f .env.local -- pnpm db:migrate` |\n| Dev server | `dotenvx run -f .env.local -- pnpm dev` (starts on port 3000) |\n| Web dev server only | `dotenvx run -f .env.local -- pnpm dev:web` |\n| Lint/format | `pnpm check` (Biome) |\n| Boundary check | `pnpm exec turbo boundaries` |\n| Tests | `pnpm test` (Vitest) |\n| Build | `pnpm build` |\n| Typecheck | `pnpm typecheck` |\n\nFor focused validation, prefer package filters before repo-wide commands, for example:\n\n```\npnpm --filter web typecheck\npnpm --filter @reactive-resume/pdf test\npnpm --filter @reactive-resume/api test\npnpm exec turbo boundaries\n```\n\nVitest test paths are package-relative when running through `pnpm --filter <package> test -- <path>`.\n\n### Gotchas\n\n- The server startup path auto-runs migrations before serving traffic, so `pnpm db:migrate` is mainly needed for first-time setup, migration debugging, or applying migrations without starting the app.\n- 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.\n- The `lefthook.yml` pre-commit hook runs `biome check` on staged files. Run `pnpm check` before committing to avoid hook failures.\n- `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.\n- Biome uses tabs, double quotes, line width 120, organized import groups, and sorted Tailwind classes for `clsx`, `cva`, and `cn`.\n- Most packages use `tsgo --noEmit` for typechecking and `vitest run --passWithNoTests` for tests.\n- There may be unrelated local edits in the worktree. Inspect `git status --short` first and avoid reverting files you did not touch.\n- **New env vars require a `turbo.json` entry.** Turborepo 2.x runs in strict env mode by default — it filters out env vars that are not listed in `globalEnv` (or task-level `env`/`passThroughEnv`). Any new environment variable added to `packages/env/src/server.ts` must also be added to the `globalEnv` array in `turbo.json`, or the variable will be `undefined` inside child processes at runtime even if it is correctly set in the OS/container environment.\n"}}