Skip to main content

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 dev
  • pnpm build -> turbo run build
  • pnpm lint -> turbo run lint
  • pnpm typecheck -> turbo run typecheck
  • pnpm test -> turbo run test
  • pnpm 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 workspace
  • pnpm 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):

  • build depends on ^build (upstream packages first), outputs to dist/**
  • typecheck depends on ^build
  • lint runs without cache
  • test depends on ^build, outputs to coverage/**
  • dev is persistent and not cached
  • db:* tasks are not cached; db:studio is persistent

Runtime Ownership by Directory

PathOwnsNotes
apps/api/src/app.tsAPI composition and middleware chainRegisters all /api/v1/* route groups
apps/api/src/routes/*HTTP contract layerAuth/rbac/tenant guards + transport validation
apps/api/src/services/*Business workflowsIngestion, polling, wallet credit, POS adapters
apps/api/src/lib/*Integration and infrastructure helpersEnv validation, OAuth helpers, encryption, email, workspace provisioning
apps/web/src/App.tsxRoute graph and role-based shellCentral navigation + guarded route composition
apps/web/src/pages/*Product viewsConsumer/client/admin workflows
apps/web/src/lib/*Frontend utilitiesAPI client, auth profile loading, Supabase client, OAuth URL helpers
apps/web/src/store/*Global stateZustand auth store
packages/db/src/schema/index.tsSystem of record schema12 tables, tenant-safe data model + constraints
packages/reward-engine/src/evaluate.tsReward policy executionPure deterministic calculation, fully tested
packages/rbac/src/permissions.tsPermission modelServer-enforced role matrix
packages/tenant/src/resolver.tsTenant authorization boundaryMembership validation and admin bypass

Dependency Direction

Implementation follows a layered dependency direction:

  1. packages/types (base contracts — no dependencies)
  2. Domain packages (rbac, tenant, reward-engine, auth, observability, db)
  3. Apps (api, web, workers)

Apps consume shared packages; shared packages do not depend on apps.

Package Boundary Rules

  • @salesarc/types is the foundation; all other packages and apps depend on it.
  • @salesarc/reward-engine is pure (zero I/O) and depends only on @salesarc/types.
  • @salesarc/rbac depends only on @salesarc/types.
  • @salesarc/tenant depends only on @salesarc/types.
  • @salesarc/auth depends on @supabase/supabase-js and @salesarc/types.
  • @salesarc/db depends on drizzle-orm, pg, and @salesarc/types.
  • @salesarc/observability depends on pino and @sentry/node.
  • @salesarc/api depends on all shared packages + Hono + Zod.
  • @salesarc/web depends 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/api stays 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