3.6 KiB
Travel Planner
Self-hosted, AI-assisted travel planner. Angular PWA frontend, NestJS API + background worker, PostgreSQL, Redis/BullMQ, and a Mistral-backed travel agent behind a strict tool boundary.
.env.examplelists configuration names and non-secret defaults only. Real production secrets (database password, SMTP credentials, LLM API keys, etc.) are never committed and live only on the deployment host / secret store, supplied to containers as environment variables.
Repository layout
frontend/ Angular PWA (pnpm workspace member)
backend/ NestJS workspace: apps/api, apps/worker, libs/*
docker/ Production Dockerfiles and edge (Nginx) config
scripts/ Compose-invariant checks and TeamCity entry points
docs/ Specs, plans, and architecture documentation
Developer setup
pnpm install
pnpm dev:infra
DATABASE_URL=postgresql://travel_planner:travel_planner_dev@localhost:5432/travel_planner \
REDIS_URL=redis://localhost:6379 \
OIDC_ISSUER=https://idp.example.invalid/realms/travel-planner \
OIDC_AUDIENCE=travel-planner-api \
pnpm --filter backend start:api
pnpm --filter frontend start
Run pending migrations against the dev database before starting the API for the first time:
export DATABASE_URL=postgresql://travel_planner:travel_planner_dev@localhost:5432/travel_planner
export REDIS_URL=redis://localhost:6379
export OIDC_ISSUER=https://idp.example.invalid/realms/travel-planner
export OIDC_AUDIENCE=travel-planner-api
pnpm --filter backend build:api && node backend/dist/apps/api/src/migration.js
pnpm dev:infra starts local PostgreSQL/Redis (see compose.dev.yml); pnpm dev:infra:down stops them.
Quality gates
pnpm lint
pnpm test
pnpm test:compose
pnpm build
TeamCity deployment scripts
TeamCity invokes repository-owned scripts rather than duplicating deployment logic in step configuration:
scripts/teamcity/validate.sh # install, lint, test, compose-invariant check, build
scripts/teamcity/build-images.sh # build + push immutable IMAGE_TAG images
scripts/teamcity/deploy.sh # pull, migrate, compose up -d, smoke test
scripts/teamcity/smoke.sh # health/root checks against APP_BASE_URL
scripts/teamcity/rollback.sh # redeploy the previous IMAGE_TAG
deploy.sh never runs docker compose down as part of a routine deployment; rollback.sh never attempts an automatic database downgrade.
Production topology
Production Docker Compose (compose.yml) publishes exactly one host port, on the edge (Nginx) service, which serves the built Angular app and reverse-proxies /api/* and /health/* to the internal api service. api, worker, postgres, and redis are reachable only over the internal Docker network. See docs/architecture/deployment.md for the full contract and scripts/teamcity/ for the TeamCity-invoked build/deploy/rollback scripts.
Phase 01 status: foundation complete
GET /health/live— process liveness only, no dependency checks.GET /health/ready— validates PostgreSQL and Redis connectivity.GET /api/v1/version— safe build metadata only (appVersion,teamCityBuildNumber,sourceRevision); never database/Redis URLs.- The compiled no-op migration entry point (
backend/dist/apps/api/src/migration.js) givesdeploy.sha stable container command contract; Phase 02 replaces its body with the real versioned migration runner. - Verified end-to-end:
docker compose -f compose.yml upwith a real TLS certificate serves/health/live,/health/ready,/, and/api/v1/versionthrough the single published edge port, withpostgres/redis/api/workerunreachable from the host.