Local Setup
Prerequisites
- Node.js 22 (the WebSocket package targets Node 22)
- pnpm 9.15.5 through Corepack
- Docker 24+ with Docker Compose v2
- Git
corepack enable
corepack prepare [email protected] --activate
Clone and Install
git clone https://github.com/obeya-cloud/obeya.git
cd obeya
pnpm install --frozen-lockfile
cp .env.example .env
The template contains safe local database URLs but also contains production placeholders. Do not deploy it unchanged.
Start Local Infrastructure
The base Compose file is the local infrastructure model:
docker compose -f docker/docker-compose.yml up -d
docker compose -f docker/docker-compose.yml ps
| Service | Host port | Purpose |
|---|---|---|
| PostgreSQL 16 | 5433 | Primary database |
| Redis 7 | 6380 | Cache and pub/sub |
| PgBouncer | 6432 | Optional connection-pool testing |
| MinIO | 9010 / 9011 | S3 API / console |
| ClamAV | 3311 | Attachment scanning |
The non-standard host ports avoid common conflicts with locally installed PostgreSQL, Redis, MinIO, and ClamAV.
Apply the Database Contract
Run all three database steps. db:migrate applies the immutable, hash-verified
Drizzle journal; the apply/check pair installs and verifies the reviewed
functions, constraints, indexes, grants, and RLS policies.
pnpm db:migrate
pnpm --filter @probeya/db apply-rls
pnpm --filter @probeya/db check-rls
The migration runner requires DATABASE_ADMIN_URL, serializes concurrent
operators with a PostgreSQL advisory lock, and applies all pending migrations
and ledger rows in one transaction. It never falls back to DATABASE_URL.
Optionally seed demo data after the RLS check passes:
pnpm db:seed
The current seed prints its available accounts when it completes. The primary
demo account is [email protected] / demo1234.
Provision Local Object Storage
The base MinIO container uses the development root identity
probeya_minio / probeya_minio_secret. Configure distinct local application
credentials in .env and keep the root values only for the bootstrap:
MINIO_ROOT_USER=probeya_minio
MINIO_ROOT_PASSWORD=probeya_minio_secret
S3_ACCESS_KEY=probeya_local_app
S3_SECRET_KEY=<generate-a-distinct-local-secret>
S3_BUCKET=probeya-uploads
S3_ENDPOINT=http://localhost:9010
S3_PUBLIC_URL=http://localhost:9010
Then replay the same least-privilege bootstrap used in production:
docker compose \
-f docker/docker-compose.yml \
-f docker/docker-compose.prod.yml \
run --rm --no-deps minio-init
This creates the private bucket and application user. Anonymous reads are limited to avatar and logo prefixes; attachment objects stay private.
Start the Applications
pnpm dev
| Application | URL | Purpose |
|---|---|---|
| Web | http://localhost:8000 | Next.js UI and tRPC/HTTP API |
| WebSocket | ws://localhost:8003 | Real-time collaboration |
| Docusaurus (when started) | http://localhost:3002 | Product documentation dev server |
| Mintlify | http://localhost:3003 | Developer docs dev server |
There is no separate apps/api process. API procedures from packages/api
are hosted by the Next.js application.
Useful Commands
pnpm dev
pnpm lint
pnpm type-check
pnpm test
pnpm build
pnpm db:generate
pnpm db:migrate
pnpm --filter @probeya/db apply-rls
pnpm --filter @probeya/db check-rls
# Destructive: disposable database only
DATABASE_APP_URL="$DATABASE_URL" \
PROBEYA_RLS_ACCEPTANCE_DISPOSABLE=1 \
pnpm --filter @probeya/db test:rls
pnpm db:seed
pnpm db:studio
The live RLS lane connects directly as exact probeya_app and
probeya_admin. It verifies the identities before test discovery and refuses
to run unless the database is explicitly marked disposable.
Troubleshooting
PostgreSQL is not ready
docker compose -f docker/docker-compose.yml ps postgres
docker compose -f docker/docker-compose.yml logs postgres
Wait for probeya-postgres to report healthy, then replay the failed schema
step.
Resetting disposable local data
This deletes every local Compose volume, including database and object data:
docker compose -f docker/docker-compose.yml down -v
docker compose -f docker/docker-compose.yml up -d
pnpm db:migrate
pnpm --filter @probeya/db apply-rls
pnpm --filter @probeya/db check-rls
pnpm db:seed
Never use this reset procedure against a shared or production environment.
Port conflict
Find the conflicting process or change the host-side mapping in
docker/docker-compose.yml:
lsof -i :5433
lsof -i :8000
Authentication secret error
Generate a development secret and place it in .env:
openssl rand -base64 32
See Database Schema Operations for schema authoring and Docker Deployment for the production sequence.