---
title: "Set up GAAPcore · Builder's guide · Chappell AI"
description: "The operator, whoever runs your servers, installs the database and the API once. This section is a summary; the exact commands are in api/README.md and migrations/README.md in the GAAPcore repository."
url: https://chappellai.us/guide/05-set-up-gaapcore/
---

Builder's guide · Section 5

# Set up GAAPcore

The operator, whoever runs your servers, installs the database and the API once. This section is a summary; the exact commands are in `api/README.md` and `migrations/README.md` in the GAAPcore repository.

## Steps

1.  **PostgreSQL 15 or later.** Create an empty database owned by a schema-owner role.
2.  **Apply the schema.** As the owner, run `docs/schema.sql` and then every migration in `migrations/`, in order.
3.  **Create the API's login role** and grant it with `api/sql/grant-api-role.sql`. The API never owns the schema. Re-run the grants after every migration.
4.  **Run the installer** once. It creates the first *administrator* writer, and optionally the first company, and prints the administrator's key one time. Store it in your secrets manager straight away; it is stored nowhere else.
5.  **Start the API** with `DATABASE_URL` (the API role's connection) and `PORT`. Check it with `GET /v1/health`.
6.  **Schedule the key cleanup** (`npm run cleanup-keys`) daily, to remove idempotency keys past their retention (at least 30 days).
7.  **Put TLS in front.** Transport security, certificates and network allow-lists are the operator's job. Ideally only your console server, and your other writers, can reach the API at all.

```
cd api && npm install
DATABASE_URL=postgres://owner@host/books npm run install-db -- \
  --owner-name "Pat Lee" --owner-email pat@example.com \
  --company "Acme Coffee" --base-currency USD --time-zone America/New_York

DATABASE_URL=postgres://ak_api:<password>@host/books PORT=8080 npm start
curl https://books.internal.example/v1/health
```

Upgrades today

Each GAAPcore migration currently assumes it is applied in order to a database built from those same migrations. Upgrade-safe migrations for databases already holding live books are on the roadmap. Until then, treat an GAAPcore upgrade as a planned event: back up, apply the new migrations in a copy first, run your tests against it, and only then upgrade production.

## For local development

The reference console's `npm run dev:setup` does all of the above in a Docker container in one step. It creates the database from a pinned GAAPcore checkout, registers the console's writer, creates demonstration people and seeds a ledger. Copy that script as the starting point for your own.
