Files
dwellops-platform/docs/architecture.md
2026-03-10 21:30:52 -03:00

4.2 KiB

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.

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. 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.