Files
lunarfront-app/docs/architecture.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

4.9 KiB

Architecture

Monorepo Structure

lunarfront/
  packages/
    shared/       @lunarfront/shared — Zod schemas, types, business logic, utils
    backend/      @lunarfront/backend — Fastify API server
    admin/        @lunarfront/admin — Admin UI (React + Vite)
  planning/       Domain planning docs (01-26)
  docs/           Technical documentation

Managed with Turborepo and Bun workspaces. @lunarfront/shared is a dependency of both backend and admin.

Backend

Fastify API server with a plugin-based architecture.

src/
  main.ts                 App entry, plugin registration, server start
  plugins/
    database.ts           Drizzle ORM + PostgreSQL connection
    auth.ts               JWT auth, permission checking, inheritance
    redis.ts              Valkey/Redis (ioredis)
    cors.ts               CORS configuration
    storage.ts            File storage provider registration
    error-handler.ts      Centralized error → HTTP response mapping
    dev-auth.ts           Dev-only auth bypass
  routes/v1/
    auth.ts               Register, login, password change, reset, profile
    accounts.ts           Accounts, members, identifiers, payment methods, etc.
    rbac.ts               Users list, roles CRUD, role assignments, permissions
    files.ts              File upload/download/delete
  services/
    account.service.ts    Account + member business logic
    rbac.service.ts       Roles, permissions, user role management
    file.service.ts       File validation, storage, metadata
    product.service.ts    Products + inventory
    lookup.service.ts     Lookup table management
    inventory.service.ts  Stock receipts, unit tracking
  db/
    schema/               Drizzle table definitions
    migrations/           SQL migrations (drizzle-kit)
    seeds/                System permission + role definitions
  storage/
    provider.ts           StorageProvider interface
    local.ts              Local filesystem provider
    s3.ts                 S3 provider (placeholder)
  utils/
    pagination.ts         withPagination, withSort, buildSearchCondition, paginatedResponse

Request Flow

  1. Fastify receives request
  2. authenticate preHandler verifies JWT, loads permissions, checks is_active
  3. requirePermission preHandler checks user has required permission slug
  4. Route handler validates input with Zod, calls service, returns response
  5. Error handler catches typed errors and maps to HTTP status codes

Permission Inheritance

Permissions follow a hierarchy: admin implies edit, which implies view for the same domain. Having accounts.admin automatically grants accounts.edit and accounts.view. Non-hierarchical actions (upload, delete, send, export) don't cascade.

Frontend (Admin UI)

React SPA with TanStack Router (file-based routing) and TanStack Query (data fetching).

src/
  routes/
    _authenticated.tsx       Layout with sidebar, permission-gated nav
    _authenticated/
      accounts/              Account list + detail pages
      members/               Member list + detail pages
      users.tsx              Users admin page
      roles/                 Roles list + create/edit pages
      profile.tsx            User profile + settings
      help.tsx               In-app wiki
    login.tsx                Login page
  api/                       React Query options + mutations per domain
  components/
    ui/                      shadcn/ui primitives
    shared/                  DataTable, AvatarUpload
    accounts/                Domain-specific forms
  stores/
    auth.store.ts            Zustand — token, user, permissions
    theme.store.ts           Zustand — color theme + light/dark mode
  hooks/
    use-pagination.ts        URL-based pagination state
  lib/
    api-client.ts            Fetch wrapper with JWT + error handling
    themes.ts                Color theme definitions
  wiki/
    index.ts                 In-app help content

State Management

Concern Solution
Auth + permissions Zustand store, persisted to sessionStorage
Server data TanStack Query (cache, refetch, invalidation)
URL state (pagination) TanStack Router search params
Theme Zustand store, persisted to localStorage
Component state React useState

Deployment Model

Each customer runs as a fully isolated deployment — their own Kubernetes namespace on DOKS, their own database on the shared managed Postgres instance. There is no multi-tenancy in the application layer. No company_id, no row-level isolation. One instance = one customer.

Database

PostgreSQL 16 with Drizzle ORM. Migrations are generated with bunx drizzle-kit generate and applied with bunx drizzle-kit migrate. Schema files live in packages/backend/src/db/schema/.

Key tables: company, location, user, account, member, member_identifier, product, inventory_unit, role, permission, user_role_assignment, role_permission, file.