This guide documents the local development workflow for contributors working on the Multica codebase.
It covers:
- first-time setup
- day-to-day development in the main checkout
- isolated worktree development
- the shared PostgreSQL model
- testing and verification
- troubleshooting and destructive reset options
Local development uses one shared PostgreSQL container and one database per checkout.
- the main checkout usually uses
.envandPOSTGRES_DB=multica - each Git worktree uses its own
.env.worktree - every checkout connects to the same PostgreSQL host:
localhost:5432 - isolation happens at the database level, not by starting a separate Docker Compose project
- backend and frontend ports are still unique per worktree
This keeps Docker simple while still isolating schema and data.
- Node.js
v20+ pnpmv10.28+- Go
v1.26+ - Docker
- The main checkout should use
.env. - A worktree should use
.env.worktree. - Do not copy
.envinto a worktree directory.
Why:
- the current command flow prefers
.envover.env.worktree - if a worktree contains
.env, it can accidentally point back to the main database
Create .env once:
cp .env.example .envBy default, .env points to:
POSTGRES_DB=multica
POSTGRES_PORT=5432
DATABASE_URL=postgres://multica:multica@localhost:5432/multica?sslmode=disable
PORT=8080
FRONTEND_PORT=3000Generate .env.worktree from inside the worktree:
make worktree-envThat generates values like:
POSTGRES_DB=multica_my_feature_702
POSTGRES_PORT=5432
PORT=18782
FRONTEND_PORT=13702
DATABASE_URL=postgres://multica:multica@localhost:5432/multica_my_feature_702?sslmode=disableNotes:
POSTGRES_DBis unique per worktreePOSTGRES_PORTstays fixed at5432- backend and frontend ports are derived from the worktree path hash
make worktree-envrefuses to overwrite an existing.env.worktree
To regenerate a worktree env file:
FORCE=1 make worktree-envFrom the main checkout:
cp .env.example .env
make setup-mainWhat make setup-main does:
- installs JavaScript dependencies with
pnpm install - ensures the shared PostgreSQL container is running
- creates the application database if it does not exist
- runs all migrations against that database
Start the app:
make start-mainStop the app processes:
make stop-mainThis does not stop PostgreSQL.
From the worktree directory:
make worktree-env
make setup-worktreeWhat make setup-worktree does:
- uses
.env.worktree - ensures the shared PostgreSQL container is running
- creates the worktree database if it does not exist
- runs migrations against the worktree database
Start the worktree app:
make start-worktreeStop the worktree app processes:
make stop-worktreeUse the main checkout when you want a stable local environment for main.
make start-main
make stop-main
make check-mainUse a worktree when you want isolated data and separate app ports.
git worktree add ../multica-feature -b feat/my-change main
cd ../multica-feature
make worktree-env
make setup-worktree
make start-worktreeAfter that, day-to-day commands are:
make start-worktree
make stop-worktree
make check-worktreeThis is a first-class workflow.
Example:
- main checkout
- database:
multica - backend:
8080 - frontend:
3000
- database:
- worktree checkout
- database:
multica_my_feature_702 - backend: generated worktree port such as
18782 - frontend: generated worktree port such as
13702
- database:
Both checkouts use:
- the same PostgreSQL container
- the same PostgreSQL port:
5432
But they do not share application data, because each uses a different database.
Start the shared PostgreSQL container:
make db-upStop the shared PostgreSQL container:
make db-downImportant:
make db-downstops the container but keeps the Docker volume- your local databases are preserved
Main checkout:
make setup-main
make start-main
make stop-main
make check-mainWorktree:
make worktree-env
make setup-worktree
make start-worktree
make stop-worktree
make check-worktreeGeneric targets for the current checkout:
make setup
make start
make stop
make check
make dev
make test
make migrate-up
make migrate-downThese generic targets require a valid env file in the current directory.
Database creation is automatic.
The following commands all ensure the target database exists before they continue:
make setupmake startmake devmake testmake migrate-upmake migrate-downmake check
That logic lives in scripts/ensure-postgres.sh.
Run all local checks:
make check-mainOr from a worktree:
make check-worktreeThis runs:
- TypeScript typecheck
- TypeScript unit tests
- Go tests
- Playwright E2E tests
Notes:
- Go tests create their own fixture data
- E2E tests create their own workspace and issue fixtures
- the check flow starts backend/frontend only if they are not already running
Run the local daemon:
make daemonThe daemon authenticates using the CLI's stored token (multica login).
It registers runtimes for all watched workspaces from the CLI config.
If you see:
Missing env file: .env
or:
Missing env file: .env.worktree
then create the expected env file first.
Main checkout:
cp .env.example .envWorktree:
make worktree-envInspect the env file:
cat .env
cat .env.worktreeLook for:
POSTGRES_DBDATABASE_URLPORTFRONTEND_PORT
docker compose exec -T postgres psql -U multica -d postgres -At -c "select datname from pg_database order by datname;"Check whether the worktree contains .env.
It should not.
The safe worktree setup is:
make worktree-env
make setup-worktree
make start-worktreeThat is expected.
make stopmake stop-mainmake stop-worktree
only stop backend/frontend processes.
To stop the shared PostgreSQL container:
make db-downIf you want to stop PostgreSQL and keep your local databases:
make db-downIf you want to wipe all local PostgreSQL data for this repo:
docker compose down -vWarning:
- this deletes the shared Docker volume
- this deletes the main database and every worktree database in that volume
- after that you must run
make setup-mainormake setup-worktreeagain
cp .env.example .env
make setup-main
make start-maingit worktree add ../multica-feature -b feat/my-change main
cd ../multica-feature
make worktree-env
make setup-worktree
make start-worktreecd ../multica-feature
make start-worktreeMain checkout:
make check-mainWorktree:
make check-worktree