Architecture
Monorepo Structure
Workspace layout#
The repo uses npm workspaces with Turborepo for task orchestration. Four top-level workspace roots:
text
commodity-management-platform/
├── apps/ ← concrete entrypoints (Next.js, Hono API, Docs)
│ ├── web/ ← Next.js 16 product frontend (port 3000)
│ ├── api/ ← Hono.js on Cloudflare Workers (port 8788)
│ └── docs/ ← This docs site (port 3001)
│
├── be-packages/ ← backend feature modules (8 packages)
│ ├── feature-dashboard/
│ ├── feature-sms-settings/
│ ├── feature-farmer-registry/
│ ├── feature-farm-mapping/
│ ├── feature-deforestation-risk/
│ ├── feature-sustainability-programs/
│ ├── feature-surveys/
│ └── feature-eudr-compliance/
│
├── fe-packages/ ← frontend feature modules (8 packages)
│ ├── feature-auth/
│ ├── feature-sms-settings-web/
│ ├── feature-farmer-registry-web/
│ ├── feature-farm-mapping-web/
│ ├── feature-deforestation-risk-web/
│ ├── feature-sustainability-programs-web/
│ ├── feature-surveys-web/
│ └── feature-eudr-compliance-web/
│
└── shared/ ← cross-cutting packages (9 packages)
├── ui/
├── brand/
├── validation/
├── auth-permissions/
├── dashboard-contracts/
├── eudr-compliance-contracts/
├── swr-config/
├── typescript-config/
└── eslint-config/Boundary rules#
These rules are enforced by TypeScript path aliases and ESLint import rules. Running npm run typecheck from the root will catch any violation.
| Workspace | May import | Must not import |
|---|---|---|
apps/web | fe-packages/*, shared/* | be-packages/* (no server code in the browser bundle) |
apps/api | be-packages/*, shared/* | fe-packages/* (no React in the edge worker) |
fe-packages/* | shared/* only | apps/*, be-packages/*, other fe-packages/* |
be-packages/* | shared/* only | apps/*, fe-packages/*, other be-packages/* |
shared/* | Other shared/* (with care) | apps/*, be-packages/*, fe-packages/* |
The four rules in plain English#
- →Apps orchestrate routing, layouts, and auth boundaries — they do not contain business logic.
- →Backend and frontend feature packages own domain behaviour. Each feature package is independently versioned and tested.
- →Shared packages expose UI primitives, brand tokens, validation schemas, and tooling — no feature logic.
- →API endpoints consume package contracts (schemas, service functions) instead of duplicating them.
Package placement guide#
| If your code… | Place it in |
|---|---|
| Code that accesses the database or calls external APIs | be-packages/feature-<domain> |
| React components or hooks for a feature | fe-packages/feature-<domain>-web |
| Zod schemas or TypeScript types shared between API and web | shared/<domain>-contracts |
| Cross-cutting validation (not domain-specific) | shared/validation |
| Reusable React UI primitives (no feature logic) | shared/ui |
| Design tokens, brand CSS, ThemeProvider | shared/brand |
Naming conventions#
| Package type | Convention | Example |
|---|---|---|
| Backend feature | feature-<domain> | @repo/feature-farmer-registry |
| Frontend feature | feature-<domain>-web | @repo/feature-farmer-registry-web |
| Shared contracts | <domain>-contracts | @repo/eudr-compliance-contracts |
| Shared utility | descriptive noun | @repo/auth-permissions |
Turborepo task graph#
turbo.json defines the pipeline. Key task relationships:
| Task | Depends on | Notes |
|---|---|---|
| build | build (deps) | Each package builds after its dependencies are built. |
| dev | — (parallel) | All dev servers start in parallel. |
| lint | — | Runs ESLint independently per workspace. |
| typecheck | build (deps) | Needs declaration files from upstream packages. |
| test | build (deps) | Vitest runs after the package is built. |
Deep imports are forbidden
Always import from the package barrel:
import { EnrollmentWizard } from '@repo/feature-farmer-registry-web'. Never use deep paths like @repo/feature-farmer-registry-web/src/components/EnrollmentWizard. The barrel is the public API contract.Internal package structure#
Each backend feature package follows the same internal layout:
text
be-packages/feature-<domain>/
└── src/
├── db/ ← Drizzle ORM schema and connection helpers
├── schema/ ← Zod validation schemas and inferred types
├── services/ ← pure business logic (no HTTP, no framework)
├── routes/ ← Hono route handlers (thin: validate → call service)
└── index.ts ← barrel exportEach frontend feature package:
text
fe-packages/feature-<domain>-web/
└── src/
├── components/ ← React components
├── hooks/ ← SWR-based data fetching hooks
├── services/ ← API client helpers (fetch wrappers)
├── types.ts ← TypeScript types specific to this package
└── index.ts ← barrel export