Initial commit
This commit is contained in:
103
docs/architecture.md
Normal file
103
docs/architecture.md
Normal file
@@ -0,0 +1,103 @@
|
||||
# Architecture
|
||||
|
||||
## Overview
|
||||
|
||||
dwellops-platform is a TypeScript-first monorepo for a modern HOA management platform. It is designed for:
|
||||
|
||||
- **Self-hosted single-tenant** deployments (one HOA per server).
|
||||
- **Future SaaS multi-tenant** evolution without major structural changes.
|
||||
|
||||
## Workspace layout
|
||||
|
||||
```
|
||||
apps/
|
||||
api/ — Fastify REST API
|
||||
web/ — Next.js 16 frontend (App Router)
|
||||
packages/
|
||||
config/ — shared config (ESLint, Prettier, Stylelint, tsconfig, Vitest)
|
||||
types/ — TypeScript-only domain types
|
||||
schemas/ — Zod schemas (reusable across frontend/backend)
|
||||
db/ — Prisma client + data access boundary
|
||||
i18n/ — locale helpers
|
||||
ui/ — shared React UI primitives (CSS Modules + design tokens)
|
||||
test-utils/ — test factories, render helpers
|
||||
```
|
||||
|
||||
## Dependency rules
|
||||
|
||||
- `apps/api` → `@dwellops/db`, `@dwellops/types`, `@dwellops/schemas`
|
||||
- `apps/web` → `@dwellops/ui`, `@dwellops/types`, `@dwellops/schemas`, `@dwellops/i18n`
|
||||
- **Prisma is only ever imported from `@dwellops/db`** — never directly in apps.
|
||||
- `packages/types` has zero runtime dependencies.
|
||||
- `packages/schemas` depends only on Zod.
|
||||
|
||||
## Frontend structure (`apps/web/src`)
|
||||
|
||||
| Layer | Description | Rules |
|
||||
| ------------- | ------------------------------------- | ------------------------------- |
|
||||
| `components/` | Pure presentational building blocks | No API calls, no business logic |
|
||||
| `widgets/` | Composed UI units with local behavior | May hold local state |
|
||||
| `views/` | Page-level server compositions | Orchestrates data + layout |
|
||||
|
||||
All styling uses **CSS Modules + PostCSS**. Tailwind is explicitly forbidden.
|
||||
Design tokens live in `packages/ui/src/tokens/tokens.css` as CSS custom properties.
|
||||
|
||||
## Backend structure (`apps/api/src`)
|
||||
|
||||
| Directory | Description |
|
||||
| ----------- | --------------------------------------------------------------- |
|
||||
| `plugins/` | Fastify plugins (cors, swagger, auth, etc.) |
|
||||
| `modules/` | Feature modules (health, auth, hoa, …) each with routes + tests |
|
||||
| `services/` | Business logic services |
|
||||
| `lib/` | Utilities: env validation, error types, logger, auth instance |
|
||||
|
||||
**Route handlers are thin**: validate → check auth/permissions → call service → shape response.
|
||||
|
||||
## Authentication
|
||||
|
||||
Powered by [Better Auth](https://better-auth.com).
|
||||
|
||||
| Method | Status |
|
||||
| -------------- | ------------------------------------- |
|
||||
| Magic link | ✅ Enabled by default |
|
||||
| Passkeys | ✅ Enabled by default |
|
||||
| OIDC | ⚙️ Optional (set `OIDC_ENABLED=true`) |
|
||||
| Email/password | ❌ Disabled |
|
||||
|
||||
Auth state is resolved in a Fastify plugin (`plugins/auth.ts`) on every request
|
||||
and attached as `request.session`. Route-level enforcement uses the `requireAuth`
|
||||
preHandler helper.
|
||||
|
||||
## Authorization
|
||||
|
||||
Roles: `ADMIN`, `BOARD_MEMBER`, `TREASURER`, `OWNER`, `TENANT`, `VIEWER`.
|
||||
|
||||
A `Membership` record connects a `User` to an `Hoa` with a `Role`, optionally
|
||||
scoped to a `Unit`. This enables future multi-tenant expansion: a user can hold
|
||||
different roles in different HOAs.
|
||||
|
||||
## Database
|
||||
|
||||
PostgreSQL + Prisma. All access goes through `@dwellops/db`.
|
||||
|
||||
Core models:
|
||||
|
||||
- `User`, `Session`, `Account`, `Verification` — Better Auth required
|
||||
- `Hoa` — homeowners association
|
||||
- `Unit` — dwelling unit within an HOA
|
||||
- `Membership` — user ↔ HOA ↔ role ↔ optional unit
|
||||
- `AuditLog` — immutable record of sensitive actions
|
||||
|
||||
## Internationalization
|
||||
|
||||
All user-facing strings use [next-intl](https://next-intl.dev). Translation files:
|
||||
|
||||
- `apps/web/messages/<locale>.json` — aggregated messages (do not edit directly)
|
||||
- `src/.../translations.json` — component-local translation fragments
|
||||
- `scripts/aggregate-translations.ts` — merges component files into the messages file
|
||||
|
||||
## Audit logging
|
||||
|
||||
`AuditService` (`apps/api/src/services/audit.service.ts`) records sensitive
|
||||
actions to the `AuditLog` table. It never throws — audit failures are logged
|
||||
but do not block primary operations.
|
||||
135
docs/development.md
Normal file
135
docs/development.md
Normal file
@@ -0,0 +1,135 @@
|
||||
# Development guide
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- **Node.js** ≥ 24
|
||||
- **pnpm** ≥ 10 (`npm install -g pnpm@10`)
|
||||
- **Docker** (for local infrastructure)
|
||||
|
||||
## Local setup
|
||||
|
||||
```bash
|
||||
# 1. Clone the repository
|
||||
git clone git@git.mifi.dev:mifi-ventures/dwellops-platform.git
|
||||
cd dwellops-platform
|
||||
|
||||
# 2. Copy environment files
|
||||
cp .env.example .env
|
||||
cp apps/api/.env.example apps/api/.env
|
||||
cp apps/web/.env.example apps/web/.env
|
||||
|
||||
# 3. Start local services (Postgres + Mailpit)
|
||||
docker compose up -d
|
||||
|
||||
# 4. Install all workspace dependencies
|
||||
pnpm install
|
||||
|
||||
# 5. Generate Prisma client
|
||||
pnpm db:generate
|
||||
|
||||
# 6. Run initial migration
|
||||
pnpm db:migrate:dev
|
||||
|
||||
# 7. (Optional) Seed with dev data
|
||||
pnpm db:seed
|
||||
|
||||
# 8. Start dev servers
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
## Dev Container (VS Code / GitHub Codespaces)
|
||||
|
||||
Open the repository in VS Code and click **Reopen in Container** when prompted,
|
||||
or run the command palette → `Dev Containers: Reopen in Container`.
|
||||
|
||||
The container starts Postgres and Mailpit via Docker Compose.
|
||||
On first create, `pnpm install` and `pnpm db:generate` run automatically.
|
||||
|
||||
All ports are forwarded: see `.devcontainer/devcontainer.json` for the full list.
|
||||
|
||||
## Running tests
|
||||
|
||||
```bash
|
||||
# Unit + integration tests (all workspaces)
|
||||
pnpm test
|
||||
|
||||
# Watch mode
|
||||
pnpm --filter @dwellops/api test:watch
|
||||
pnpm --filter @dwellops/web test:watch
|
||||
|
||||
# End-to-end tests (requires the web app to be running)
|
||||
pnpm test:e2e
|
||||
|
||||
# Coverage report
|
||||
pnpm --filter @dwellops/api test -- --coverage
|
||||
```
|
||||
|
||||
## Storybook
|
||||
|
||||
```bash
|
||||
# Run Storybook for the web app (includes packages/ui stories)
|
||||
pnpm --filter @dwellops/web storybook
|
||||
|
||||
# Run Storybook for the UI package standalone
|
||||
pnpm --filter @dwellops/ui storybook
|
||||
```
|
||||
|
||||
## Database operations
|
||||
|
||||
```bash
|
||||
pnpm db:generate # Re-generate Prisma client after schema changes
|
||||
pnpm db:migrate:dev # Create and apply a migration (dev only)
|
||||
pnpm db:migrate # Deploy pending migrations (CI/production)
|
||||
pnpm db:push # Push schema changes without a migration (prototype only)
|
||||
pnpm db:studio # Open Prisma Studio in the browser
|
||||
pnpm db:seed # Seed the database with dev data
|
||||
```
|
||||
|
||||
## i18n
|
||||
|
||||
```bash
|
||||
# Aggregate component translations.json files into messages/<locale>.json
|
||||
pnpm i18n:aggregate
|
||||
```
|
||||
|
||||
Add new strings by editing `translations.json` files alongside components,
|
||||
then running `pnpm i18n:aggregate`. Never hand-edit `messages/en.json`
|
||||
for component-specific strings.
|
||||
|
||||
## Code quality
|
||||
|
||||
```bash
|
||||
pnpm lint # ESLint + Stylelint
|
||||
pnpm lint:fix # Auto-fix lint issues
|
||||
pnpm typecheck # TypeScript across all workspaces
|
||||
pnpm format # Prettier
|
||||
pnpm format:check # Check formatting without writing
|
||||
```
|
||||
|
||||
Pre-commit hooks run lint-staged automatically.
|
||||
|
||||
## Adding a new package
|
||||
|
||||
1. Create `packages/<name>/` with `package.json`, `tsconfig.json`, and `src/index.ts`.
|
||||
2. Name the package `@dwellops/<name>`.
|
||||
3. Extend `@dwellops/config/tsconfig/base.json` (or `node.json` / `react-library.json`).
|
||||
4. Add a `workspace:*` reference in any consumer's `package.json`.
|
||||
5. Add to root `tsconfig.json` references.
|
||||
6. Run `pnpm install`.
|
||||
|
||||
## Adding a new route in apps/api
|
||||
|
||||
1. Create `src/modules/<feature>/<feature>.routes.ts`.
|
||||
2. Implement thin route handlers — call services for business logic.
|
||||
3. Register the routes in `src/app.ts`.
|
||||
4. Write `<feature>.test.ts` alongside the routes.
|
||||
5. Update Swagger schemas as part of the change.
|
||||
|
||||
## Adding a new page in apps/web
|
||||
|
||||
1. Create `src/app/[locale]/<path>/page.tsx` — thin page that delegates to a view.
|
||||
2. Create `src/views/<FeatureName>View/` with the view component.
|
||||
3. Create any new components in `src/components/` or `src/widgets/`.
|
||||
4. Add translations to `translations.json` alongside each component.
|
||||
5. Run `pnpm i18n:aggregate`.
|
||||
6. Add Storybook stories for any new components/widgets.
|
||||
Reference in New Issue
Block a user