{"path":"docs/wiki/Development-Guide.md","size":8192,"locked":false,"binary":false,"truncated":false,"content":"# Development Guide\n\nThis guide covers the development workflow for contributing to the Mappers Protocol monorepo: workspace conventions, package relationships, code generation, and best practices.\n\n---\n\n## Workspace Overview\n\nMappers uses **pnpm workspaces** to manage the repository:\n\n| Category          | Path                 | Purpose                                       |\n| ----------------- | -------------------- | --------------------------------------------- |\n| Applications      | `apps/*`             | Deployable services (API server, dashboard)   |\n| Libraries         | `lib/*`              | Shared packages consumed by apps              |\n| Oracle            | `oracle/`            | Workspace package for verification middleware |\n| Tooling and tests | `scripts/`, `tests/` | Integration scripts and Anchor tests          |\n\nThe workspace is defined in `pnpm-workspace.yaml`. The Oracle is intentionally included as a root workspace package so its dependencies resolve through the authoritative `pnpm-lock.yaml` and Dependabot can update it from the root workspace.\n\n---\n\n## Package Manager\n\nThis project uses **pnpm exclusively**. The `preinstall` script rejects npm and yarn:\n\n```bash\n# Correct\npnpm install\npnpm add <package>\npnpm run <script>\n\n# Will fail\nnpm install\nyarn install\n```\n\n---\n\n## Package Dependencies\n\nInternal packages reference each other using `workspace:*` protocol:\n\n```json\n{\n  \"dependencies\": {\n    \"@workspace/db\": \"workspace:*\",\n    \"@workspace/api-zod\": \"workspace:*\"\n  }\n}\n```\n\nThis ensures packages always resolve to the local workspace version, never a published registry version.\n\n### Dependency Graph\n\n```\nlib/api-spec (OpenAPI definition)\n  |\n  |-- codegen --> lib/api-zod (Zod schemas)\n  |-- codegen --> lib/api-client-react (React Query hooks)\n\nlib/db (Drizzle schema)\nlib/sdk (MappersClient + OracleClient)\n\napps/api-server\n  imports: lib/db, lib/api-zod\n\napps/dashboard\n  imports: lib/api-client-react\n```\n\n---\n\n## TypeScript Configuration\n\nThe workspace uses **composite project references** for fast incremental builds:\n\n- `tsconfig.base.json` — shared compiler options (all packages extend this)\n- `tsconfig.json` (root) — references all lib packages for `tsc --build`\n- Each package has its own `tsconfig.json` extending the base\n\n### Type-Checking\n\n```bash\n# Check only lib packages (fast, no app code)\npnpm run typecheck:libs\n\n# Check everything, including the Oracle workspace package\npnpm run typecheck\n\n# Check and test Oracle explicitly\npnpm run typecheck:oracle\npnpm run test:oracle\n\n# Full build (typecheck + package builds)\npnpm run build\n```\n\nThe `typecheck:libs` step must pass before apps can be checked, because apps import types from lib packages.\n\n---\n\n## Code Generation\n\nThe API contract is defined as an OpenAPI specification in `lib/api-spec/`. From it, [orval](https://orval.dev/) generates:\n\n1. **`lib/api-zod/src/generated/`** — Zod validation schemas for every request and response\n2. **`lib/api-client-react/src/generated/`** — TanStack Query hooks with full type safety\n\n### Regenerating\n\n```bash\ncd lib/api-spec\npnpm run codegen\n```\n\nThis runs orval and then type-checks the workspace to verify consistency.\n\n### When to Regenerate\n\n- After modifying the OpenAPI spec\n- After adding, removing, or renaming an API endpoint\n- After changing request/response shapes\n\n**Do not manually edit files in `*/generated/` directories.** They will be overwritten on the next codegen run.\n\n---\n\n## Adding a New API Endpoint\n\n1. **Define the endpoint** in the OpenAPI spec (`lib/api-spec/`)\n2. **Regenerate** — `cd lib/api-spec && pnpm run codegen`\n3. **Implement the handler** in `apps/api-server/src/routes/`\n4. **Use the hook** in `apps/dashboard/` via the generated TanStack Query hook\n\nThe generated Zod schemas automatically validate request params and bodies in the API server. The generated React hooks automatically type the response data in the dashboard.\n\n---\n\n## Database Workflow\n\nThe database layer uses [Drizzle ORM](https://orm.drizzle.team/) with PostgreSQL.\n\n### Schema\n\nThe schema is defined in `lib/db/src/schema/`. Each table has a dedicated file:\n\n```typescript\n// lib/db/src/schema/jobs.ts\nexport const jobsTable = pgTable(\"jobs\", {\n  id: serial(\"id\").primaryKey(),\n  jobId: text(\"job_id\").notNull().unique(),\n  clientPubkey: text(\"client_pubkey\").notNull(),\n  // ...\n});\n```\n\n### Pushing Schema Changes\n\n```bash\ncd lib/db\npnpm run push          # Push schema to database\npnpm run push-force    # Force push (destructive — use with caution)\n```\n\nDrizzle Kit's `push` command compares the TypeScript schema to the actual database and applies the diff. It does **not** generate migration files — it pushes directly.\n\n### Adding a New Table\n\n1. Create a new file in `lib/db/src/schema/` (e.g., `users.ts`)\n2. Export the table and any derived schemas\n3. Re-export from `lib/db/src/schema/index.ts`\n4. Run `pnpm run push` to apply to the database\n\n---\n\n## Smart Contract Development\n\nThe escrow program lives in `programs/project_mappers/src/lib.rs`.\n\n### Build\n\n```bash\nanchor build\n```\n\n### Test\n\n```bash\n# Localnet (spins up a local validator)\nanchor test\n\n# Devnet (uses existing devnet deployment)\nanchor test --provider.cluster devnet\n```\n\n### Deploy\n\n```bash\nanchor deploy --provider.cluster devnet\n```\n\nThe program IDL is output to `idl.json` at the repo root and also copied to `oracle/idl.json`.\n\n---\n\n## Oracle Development\n\nThe Oracle is a Node.js service and a first-class root pnpm workspace package:\n\n```bash\npnpm install\ncd oracle\npnpm run dev\n```\n\nUse the root scripts for strict validation:\n\n```bash\npnpm run typecheck:oracle\npnpm run test:oracle\n```\n\nOracle dependencies are recorded in the root `pnpm-lock.yaml`. Do not create or restore a nested `oracle/package-lock.json`.\n\n---\n\n## Formatting and Linting\n\nThe project uses Prettier for code formatting:\n\n```bash\n# Format all files\nnpx prettier --write .\n\n# Check formatting (CI)\nnpx prettier --check .\n```\n\nThe `.prettierignore` file excludes generated files, build outputs, and lock files.\n\n---\n\n## Supply Chain Security\n\nThe workspace enforces a **minimum release age** of 1 day (1440 minutes) for all npm packages via `pnpm-workspace.yaml`:\n\n```yaml\nminimumReleaseAge: 1440\n```\n\nThis means freshly published npm versions cannot be installed until they've been available for at least 24 hours — providing a buffer for the community to detect and report malicious packages.\n\nIf you absolutely must install a package within its first 24 hours, add it to `minimumReleaseAgeExclude`. This should be extremely rare and temporary.\n\n---\n\n## Project Conventions\n\n- **Package naming:** Apps use `@workspace/<name>`, the SDK uses `@mappers-protocol/sdk`\n- **Module format:** All packages use ESM (`\"type\": \"module\"`)\n- **Exports:** Packages export via `\"exports\"` field in `package.json`, pointing to source TypeScript (not compiled JS)\n- **No barrel re-exports of large modules:** Each package has a focused `index.ts`\n- **Amounts as strings:** All lamport amounts are stored and transmitted as strings (u64 safety)\n\n---\n\n## Common Tasks\n\n| Task                    | Command                               |\n| ----------------------- | ------------------------------------- |\n| Install dependencies    | `pnpm install`                        |\n| Full build              | `pnpm run build`                      |\n| Type-check all packages | `pnpm run typecheck`                  |\n| Type-check Oracle       | `pnpm run typecheck:oracle`           |\n| Test Oracle             | `pnpm run test:oracle`                |\n| Run Anchor tests        | `pnpm run test:anchor`                |\n| Start API server        | `cd apps/api-server && pnpm run dev`  |\n| Start dashboard         | `cd apps/dashboard && pnpm run dev`   |\n| Start Oracle            | `cd oracle && pnpm run dev`           |\n| Push DB schema          | `cd lib/db && pnpm run push`          |\n| Regenerate API code     | `cd lib/api-spec && pnpm run codegen` |\n| Format code             | `pnpm exec prettier --write .`        |\n\n---\n\nSee [Getting Started](Getting-Started.md) for first-time setup, or [Architecture](Architecture.md) for the system design.\n"}