Repository Structure
SalesArck is implemented as a pnpm/turbo monorepo.
Workspace Layout
salesarck_code/
apps/
api/ # Hono API service (Node.js)
web/ # React web portal (consumer, client, admin, pos_operator)
workers/ # Background worker entrypoint (scaffolded, not yet queue-backed)
packages/
auth/ # Supabase server-side auth helpers + auth error types
db/ # Drizzle schema, migrations, and DB client
observability/ # Pino logger, correlation ID, Sentry bootstrap
rbac/ # Permission matrix and RBAC errors
reward-engine/ # Deterministic reward and redemption calculations
tenant/ # Tenant membership resolution from verified claims
types/ # Shared Zod schemas + TS contracts (foundation package)
docs/
proposal.tex # LaTeX project proposal (v1.0)
phase-0-deploy.md
worklog-square-oauth-plan.md
Tooling and Build Orchestration
Root package.json defines the monorepo task model:
pnpm dev->turbo run devpnpm build->turbo run buildpnpm lint->turbo run lintpnpm typecheck->turbo run typecheckpnpm test->turbo run testpnpm db:generate-> schema diff generation (@salesarc/db)pnpm db:migrate-> apply SQL migrations (@salesarc/db)pnpm db:studio-> Drizzle Studio UI (@salesarc/db)pnpm format-> Prettier formatting across workspacepnpm clean-> remove build artifacts and node_modules
Engine requirements: Node.js >= 20.0.0, pnpm >= 9.0.0.
The workspace package map is declared in pnpm-workspace.yaml:
packages:
- "apps/*"
- "packages/*"
Turbo pipeline (turbo.json):
builddepends on^build(upstream packages first), outputs todist/**typecheckdepends on^buildlintruns without cachetestdepends on^build, outputs tocoverage/**devis persistent and not cacheddb:*tasks are not cached;db:studiois persistent
Runtime Ownership by Directory
| Path | Owns | Notes |
|---|---|---|
apps/api/src/app.ts | API composition and middleware chain | Registers all /api/v1/* route groups |
apps/api/src/routes/* | HTTP contract layer | Auth/rbac/tenant guards + transport validation |
apps/api/src/services/* | Business workflows | Ingestion, polling, wallet credit, POS adapters |
apps/api/src/lib/* | Integration and infrastructure helpers | Env validation, OAuth helpers, encryption, email, workspace provisioning |
apps/web/src/App.tsx | Route graph and role-based shell | Central navigation + guarded route composition |
apps/web/src/pages/* | Product views | Consumer/client/admin workflows |
apps/web/src/lib/* | Frontend utilities | API client, auth profile loading, Supabase client, OAuth URL helpers |
apps/web/src/store/* | Global state | Zustand auth store |
packages/db/src/schema/index.ts | System of record schema | 12 tables, tenant-safe data model + constraints |
packages/reward-engine/src/evaluate.ts | Reward policy execution | Pure deterministic calculation, fully tested |
packages/rbac/src/permissions.ts | Permission model | Server-enforced role matrix |
packages/tenant/src/resolver.ts | Tenant authorization boundary | Membership validation and admin bypass |
Dependency Direction
Implementation follows a layered dependency direction:
packages/types(base contracts — no dependencies)- Domain packages (
rbac,tenant,reward-engine,auth,observability,db) - Apps (
api,web,workers)
Apps consume shared packages; shared packages do not depend on apps.
Package Boundary Rules
@salesarc/typesis the foundation; all other packages and apps depend on it.@salesarc/reward-engineis pure (zero I/O) and depends only on@salesarc/types.@salesarc/rbacdepends only on@salesarc/types.@salesarc/tenantdepends only on@salesarc/types.@salesarc/authdepends on@supabase/supabase-jsand@salesarc/types.@salesarc/dbdepends ondrizzle-orm,pg, and@salesarc/types.@salesarc/observabilitydepends onpinoand@sentry/node.@salesarc/apidepends on all shared packages + Hono + Zod.@salesarc/webdepends on@salesarc/types+ React ecosystem.
Why This Structure Matters
- Shared contracts reduce API/frontend drift.
- Domain logic (reward engine, RBAC, tenant resolution) is testable in isolation.
apps/apistays thin by delegating logic to packages/services.- Deployment targets can evolve independently while preserving type-safe domain behavior.
- Pure packages (
reward-engine,rbac,tenant) have no I/O, making them deterministic and fast to test.
Written byDhruv Doshi