Rebrand from Forte (music-store-specific) to LunarFront (any small business): - Package namespace @forte/* → @lunarfront/* - Database forte/forte_test → lunarfront/lunarfront_test - Docker containers, volumes, connection strings - UI branding, localStorage keys, test emails - All documentation and planning docs Generalize music-specific terminology: - instrumentDescription → itemDescription - instrumentCount → itemCount - instrumentType → itemCategory (on service templates) - New migration 0027_generalize_terminology for column renames - Seed data updated with generic examples - RBAC descriptions updated
121 lines
4.9 KiB
Markdown
121 lines
4.9 KiB
Markdown
# 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. `onRequest` hook sets `companyId` from header
|
|
3. `authenticate` preHandler verifies JWT, loads permissions, checks `is_active`
|
|
4. `requirePermission` preHandler checks user has required permission slug
|
|
5. Route handler validates input with Zod, calls service, returns response
|
|
6. 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` |
|
|
|
|
## Multi-Tenancy
|
|
|
|
Every domain table has a `company_id` column. All queries filter by the authenticated user's company. Location-scoped tables (inventory, transactions) additionally filter by `location_id`.
|
|
|
|
## 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`.
|