Local setup and development¶
For developers and operators only
This section is for working on PK-DB itself or running a separate server. General users do not need a source checkout, Docker, a database, or administrator access. To use PK-DB, start with Browse and access data or the Python client and API.
Run the backend, frontend, and PostgreSQL locally with Docker Engine and the Docker Compose plugin. No host Python, Node.js, PostgreSQL, mail server, or external authentication service is needed for this setup.
Quick start¶
Clone the repository (git clone https://github.com/matthiaskoenig/pkdb.git) and change into it (cd pkdb). From the repository root, set PKDB_ADMIN and PKDB_ADMIN_EMAIL to your chosen administrator username and email address, then start the services and create the administrator:
export PKDB_ADMIN=your-username
export PKDB_ADMIN_EMAIL=you@example.org
PKDB_BUILD_COMMIT="$(git rev-parse HEAD)" docker compose --profile dev up --build --wait
docker compose exec backend pkdb-server create-admin "$PKDB_ADMIN" --email "$PKDB_ADMIN_EMAIL"
Enter a password at the hidden prompt. Create the administrator once; subsequent starts preserve the account. There is one designated administrator per database, identified by its internal account ID. The username is your choice. The email is marked verified by this operator command, so local login and API-key creation work without SMTP.
The first build downloads dependencies. Startup applies database migrations and loads the bundled vocabulary. Defaults work without an environment file.
| Open | Purpose |
|---|---|
| http://localhost:8080 | Frontend; sign in with the username and password you chose |
| http://localhost:18083/docs | Backend API documentation |
| http://localhost:18083/health/ready | Backend readiness check |
The frontend proxies API requests to the backend, including browser session cookies and CSRF. Use localhost consistently for browser login. Both HTTP ports bind only to the local machine.
Populate the database with our users¶
As the third setup command, load the bundled historical curator/reviewer roster and avatars:
docker compose exec backend pkdb-server import-users /app/bootstrap/curator-roster.json --avatar-root /app/frontend/public --apply
Use --dry-run instead of --apply to preview changes first, especially on an existing database. The public roster contains 69 historical entries: 67 curator/reviewer accounts are imported on a fresh database; the historical test account is excluded, and the historical administrator profile is skipped unless it matches the already designated administrator. Choosing another admin username does not rename or adopt that historical identity. The empty users.json is not the user roster. Compose mounts the bundled avatars read-only and the importer copies them into persistent backend storage.
Imported users retain their attribution, roles, and profile data, but new imported accounts have no usable password and remain disabled. Repeating the same import is safe: it preserves credentials, account state, and later profile edits. Existing role or study-assignment changes require a reviewed dry run and --update-existing on both preview and apply.
Active accounts for local testing¶
For immediate login as a curator, create a separate test account with a username absent from the historical roster:
docker compose exec backend pkdb-server create-user local-curator --role curator --email local-curator@example.org
Enter its password when prompted. Use --role reviewer to test reviewer access to public studies, or omit --role for an ordinary reader. Private-study access requires an explicit curator assignment unless the account is the administrator. Email is optional for browser login; supply it when testing personal API keys. These commands create new accounts and never overwrite imported users or reset existing passwords.
Invite the real users¶
Provide reviewed email addresses in a private JSON file outside the repository, for example /absolute/path/contacts.json:
Mount it read-only for the import. Preview, resolve any conflicts, then repeat with --apply in place of --dry-run:
docker compose run --rm --no-deps \
--volume /absolute/path/contacts.json:/private/contacts.json:ro \
backend pkdb-server import-users /app/bootstrap/curator-roster.json \
--avatar-root /app/frontend/public --contacts /private/contacts.json --dry-run
Configure SMTP in .env and recreate the backend with docker compose --profile dev up -d --wait. Sign in as the administrator and use User administration → Invite. Recipients accept the invitation and choose their own password. Importing does not send mail or activate users. See account administration for contact overlays, existing account IDs, and study assignments.
Load studies and test uploads¶
The initial database contains vocabulary and any users you imported, but no studies. Follow the minimal local upload setup for the complete sequence: start Docker, create the administrator, import users, prepare attribution accounts, and validate and upload with the pkdb Python package. This uses the same running stack and does not require another backend installation.
Daily development¶
Start the live frontend at http://localhost:8080 with:
Keep this stack running while editing the GUI. Save a Vue, TypeScript, or CSS file under frontend/src/ and Vite updates the open browser through hot module replacement, preserving component state where possible. Changes to assets in frontend/public/ trigger a page reload. You do not need to rebuild the image or refresh the browser for these edits. The source directories are mounted into the Vite container. Docker development uses polling every 250 ms so changes are detected even when bind-mount filesystem events are missed. Set PKDB_DEV_USE_POLLING=false in .env to use native filesystem events when those work reliably. Rebuild after dependency or frontend configuration changes. Backend code is built into its image; after changing it, run:
Stop and resume without losing database or attachment data:
docker compose --profile dev down also preserves named volumes. Adding --volumes deletes the local database and attachments. The project is named pkdb-current; it does not reuse older deployment volumes. Inspect failures with docker compose --profile dev logs --tail=100 backend db frontend.
Configuration¶
Copy .env.example to .env if you need overrides. PKDB_HTTP_PORT changes the backend's host port (default 18083); the container frontend always reaches it on http://backend:8000. Keep PKDB_BROWSER_ORIGIN=http://localhost:8080 for the default frontend. The database password must be URL-safe because it appears in the connection URL. Changing it after database initialization does not change the stored PostgreSQL password.
Native frontend and frontend checks¶
For a host frontend with the Docker backend, start only the database and API with docker compose up --build --wait. If you use the native backend instead, keep that process running and skip this Compose startup. Stop any Docker frontend with docker compose --profile dev stop frontend. Install Node 24.21.0 and npm 12.1.0, then run:
The development proxy defaults to http://127.0.0.1:18083. Set PKDB_DEV_API_TARGET=http://127.0.0.1:YOUR_PORT when starting Vite if you changed the backend host port. Keep VITE_API_BASE empty for same-origin requests. Native Vite uses filesystem events by default; set PKDB_DEV_USE_POLLING=true if your filesystem does not reliably deliver change notifications.
Run frontend checks from frontend/:
npm run test:source
npm run typecheck
npm run lint
npm run test:unit -- --run
npm run build
npx playwright install --with-deps
npm run test:e2e
Browser tests use a separate disposable Compose project. See isolated frontend browser checks.
Native backend server¶
Use this workflow when you need automatic backend reloads. Stop the Compose backend first so port 18083 is free; this native workflow uses a separate development database and file directory:
docker compose --profile dev stop backend frontend
docker run --detach --name pkdb-native-db \
--publish 127.0.0.1:15438:5432 \
--env POSTGRES_DB=pkdb_dev --env POSTGRES_USER=pkdb_dev \
--env POSTGRES_PASSWORD=local-development-only \
--mount source=pkdb-native-database,target=/var/lib/postgresql \
postgres:18.6
docker exec pkdb-native-db pg_isready -U pkdb_dev -d pkdb_dev
Wait for pg_isready to report that PostgreSQL accepts connections. On subsequent starts, use docker start pkdb-native-db instead of creating it again. From the repository root:
uv sync --project backend --locked --python 3.14
export PKDB_DATABASE_URL=postgresql+psycopg://pkdb_dev:local-development-only@127.0.0.1:15438/pkdb_dev
export PKDB_FILE_ROOT="$PWD/.cache/native-files"
export PKDB_BROWSER_ORIGIN=http://localhost:8080
export PKDB_SECURE_COOKIES=false
export PKDB_ADMIN=your-username
export PKDB_ADMIN_EMAIL=you@example.org
mkdir -p "$PKDB_FILE_ROOT"
cd backend
uv run --locked alembic upgrade head
uv run --locked pkdb-server bootstrap bootstrap
uv run --locked pkdb-server create-admin "$PKDB_ADMIN" --email "$PKDB_ADMIN_EMAIL"
uv run --locked uvicorn pkdb_server.app:create_app --factory --reload --host 127.0.0.1 --port 18083
Create the administrator only once and choose its password at the prompt. In another terminal, start the native frontend; its default proxy reaches this API on port 18083. Keep the environment variables set for subsequent native API and migration commands. This local database and its accounts are independent of beta.pk-db.com.
Backend tests and checks¶
The library and backend support Python 3.14 and 3.15 (currently tested with 3.15.0rc2). Python 3.15 currently uses the Pydantic 2.14 beta for native dependency wheels and the beartype 0.23 release candidate for MCP compatibility. Python 3.14 remains the default for local development, hooks, and Docker. To build the Python 3.15 runtime, use docker build --build-arg PYTHON_VERSION=3.15 -f backend/Dockerfile ..
Install uv and Python 3.14 for the development hooks. Run from the repository root (use --python 3.15 to select Python 3.15):
uv sync --project backend --locked --python 3.14
uv run --project backend pre-commit install
docker compose -f compose.test.yaml up -d --wait
export PKDB_TEST_DATABASE_URL=postgresql+psycopg://pkdb_test:local-test-only@127.0.0.1:15439/pkdb_test
uv run --project backend pytest backend/tests -q -x
uv run --project backend python -m pytest tools/backend_migration -q -x
uv run --project backend ruff check .
uv run --project backend ruff format --check .
uv run --project backend ty check --project backend
The test database uses temporary container storage. Tests create isolated schemas. Keep it separate from your upload-testing database. Stop it with docker compose -f compose.test.yaml down.
Image lifecycle and backup/restore tests live in backend/system_tests. They require Docker, a built image selected by PKDB_TEST_IMAGE, and the test database URL. CI runs these tests on Python 3.14 and 3.15. Corpus tests require explicitly configured source data and are not part of the default suite.
Migrations¶
Commit Alembic migrations in backend/alembic/versions/. Compose applies them before starting the API. The ASGI application itself does not mutate database schemas. For native development, set PKDB_DATABASE_URL, change into backend/, and run uv run alembic upgrade head. Check model/schema agreement with uv run alembic check.
The unified data-model baseline (p001initial) requires an empty database and fresh study uploads. Historical migration revisions are no longer supported. Follow the local upload guide for account setup and uploading, and the data-model guide for the baseline details. Migration p006studyformat upgrades an existing database to study format 2 and processing version 9; every study must be uploaded again afterwards, see upgrade to study format 2.
Documentation¶
Zensical builds independently of the backend:
uvx --python 3.14 --with-requirements docs/requirements.txt zensical build --clean
uv run --no-project --python 3.14 python scripts/llms_txt.py
Branches and releases¶
Use a topic branch and a pull request against develop. Required checks are tests, ruff, ty, and docs. The tests check covers both Python versions and a fresh Compose startup/restart smoke test. Release automation uses .bumpversion.toml to update package metadata, the lockfile, and the runtime version together. Do not edit generated changelogs manually.