zaumau.ch is a Nuxt 4 app for shared house stays where some costs should follow who stayed when, and others should be shared evenly.
Each trip has a default split rule for new expenses, and each expense can still be set individually:
By nights stayed: spread the expense across trip nights, then split each night among the people staying that night.Equal per person: split the expense evenly across all trip participants.
The app converts the final balances into a short settlement list. Smaller groups use an exact minimum-transfer solver; larger groups fall back to a fast exact-cent heuristic.
- Nuxt 4 + Vue 3 + TypeScript
- Nuxt UI
- Pinia Colada for frontend remote-state queries and mutations
- Drizzle ORM + Drizzle Kit
- SQLite via
better-sqlite3 - Zod validation
- Vitest
Install dependencies:
npm install
# or
make installCreate the local database path:
cp .env.example .envStart the app:
npm run dev
# or
make devThe repo stays npm-first, but now exposes thin make wrappers for the common flows:
make help
make test
make lint
make typecheck
make build
make verifyThe app uses a file-backed SQLite database.
- Default path:
./data/zaumau.ch.sqlite - Override with
DATABASE_URL - Example:
DATABASE_URL=./data/zaumau.ch.sqlite
Generate Drizzle migrations:
npm run db:generateApply migrations manually if needed:
npm run db:migrateThe server also runs committed migrations automatically on startup.
Remote trip data follows a strict client boundary:
app/api/*contains thin$fetchwrappers for Nitro endpoints.app/queries/*contains Pinia Colada query and mutation wrappers.- Pages, components, and composables use
app/queries/*instead of calling$fetchdirectly.
Local form state still lives close to the UI, while cacheable server state lives in Pinia Colada.
Build the production image:
docker build -t zaumau.ch .Run it with a persisted SQLite directory:
docker run \
--rm \
-p 3000:3000 \
-e DATABASE_URL=/app/data/zaumau.ch.sqlite \
-v "$(pwd)/data:/app/data" \
zaumau.chThe container runs the built Nitro server from .output/server/index.mjs and expects the committed drizzle/ migrations alongside it.
cog.toml configures conventional-commit-based versioning with a v tag prefix.
- CI runs on
npm, notpnpm. - Releases are created from pushes to
main. - The release workflow derives the next version from conventional commits, creates a Git tag and GitHub Release, and publishes a Docker image to GHCR.
Run tests:
npm run testRun static checks:
npm run lint
npm run typecheckBuild for production:
npm run build