Skip to content

Repository files navigation

CarCare — Core Domain MVP

A platform for vehicle owners in the Sri Lankan market to manage their vehicles and see the complete, verified service history in one place — garages and service centers log service records against a vehicle, and owners can share that history with dealers so used and refurbished vehicles can be sold without the usual paperwork hassle. Architected as a multi-tenant SaaS. This is Milestone 1: Core Domain MVP — tenancy, auth, Postgres Row-Level Security, vehicles, service records, inventory, cross-tenant consent, quotes/invoices/payments, a type/condition-aware vehicle taxonomy console, and an internal ops (/platform) section. See Roadmap below for what's intentionally out of scope for this milestone.

Further reading: docs/ARCHITECTURE.md (system overview & module map), docs/ER_DIAGRAM.md (full data model), docs/GAP_ANALYSIS.md (verified gaps for future development), docs/adr/ (architectural decision records), NEXT.md (product roadmap toward a vehicle passport).

Stack

  • apps/api — NestJS (TypeScript), Prisma 7 (driver adapters, @prisma/adapter-pg), PostgreSQL 15 with Row-Level Security, JWT auth (Argon2id), XState v5 statecharts for every lifecycle entity.
  • apps/web — Next.js 14 (App Router), TanStack Query, react-hook-form + zod, Tailwind. Includes the internal ops console at /platform (tenant search/management, vehicle-taxonomy console), gated by a RoleScope.PLATFORM role rather than a separate app — see ADR 0006.
  • packages/shared — zod DTOs, permission catalog, XState machines, country pack — imported by both the API (enforcement) and the web app (UI can(state, event) checks), so they can never disagree.

Prerequisites

  • Node.js 20+, npm 10+
  • Docker (Postgres 15 + Redis via docker-compose.yml; the full stack can also run entirely in Docker — see Running fully in Docker below)

Getting started

# 1. Install dependencies (workspace root)
npm install

# 2. Start Postgres + Redis
docker compose up -d

# 3. Copy env files
cp apps/api/.env.example apps/api/.env         # already has working local-dev defaults

# 4. Build packages/shared (apps/api and apps/web import its compiled output, not raw source)
npm run build --workspace packages/shared

# 5. Apply migrations (creates the carcare_app RLS role, RLS policies, partitions, etc.)
cd apps/api
npx prisma migrate deploy

# 6. Seed demo data (run ONCE against a freshly migrated, empty database — see the doc-comment
#    at the top of apps/api/prisma/seed.ts; it is not safe to re-run against a populated DB)
npm run db:seed

# 7. Back at the repo root, start everything
cd ../..
npm run dev
  • API: http://localhost:3000 (/healthz, Swagger at /docs)
  • Web: http://localhost:8080 — internal ops lives at /platform within this same app, visible in the sidebar for any account that's been granted a RoleScope.PLATFORM role (see ADR 0005 for the auth model and ADR 0006 for why it's part of apps/web, not a separate app):
    cd apps/api
    npm run db:sync-permissions   # creates the platform_admin/platform_support built-in roles
    npm run db:grant-platform-role -- <email> platform_admin
    The dev seed already grants platform_admin to admin@autocare.lk (below) after running the two commands above.

Seeded accounts (password Password123! for all)

Email Role Workspace
admin@autocare.lk station_admin (+ platform_admin — see above) AutoCare Group — Colombo 05
advisor@autocare.lk service_advisor AutoCare Group — Colombo 05
tech@autocare.lk technician AutoCare Group — Colombo 05
admin@primeauto.lk dealer_admin Prime Auto Traders
owner1@example.com owner_admin My Vehicles (Corolla, Alto)
owner2@example.com owner_admin My Vehicles (Bajaj Pulsar)

Running fully in Docker

For a quick end-to-end run without installing Node locally, docker-compose.yml also builds and runs api and web (in addition to db/redis):

docker compose up -d --build

The api container's entrypoint runs prisma migrate deploy on every start (idempotent — safe to re-run), then starts the server. Migrations, RLS policies, and partitions are applied automatically; seeding is not run automatically (seed.ts is not idempotent — see its doc-comment), so seed once explicitly:

docker compose run --rm api npm run db:seed

Notes:

  • web is built with NEXT_PUBLIC_API_URL=http://localhost:3000 baked in at image build time (Next.js inlines NEXT_PUBLIC_* vars during next build), since that variable is read by the browser, not by the container — it must be a host-reachable URL, not the Docker-internal http://api:3000. Server-to-server config (DATABASE_URL, APP_DATABASE_URL, REDIS_URL) uses the Docker-internal service names (db, redis) instead.
  • This is a from-source build (multi-stage Dockerfile per app, full node_modules copied into the runtime image — not a pruned/standalone Next.js output), intended for local end-to-end testing and demos, not hardened for production deployment.
  • The local npm run dev workflow above is still the faster loop for active development (hot reload); use whichever fits — both point at the same db/redis containers, so don't run both against the same Postgres volume with the app-level (non-Docker) api/web at the same time as their Docker equivalents (port collisions on 3000/8080).

Testing

cd apps/api
npm test            # unit tests — includes tests that hit the real Postgres instance

Docker must be up and migrated (steps 2 + 5 above) before running tests that exercise RLS, document numbering concurrency, or the stock ledger against a real database.

Repository layout

apps/
  api/              NestJS backend
    prisma/
      schema.prisma       Prisma-managed models (normalized, no JSON columns)
      migrations/          baseline + hand-written SQL layered on top (RLS, partitioning,
                            generated columns, materialized view — see docs/adr/0002)
      seed.ts               demo data (run once, see doc-comment)
    src/
      core/                cross-cutting: prisma, tenant context, auth, rbac, state-machine,
                            audit, documents (numbering/tax)
      modules/             one directory per bounded context (see docs/adr/0003)
  web/               Next.js customer-facing app — also hosts /platform, the internal ops
                     section (see docs/adr/0006), gated by a RoleScope.PLATFORM role, not a
                     separate app
packages/
  shared/            zod DTOs, XState machines, permission catalog, country pack
  ui/                design-system package (not yet populated this milestone)
  infrastructure/    reserved for future Terraform/Helm — not used yet, see its README
docs/
  ARCHITECTURE.md    system overview, module map, request lifecycle
  ER_DIAGRAM.md      full data model (all 43 Prisma models, grouped by bounded context)
  GAP_ANALYSIS.md    verified gaps for future development
  adr/               architecture decision records

Roadmap / what's deferred

This milestone intentionally does not include (see docs/adr/* "Consequences" sections for the reasoning behind several of these):

  • SSO (OIDC/SAML), SCIM, MFA/TOTP, device/session management UI
  • Terraform/Helm/Kubernetes manifests; CI beyond basic lint/test/migrate-check
  • Stripe billing/plan enforcement; the feature-flag management subsystem (no feature_flags table yet — it'll be added when the feature is actually built, not stubbed ahead of time)
  • Webhook delivery infrastructure (HMAC signing/retry) and API key management (same reasoning — no webhooks/api_keys tables yet)
  • Branded PDF rendering (S3 + headless Chromium/react-pdf) for quotes/invoices/credit notes/receipts — they have a nullable pdf_url column ready for it
  • Broader job-queue coverage — @nestjs/bullmq (against the same Redis docker-compose.yml provisions) is already wired for outbound mail (core/mail/) and the debounced workspace_revenue_summary refresh (core/revenue-summary/; see docs/PERFORMANCE.md §1.1), but most other side effects (notifications, audit) still happen synchronously in the same DB transaction as the triggering mutation. Partition maintenance (npm run db:ensure-partitions --workspace apps/api) is a script meant for a cron, not a live in-process scheduler.
  • ClickHouse/DuckDB analytics sink, report builder, scheduled report emails, CSV/XLSX export
  • PgBouncer, read replicas; partitioning is limited to service_records and audit_events (state_transitions stays a normal BRIN-indexed table)
  • next-intl i18n wiring (folder structure left ready; only the LK country pack / English copy exists)
  • The exhaustive worldwide vehicle catalog from the original spec — the seed loads a representative ~12-make subset spanning the type-branches (car/motorcycle/three-wheeler/van/EV)
  • A real internal-ops identity system beyond individual RoleScope.PLATFORM accounts (SSO, audited impersonation, an audit trail for admin actions) — see docs/adr/0005-platform-role-scope.md
  • Tenant-level (cross-workspace) admin roles are modeled in the permission catalog but not yet independently assignable — see docs/adr/0001-tenancy-model.md

This list is the maintainers' own curated "intentionally out of scope" set. For a fuller, codebase-verified inventory (including things not intentionally deferred — e.g. wide-open CORS, missing security headers, zero frontend test coverage, unaudited admin actions — that should be closed rather than tracked as roadmap), see docs/GAP_ANALYSIS.md.

About

Multi-tenant SaaS for vehicle service history, ownership records, and dealer-ready vehicle sharing.

Topics

Resources

Contributing

Security policy

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages