---
title: "Structure"
description: "Apps, packages and the rules between them."
url: https://docs.skiffr.findmalek.engineer/docs/structure
markdown: https://docs.skiffr.findmalek.engineer/docs/structure.md
---

# Structure

```text
skiffr/
├─ apps/
│  ├─ web/          landing page, next
│  ├─ dashboard/    profile, answers, queue, stats, next
│  ├─ api/          orpc on bun
│  ├─ extension/    chrome extension, wxt and react
│  ├─ e2e/          playwright suite for the extension
│  └─ docs/         this site, fumadocs on next
├─ packages/
│  ├─ ui/           shadcn components and theme tokens
│  ├─ common/       shared zod schemas, constants and utils
│  ├─ orpc/         procedures and clients, built on common
│  ├─ db/           drizzle schema, migrations, seed scenario
│  ├─ ai/           field mapping and answer drafts, vercel ai sdk
│  ├─ auth/         better-auth setup
│  ├─ env/          zod-validated env
│  ├─ storage/      s3 compatible storage
│  └─ config/       shared tsconfig
├─ docker/          local postgres compose file
└─ turbo.json
```

## Rules

- `apps/api` is the only app that touches the database, auth and providers. `web`, `dashboard` and the extension call it through `@skiffr/orpc`, so secrets and data access live in one place
- anything used by more than one app or package goes in `@skiffr/common`: schemas and their types, constants, small utils. Don't redeclare a type in an app when one exists there
- the theme lives in `packages/ui/src/styles/theme.css`, use its tokens instead of raw colors
- the database schema is in `packages/db/src/schema`, change it and run `pnpm db:generate` to get a migration, never write one by hand

## Adding an endpoint

1. put the input and output schemas in `packages/common/src/schemas`
2. add the procedure in `packages/orpc/src/routers`
3. call it from an app with `orpc.<router>.<procedure>` in client components or `call((api) => ...)` on the server
