- 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>
3.6 KiB
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:
lunarfronton localhost:5432 - Test:
lunarfront_teston 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 modebun run test— run all testsbun run lint— lint all packagesbun 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
PaginationSchemafrom@lunarfront/shared/schemasto 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/allsuffix to distinguish from the paginated list endpoint for the same resource.
Frontend Table Conventions
- Every table that displays data must use the shared
DataTablecomponent (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
DataTablewith 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