All pages

Install and run

You are about to get both apps running against your own accounts. This page covers your machine. The following pages explain each provider integration before deployment.

Everything here is reported rather than enforced. Skip Stripe and you still reach a running app, with the checkout route answering 501.

What you need

Tool Version Why
Node 22.12.0 or newer engines in the root package.json
pnpm 11.25.0 pinned by packageManager
git any
Careful

Do not run this repo through corepack. pnpm refuses to self-switch under it and the packageManager check then fails inside nested turbo tasks. Install pnpm directly and invoke pnpm directly.

The short version

  1. Clone and install

    git clone git@github.com:<owner>/<repo>.git
    cd <repo>
    pnpm install

    One lockfile covers all four packages. @ffd/shared has no build step, so there is nothing to compile before the apps can import it.

  2. Fill in the two env files

    cp apps/api/.env.example apps/api/.env
    cp apps/web/.env.example apps/web/.env.local

    Both example files ship with local defaults. SETUP.md directs an agent to obtain the account-backed values through each provider's supported tools and write them directly without exposing credentials in chat or terminal output. The steps only you can take, such as choosing an account or copying a dashboard-only key, run in your terminal through pnpm setup:wizard, which opens each page, takes secrets through hidden input, and checks them against the provider. The provider pages explain those values and the human handoffs. The full list, with which app reads each one, is Environment variables.

  3. Create the database and run the migrations

    pnpm db:migrate

    This creates the target database if it is not there, then applies every migration under packages/shared/drizzle/. It resolves to the development database unless you say otherwise, so migrating production is NODE_ENV=production pnpm db:migrate, typed on purpose.

    Nothing migrates at boot, so this is a step you run rather than something a deploy does for you.

  4. Run both apps

    pnpm dev

    Turbo runs vite dev for the web app on port 3000 and tsx watch for the api on port 5001. Both reload on save, including changes inside packages/shared.

  5. Check that the api agrees with you

    curl http://localhost:5001/health
    {
      "status": "ok",
      "service": "api",
      "uptimeSeconds": 12,
      "database": "ffd_dev",
      "stripeEnv": "test"
    }

    database is the resolved database name, never the URL, which carries a password. stripeEnv is null when no Stripe key is configured, which is a supported state. Those two fields are the two environment axes, and this endpoint is where you find out they disagree.

Let an agent do it

SETUP.md at the repository root is the agent's end-to-end guide. It covers repository work and external provisioning, using CLIs and APIs first and authenticated browser control where needed. It pauses only for account control, consent, approval, or an ambiguous resource choice, then continues the same sequence.

It is a guide, not a gate. Nothing in it is required, and a buyer who skips a section still reaches a running app.

The two commands that gate a change

pnpm check      # Biome, formatting and lint
pnpm typecheck  # tsc --noEmit across every package

There is no test suite in this repository and none ships. That is deliberate: your tests are for your product, and a suite covering FFD's own behaviour would be a suite you delete. The two commands above are the whole gate, and a change that has not passed both is not finished.

No CI configuration ships either, so nothing runs them for you until you add a workflow that does.

pnpm check:fix writes the formatting fixes rather than reporting them.

What runs where

Command What it does
pnpm dev both apps, watching
pnpm build vite build for web, nothing for the api
pnpm db:generate writes the next migration from the schema diff
pnpm db:migrate creates the database if needed, then migrates
pnpm check Biome
pnpm typecheck tsc --noEmit

The api has no build step. It runs under tsx in production too, started by pnpm --filter @ffd/api start.

  • docs/adr/0009-drizzle-v1-on-neon-postgres.md, why nothing migrates at boot
  • docs/adr/0010-typescript-7-and-biome.md, the toolchain

Updated