docs/contributing/development.mdx
These steps set up Reactive Resume for local development, whether you're contributing to the project or customizing it for yourself.
```bash
pnpm install
```
```bash
docker compose -f compose.dev.yml up -d postgres redis seaweedfs seaweedfs_create_bucket
```
This starts the following infrastructure services:
- **PostgreSQL** — Database (port 5432)
- **Redis** — AI Agent workspace streams/state (port 6379)
- **SeaweedFS** — S3-compatible storage (port 8333)
<Info>
**From v5.1.0 onwards** — PDF generation now runs entirely in the browser via `@react-pdf/renderer`, so no Browserless or Chromium container is required for development.
</Info>
<Tip>
`compose.dev.yml` can also run the app in a development container with `docker compose -f compose.dev.yml up -d`.
Use the service-filtered command above when you want local editor tooling and `pnpm dev` on the host.
</Tip>
<Tip>
Wait for all services to be healthy before proceeding. Check with `docker compose -f compose.dev.yml ps`.
</Tip>
```bash
cp .env.example .env.local
```
Then edit `.env.local` as needed. For local development on the host, set at minimum:
```bash
# Application
PORT=3000
SERVER_PORT=3001
APP_URL=http://localhost:3000
# Database
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/postgres
# Authentication
AUTH_SECRET=development-secret-change-in-production
# Storage (SeaweedFS)
S3_ACCESS_KEY_ID=seaweedfs
S3_SECRET_ACCESS_KEY=seaweedfs
S3_ENDPOINT=http://localhost:8333
S3_BUCKET=reactive-resume
S3_FORCE_PATH_STYLE=true
# Email (Mailpit for local development)
SMTP_HOST=localhost
SMTP_PORT=1025
SMTP_FROM="Reactive Resume <[email protected]>"
# AI Agent workspace and saved AI providers
REDIS_URL=redis://localhost:6379
ENCRYPTION_SECRET=change-me-to-a-secure-agent-secret-in-production
```
<Tip>
**Email testing**: The development stack includes [Mailpit](https://mailpit.axllent.org/). Emails the app sends are captured there and viewable at [http://localhost:8025](http://localhost:8025), so nothing reaches a real address during development.
</Tip>
```bash
dotenvx run -f .env.local -- pnpm run db:migrate
```
Your local Reactive Resume instance will be available at [http://localhost:3000](http://localhost:3000).
The scripts you will use most during development:
| Command | Description |
|---|---|
dotenvx run -f .env.local -- pnpm dev | Start the web and server development processes |
pnpm build | Build the production web bundle and server bundle |
pnpm start | Start the built production server |
pnpm typecheck | Run TypeScript type checking |
pnpm test | Run Vitest across workspaces |
pnpm exec biome check . | Run a non-mutating Biome check |
pnpm check | Run Biome with write/fix behavior (--write --unsafe) |
pnpm exec turbo boundaries | Check workspace/package boundary rules |
| Command | Description |
|---|---|
dotenvx run -f .env.local -- pnpm run db:generate | Generate migration files from schema changes |
dotenvx run -f .env.local -- pnpm run db:migrate | Apply pending migrations |
dotenvx run -f .env.local -- pnpm run db:studio | Open Drizzle Studio (database GUI) |
| Command | Description |
|---|---|
pnpm run lingui:extract | Extract translatable strings from code |
reactive-resume/
├── apps/
│ ├── web/ # TanStack Start routes, web features, and browser UI
│ └── server/ # Hono production server, HTTP adapters, static serving
├── packages/
│ ├── api/ # oRPC features and business behavior
│ ├── auth/ # Better Auth configuration and helpers
│ ├── db/ # Drizzle client and schema
│ ├── docx/ # DOCX export generation
│ ├── mcp/ # MCP tools, prompts, resources, and metadata
│ ├── pdf/ # React PDF rendering and PDF generation adapters
│ ├── resume/ # Pure resume-domain helpers
│ ├── schema/ # Zod schemas and typed models
│ ├── ui/ # Shared Base UI/shadcn-style primitives
│ └── ...
├── tooling/ # Development-only scripts and repository tooling
├── migrations/ # Generated database migrations
├── docs/ # Documentation
└── data/ # Local development data and uploads
Use Drizzle Studio to explore and manage your database:
dotenvx run -f .env.local -- pnpm run db:studio
This opens a web-based GUI at https://local.drizzle.studio.
packages/db/src/schema/*dotenvx run -f .env.local -- pnpm run db:generate
dotenvx run -f .env.local -- pnpm run db:migrate
<Warning>Always review generated migrations before applying them, especially when working with existing data.</Warning>
Reactive Resume uses Lingui for internationalization.
Use the t macro for strings or <Trans> component for JSX:
import { t } from "@lingui/core/macro";
import { Trans } from "@lingui/react/macro";
// For plain strings
const message = t`Hello, World!`;
// For JSX content
<Trans>Welcome to Reactive Resume</Trans>;
After adding new translatable text, extract them to the locale files:
pnpm run lingui:extract
Translation files live in apps/web/locales, in .po format.
Uses Biome for linting, formatting, import organization, and Tailwind class sorting:
# Non-mutating check
pnpm exec biome check .
# Project script with write/fix behavior
pnpm check
Run TypeScript type checking:
pnpm run typecheck
<Accordion title="Database connection refused">
Ensure Docker containers are running:
```bash
docker compose -f compose.dev.yml ps
docker compose -f compose.dev.yml up -d
```
Check that PostgreSQL is healthy and accessible on port 5432.
</Accordion>
<Accordion title="S3/Storage errors">
Verify SeaweedFS is running and the bucket exists:
```bash
docker compose -f compose.dev.yml logs seaweedfs
docker compose -f compose.dev.yml logs seaweedfs_create_bucket
```
If the bucket wasn't created, restart the bucket creation service:
```bash
docker compose -f compose.dev.yml restart seaweedfs_create_bucket
```
</Accordion>
<Accordion title="Type errors after pulling changes">
The route tree may need regeneration. Run the dev server which auto-generates routes:
```bash
dotenvx run -f .env.local -- pnpm run dev
```
Or run type checking to see specific errors:
```bash
pnpm run typecheck
```
</Accordion>