Files
lunarfront-app/CLAUDE.md
Ryan Moon c2b1073fef feat: add CI/CD pipeline, production Dockerfile, and deployment architecture
- Add production Dockerfile with bun build --compile, multi-stage Alpine build
- Add .dockerignore
- Swap bcrypt -> bcryptjs (pure JS, no native addons)
- Add programmatic migrations on startup via drizzle migrator
- Add /v1/version endpoint with APP_VERSION baked in at build time
- Add .gitea/workflows/ci.yml (lint + test with postgres/valkey services)
- Add .gitea/workflows/build.yml (version bump, build, push to registry)
- Update CLAUDE.md and docs/architecture.md to remove multi-tenancy
- Add docs/deployment.md covering DOKS + ArgoCD architecture

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 19:50:37 -05:00

3.6 KiB

LunarFront — Project Conventions

App

  • Name: LunarFront
  • Purpose: Small business management platform (POS, inventory, rentals, scheduling, repairs, accounting)
  • Company: Lunarfront Tech LLC

Tech Stack

  • Runtime: Bun
  • Language: TypeScript (strict mode, end-to-end)
  • API: Fastify with Pino JSON logging
  • ORM: Drizzle ORM (PostgreSQL 16)
  • Validation: Zod (shared schemas between frontend and backend)
  • Queue: BullMQ (Valkey-backed)
  • Cache: Valkey 8 (Redis-compatible fork)
  • Monorepo: Turborepo with Bun workspaces
  • Testing: bun test (built-in, uses bun:test imports)
  • Linting: ESLint 9 flat config + Prettier

Package Namespace

  • @lunarfront/shared — types, Zod schemas, business logic, utils
  • @lunarfront/backend — Fastify API server

Database

  • Dev: lunarfront on localhost:5432
  • Test: lunarfront_test on localhost:5432
  • Each deployed instance has its own isolated database — no multi-tenancy, no company_id
  • Migrations via Drizzle Kit (bunx drizzle-kit generate, bunx drizzle-kit migrate)

Key Entity Names

  • account — billing entity (family, individual, or business)
  • member — individual person on an account (NOT "student" — renamed to support multiple adults)
  • member.is_minor — derived from date_of_birth, controls consent/portal rules

Commands

  • bun run dev — start all packages in dev mode
  • bun run test — run all tests
  • bun run lint — lint all packages
  • bun run format — format all files with Prettier

API Conventions

  • Every endpoint that returns a list must support pagination, search, and sorting — no exceptions unless the endpoint is explicitly a lightweight lookup (see below)
    • ?page=1&limit=25 — pagination (default: page 1, 25 per page, max 100)
    • ?q=search+term — full-text search across relevant columns
    • ?sort=name&order=asc — sorting by field name, asc or desc
  • List responses always return { data: [...], pagination: { page, limit, total, totalPages } }
  • Search and filtering is ALWAYS server-side, never client-side
  • Use PaginationSchema from @lunarfront/shared/schemas to parse query params
  • Use pagination helpers from packages/backend/src/utils/pagination.ts
  • Lookup endpoints (e.g., /roles/all, /statuses/all) are the exception — these return a flat unpaginated list for populating dropdowns/selects. Use a /all suffix to distinguish from the paginated list endpoint for the same resource.

Frontend Table Conventions

  • Every table that displays data must use the shared DataTable component (components/shared/data-table.tsx)
  • All tables must support: search (via ?q=), sortable columns, and server-side pagination
  • Use the usePagination() hook (hooks/use-pagination.ts) — it manages page, search, and sort state via URL params
  • All data columns that make sense to sort by should be sortable (e.g., name, email, date, status) — don't limit to just 1-2 columns
  • Sub-resource tables (e.g., members within an account, payment methods) follow the same rules — use DataTable with pagination, not raw <Table> with unbounded queries
  • Loading states should use skeleton loading (built into DataTable), not plain "Loading..." text

Conventions

  • Shared Zod schemas are the single source of truth for validation (used on both frontend and backend)
  • Business logic lives in @lunarfront/shared, not in individual app packages
  • API routes are thin — validate with Zod, call a service, return result
  • All financial events must be auditable (append-only audit records)
  • JSON structured logging with request IDs on every log line