High Level Architecture
Last updated: February 2026
Technical Summary​
The EMTB Tax Claim Management System follows a secure multi-tenant monorepo architecture with independent service deployment. The backend leverages NestJS 11 with TypeORM for entity-based database operations and comprehensive role-based authorization via CASL, while the frontend uses React 19 with Vite for a fast single-page application. Key integration points include custom JWT authentication for stateless user context, shared TypeScript interfaces between services (@emtb/shared-types), and API-level tenant isolation through NestJS guards and TypeORM query scoping. The architecture deploys on Dokploy (self-hosted VPS) with Traefik as the reverse proxy, PostgreSQL 16 as the primary database, and Redis for caching. This design achieves the PRD goals by implementing zero-trust security principles where every API endpoint validates both user roles and tenant ownership, ensuring complete data isolation between clients while enabling EMTB staff to access assigned client data based on their permission levels.
Platform and Infrastructure​
Platform: Dokploy (self-hosted VPS)
Reverse Proxy: Traefik (SSL termination, Let's Encrypt)
Key Services: PostgreSQL 16, Redis 7, S3/R2 Object Storage
Deployment: Docker multi-stage builds, auto-deploy on push to main
Repository Structure​
Structure: Monorepo
Package Manager: Yarn 4.12.0 (Corepack)
Build Orchestration: Turborepo 2.8.9
Package Organization: App-based separation (apps/api, apps/frontend, apps/e2e) with shared packages (shared/types) and documentation (docs-site)
High Level Architecture Diagram​
Architectural Patterns​
-
Multi-Tenant SaaS Architecture: API-level tenant isolation through NestJS guards and TypeORM query scoping — every query is filtered by the authenticated user's tenant context, ensuring complete data separation between clients.
-
Role-Based Access Control (RBAC) with CASL: Attribute-based permission system using CASL abilities. Permissions are defined declaratively in
CaslAbilityFactoryand enforced via@CheckPolicies()decorators on controllers and defensive checks in services. -
Guard Pipeline (NestJS): Three-layer guard chain —
JwtAuthGuard(authentication) →PoliciesGuard(CASL authorization) →TenantAccessGuard(tenant isolation). This ensures defense-in-depth where each layer validates independently. -
Repository Pattern with TypeORM: Entity-based data access using TypeORM decorators and repository pattern. Tenant filtering is applied at the service layer through query builders and where clauses scoped to the user's tenant.
-
Custom JWT Authentication: Stateless authentication using Passport local strategy for login and @nestjs/jwt for token issuance. No third-party auth provider — user credentials and roles are stored in the PostgreSQL database.
-
Server-Centric Security: All authorization decisions are made server-side. The frontend uses
PermissionGatecomponents to conditionally render UI based on roles, but the API enforces all access rules independently.