EMTB Fullstack Architecture Document
Introductionβ
This document outlines the complete fullstack architecture for EMTB Tax Claim Management System, including backend systems, frontend implementation, and their integration. It serves as the single source of truth for AI-driven development, ensuring consistency across the entire technology stack.
This unified approach combines what would traditionally be separate backend and frontend architecture documents, streamlining the development process for modern fullstack applications where these concerns are increasingly intertwined.
Starter Template or Existing Projectβ
Based on the PRD analysis, this is a brownfield enhancement project built on:
Current Architecture Foundation:
- Backend: Existing NestJS API with TypeScript, TypeORM, PostgreSQL database, Swagger documentation
- Frontend: Next.js 14 with App Router, React 18, Material-UI (MUI), JWT-based authentication
- Infrastructure: Cloud deployment with independent API and frontend services
- Repository: Monorepo structure with apps/api and apps/frontend
Pre-configured Constraints:
- Must maintain existing JWT authentication integration
- Database schema enhancement required (adding minimal RBAC tables)
- Current PostgreSQL + TypeORM setup must be preserved
- Material-UI components and existing user experience patterns must be maintained
- Zero-downtime deployment requirements
Architectural Decisions Already Made:
- TypeScript across both frontend and backend
- TypeORM for type-safe database operations
- Independent service deployment model
- JWT-based authentication (extending to authorization)
Change Logβ
| Date | Version | Description | Author |
|---|---|---|---|
| 2025-09-09 | v1.0 | Initial fullstack architecture for RBAC implementation | Winston (Architect) |
High Level Architectureβ
Technical Summaryβ
The EMTB Tax Claim Management System follows a secure multi-tenant monorepo architecture with independent service deployment. The backend leverages NestJS with TypeORM for type-safe database operations and comprehensive role-based authorization middleware, while the frontend uses Next.js 14 with App Router for modern React development patterns. Key integration points include JWT token validation for user context, shared TypeScript interfaces between services, and database-level tenant isolation through TypeORM interceptors. The architecture deploys on cloud infrastructure with PostgreSQL database and independent scaling capabilities. 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 Choiceβ
Platform: Cloud Infrastructure Key Services: PostgreSQL Database, Web Services (API + Frontend), Environment Management, SSL/TLS Deployment Host and Regions: Cloud hosting with EU compliance considerations for French data protection
Repository Structureβ
Structure: Monorepo (existing structure maintained)
Monorepo Tool: npm workspaces (current implementation)
Package Organization: App-based separation (apps/api, apps/frontend) with shared packages for types and utilities
High Level Architecture Diagramβ
Architectural Patternsβ
-
Multi-Tenant SaaS Architecture: Database-level tenant isolation through existing client relationships - Rationale: Ensures complete data separation between clients while maintaining performance through existing foreign keys
-
Role-Based Access Control (RBAC) Pattern: Hierarchical permission system with role inheritance and tenant-aware authorization - Rationale: Provides granular security control matching EMTB's complex permission requirements (Admin, Account Manager, Tax Specialist, Client roles)
-
Guard Pattern (NestJS): Declarative authorization using custom guards and decorators on API endpoints - Rationale: Integrates seamlessly with existing NestJS architecture while providing centralized security enforcement
-
Repository Pattern with Prisma: Abstract data access with automatic tenant context injection through middleware - Rationale: Maintains existing Prisma patterns while adding transparent tenant filtering without code changes
-
JWT Claims-Based Authorization: Extract role and tenant information from JWT tokens for stateless authorization - Rationale: Leverages JWT standard without requiring session management or additional auth infrastructure
-
Server-Centric Security: All authorization decisions made server-side with frontend displaying filtered results - Rationale: Ensures security cannot be bypassed through client-side manipulation
Tech Stackβ
| Category | Technology | Version | Purpose | Rationale |
|---|---|---|---|---|
| Frontend Language | TypeScript | ^5.0.0 | Type-safe frontend development | Existing choice - provides type safety for role-based UI components |
| Frontend Framework | Next.js | 14.x (App Router) | React-based web application | Existing choice - App Router provides excellent route protection patterns |
| UI Component Library | Material-UI (MUI) | ^5.14.0 | React component library | Existing choice - role-based component rendering fits MUI patterns |
| State Management | React Context | Built-in | Authentication and role state | Use React Context for auth state rather than adding Redux complexity |
| Backend Language | TypeScript | ^5.0.0 | Type-safe API development | Existing choice - shared types between frontend/backend crucial for RBAC |
| Backend Framework | NestJS | ^10.0.0 | Enterprise Node.js framework | Existing choice - guards and decorators perfect for role-based authorization |
| API Style | REST with Swagger | OpenAPI 3.0 | RESTful API with documentation | Existing choice - adding security schemas to existing Swagger setup |
| Database | PostgreSQL | ^15.0 | Relational database | Existing choice - excellent support for complex queries and constraints |
| ORM | Prisma | ^5.0.0 | Type-safe database client | Existing choice - middleware enables transparent tenant filtering |
| Cache | Redis (if needed) | ^7.0 | Session and API caching | Optional addition only if performance requires it |
| File Storage | Cloud Storage | Current | Document and file storage | Existing choice - maintain current file handling approach |
| Authentication | JWT | Standard | User authentication and JWT | JWT-based authentication with custom claims for roles and client access |
| Frontend Testing | Jest + React Testing Library | ^29.0 / ^13.0 | Component and integration testing | Existing testing approach - add role-based test scenarios |
| Backend Testing | Jest + Supertest | ^29.0 / ^6.0 | API testing framework | Existing testing approach - add authorization test scenarios |
| E2E Testing | Playwright or Cypress | ^1.40 / ^13.0 | End-to-end testing | Choose based on existing preference - test role-based workflows |
| Build Tool | npm workspaces | Built-in | Monorepo package management | Existing choice - maintains current build processes |
| Bundler | Next.js built-in | Webpack 5 | Frontend bundling | Existing choice - no changes needed |
| IaC Tool | Deployment Dashboard | Web-based | Infrastructure management | Existing choice - no complex IaC needed for current scale |
| CI/CD | GitHub Actions | Built-in | Automated testing and deployment | Recommended addition - automate security testing |
| Monitoring | Cloud Metrics | Built-in | Basic performance monitoring | Existing choice - sufficient for current needs |
| Logging | Winston or Pino | ^3.8 / ^8.0 | Structured logging with security audit trails | Addition required - audit logging for RBAC compliance |
| CSS Framework | Material-UI Theming | ^5.14.0 | Styling and theming | Existing choice - role-based theme variations if needed |
Data Modelsβ
User (JWT + Role Extension)β
Purpose: Represents EMTB staff and client users with role-based permissions and client access rights
Key Attributes:
- id: string - User identifier (primary key)
- email: string - User email address
- name: string - Full user name
- role: UserRole - Role enumeration (ADMIN, ACCOUNT_MANAGER, TAX_SPECIALIST, CLIENT)
- client_access: string[] - Array of client IDs this user can access
- created_at: DateTime - Account creation timestamp
- updated_at: DateTime - Last modification timestamp
interface User {
id: string;
email: string;
name: string;
role: UserRole;
client_access: string[]; // Client IDs this user can access
created_at: Date;
updated_at: Date;
}
enum UserRole {
ADMIN = "ADMIN", // Full system access
ACCOUNT_MANAGER = "ACCOUNT_MANAGER", // Assigned clients only
TAX_SPECIALIST = "TAX_SPECIALIST", // Assigned by account managers
CLIENT = "CLIENT", // Own company data only
}
Relationships:
- Has access to multiple clients through client_access array
- Role determines permission level within accessible clients
Client (Existing Model - Minimal Changes)β
Purpose: Represents business clients of EMTB with their company information
interface Client {
id: string;
company_name: string;
contact_email: string;
address: string;
created_at: Date;
// Existing fields preserved
sites?: Site[];
reclamations?: Reclamation[];
factures?: Facture[];
}
Relationships:
- One-to-many with Sites (existing)
- One-to-many with Reclamations (existing)
- One-to-many with Factures (existing)
Site (Existing Model - No Changes)β
Purpose: Represents physical locations for tax claims
interface Site {
id: string;
client_id: string;
site_name: string;
address: string;
// Tenant isolation through client_id relationship
client?: Client;
reclamations?: Reclamation[];
}
Relationships:
- Many-to-one with Client (existing) - This provides tenant isolation
- One-to-many with Reclamations (existing)
Reclamation (Existing Model - No Changes)β
Purpose: Represents tax claims (TF/CFE) for specific sites
interface Reclamation {
id: string;
client_id: string; // Direct client reference for efficient filtering
site_id: string;
claim_type: "TF" | "CFE";
amount: number;
status: string;
// Tenant isolation through client_id relationship
client?: Client;
site?: Site;
documents?: Document[];
}
Relationships:
- Many-to-one with Client (existing) - Primary tenant isolation
- Many-to-one with Site (existing)
- One-to-many with Documents (existing)
Document (Existing Model - No Changes)β
Purpose: File attachments related to tax claims
interface Document {
id: string;
reclamation_id: string;
filename: string;
file_path: string;
uploaded_at: Date;
// Tenant isolation through reclamation.client_id chain
reclamation?: Reclamation;
}
Relationships:
- Many-to-one with Reclamation (existing) - Tenant isolation through reclamation.client_id
API Specificationβ
REST API Specificationβ
openapi: 3.0.0
info:
title: EMTB Tax Claim Management API
version: 1.0.0
description: Role-based API for multi-tenant tax claim management with comprehensive authorization
servers:
- url: https://api.your-domain.com
description: Production API Server
- url: http://localhost:3001
description: Local Development Server
components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: JWT token with role and client_access claims
schemas:
User:
type: object
properties:
id:
type: string
email:
type: string
name:
type: string
role:
type: string
enum: [ADMIN, ACCOUNT_MANAGER, TAX_SPECIALIST, CLIENT]
client_access:
type: array
items:
type: string
description: Array of client IDs this user can access
ApiError:
type: object
properties:
error:
type: object
properties:
code:
type: string
message:
type: string
details:
type: object
timestamp:
type: string
format: date-time
requestId:
type: string
security:
- BearerAuth: []
paths:
# Client Management (Role-based access)
/api/clients:
get:
summary: List accessible clients
security:
- BearerAuth: []
x-required-roles: [ADMIN, ACCOUNT_MANAGER, TAX_SPECIALIST, CLIENT]
x-tenant-filter: client_access
description: Returns only clients the user has access to based on role and client_access array
responses:
"200":
description: List of accessible clients
"403":
description: Insufficient permissions
/api/clients/{clientId}:
get:
summary: Get client details
security:
- BearerAuth: []
x-required-roles: [ADMIN, ACCOUNT_MANAGER, TAX_SPECIALIST, CLIENT]
x-tenant-filter: client_access
parameters:
- name: clientId
in: path
required: true
schema:
type: string
responses:
"200":
description: Client details
"403":
description: No access to this client
# Tax Claims (Reclamations) - Tenant isolated
/api/clients/{clientId}/reclamations:
get:
summary: List tax claims for client
security:
- BearerAuth: []
x-required-roles: [ADMIN, ACCOUNT_MANAGER, TAX_SPECIALIST, CLIENT]
x-tenant-filter: client_access
parameters:
- name: clientId
in: path
required: true
schema:
type: string
responses:
"200":
description: List of tax claims for accessible client
"403":
description: No access to this client's data
Componentsβ
Authentication Gatewayβ
Responsibility: JWT token validation and user context extraction
Key Interfaces:
validateJWT(token: string): Promise<UserContext>extractUserContext(jwt: JWT): UserContext
Dependencies: JWT verification library, User service for role validation
Technology Stack: NestJS Guard using @nestjs/jwt for token verification
Tenant Context Serviceβ
Responsibility: Automatic data filtering based on user's client_access permissions extracted from JWT
Key Interfaces:
getCurrentUserContext(): UserContextfilterByClientAccess<T>(query: Query<T>): Query<T>validateClientAccess(clientId: string): boolean
Dependencies: Authentication Gateway, Prisma Client
Technology Stack: NestJS service with Prisma middleware for transparent query filtering
Role Authorization Serviceβ
Responsibility: Role-based endpoint access control using decorators and guards
Key Interfaces:
@RequireRoles(...roles: UserRole[])@RequireClientAccess(clientIdParam: string)validateRoleAccess(requiredRoles: UserRole[], userRole: UserRole): boolean
Dependencies: Authentication Gateway, Tenant Context Service
Technology Stack: NestJS custom decorators and guards with metadata reflection
API Client Service (Frontend)β
Responsibility: HTTP client that automatically includes JWT token in all requests
Key Interfaces:
get<T>(url: string): Promise<T>post<T>(url: string, data: any): Promise<T>upload(url: string, file: File): Promise<any>
Dependencies: JWT token storage and management
Technology Stack: Axios or Fetch with JWT token interceptor, no client-side filtering logic
Component Diagramsβ
External APIsβ
Auth0 Management APIβ
- Purpose: User authentication, JWT token validation, and custom claims management for role-based access control
- Documentation: https://auth0.com/docs/api/management/v2
- Base URL(s): https://YOUR_DOMAIN.auth0.com/api/v2/
- Authentication: Machine-to-machine token with Management API scopes
- Rate Limits: 1000 requests per minute for most endpoints
Key Endpoints Used:
GET /users/{id}- Retrieve user profile and custom claimsPATCH /users/{id}- Update user metadata including role and client_accessPOST /users/{id}/roles- Assign roles to usersGET /roles- List available roles
Integration Notes: Used for synchronizing user roles and client access permissions. JWT tokens from Auth0 contain custom claims (role, client_access) that drive server-side security filtering.
Core Workflowsβ
User Authentication and Context Establishmentβ
Client Data Access with Tenant Filteringβ
Database Schemaβ
Core Schema (Existing Tables - Preserved)β
-- Existing Client table (no changes required)
CREATE TABLE clients (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
company_name VARCHAR(255) NOT NULL,
contact_email VARCHAR(255) NOT NULL,
address TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Existing Site table (no changes required)
CREATE TABLE sites (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
client_id UUID NOT NULL REFERENCES clients(id) ON DELETE CASCADE,
site_name VARCHAR(255) NOT NULL,
address TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Existing Reclamation table (no changes required)
CREATE TABLE reclamations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
client_id UUID NOT NULL REFERENCES clients(id) ON DELETE CASCADE,
site_id UUID NOT NULL REFERENCES sites(id) ON DELETE CASCADE,
claim_type VARCHAR(10) NOT NULL CHECK (claim_type IN ('TF', 'CFE')),
amount DECIMAL(10,2) NOT NULL,
status VARCHAR(50) NOT NULL DEFAULT 'DRAFT',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Existing Document table (no changes required)
CREATE TABLE documents (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
reclamation_id UUID NOT NULL REFERENCES reclamations(id) ON DELETE CASCADE,
filename VARCHAR(255) NOT NULL,
file_path VARCHAR(500) NOT NULL,
file_size INTEGER,
mime_type VARCHAR(100),
uploaded_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
New RBAC Tables (Minimal Addition)β
-- User table with role and client access
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
name VARCHAR(255) NOT NULL,
role VARCHAR(50) NOT NULL CHECK (role IN ('ADMIN', 'ACCOUNT_MANAGER', 'TAX_SPECIALIST', 'CLIENT')),
client_access UUID[] DEFAULT '{}', -- Array of client IDs this user can access
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Audit log for security compliance
CREATE TABLE audit_logs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id),
action VARCHAR(100) NOT NULL,
resource_type VARCHAR(50) NOT NULL,
resource_id UUID,
client_context UUID,
success BOOLEAN NOT NULL,
error_message TEXT,
ip_address INET,
user_agent TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Frontend Architectureβ
The frontend architecture embraces the server-centric security principle where the UI is completely "security agnostic" - it simply displays whatever data the server returns after filtering.
Component Organizationβ
apps/frontend/src/
βββ components/
β βββ common/ # Shared UI components
β βββ clients/ # Client management components
β βββ reclamations/ # Tax claim components
β βββ documents/ # Document management
βββ services/ # API communication layer
β βββ api.ts # Base API client with JWT
β βββ clientService.ts # Client API calls
β βββ reclamationService.ts # Tax claim API calls
βββ contexts/ # React contexts
β βββ AuthContext.tsx # Auth0 integration (no security logic)
β βββ ApiContext.tsx # API client context
βββ hooks/ # Custom React hooks
β βββ useAuth.ts # Authentication state
β βββ useClients.ts # Client data fetching
βββ utils/ # Utilities
βββ constants.ts
API Client Setupβ
// services/api.ts - Simple API client that adds JWT to requests
import axios, { AxiosInstance } from "axios";
class ApiClient {
private client: AxiosInstance;
constructor() {
this.client = axios.create({
baseURL: process.env.NEXT_PUBLIC_API_URL,
});
// Automatically add JWT token to all requests
this.client.interceptors.request.use(async (config) => {
try {
const token = localStorage.getItem("jwt_token");
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
} catch (error) {
console.error("Failed to get access token:", error);
}
return config;
});
// Handle authorization errors globally
this.client.interceptors.response.use(
(response) => response,
(error) => {
if (error.response?.status === 401) {
window.location.href = "/login";
} else if (error.response?.status === 403) {
throw new Error("You do not have permission to access this resource");
}
throw error;
},
);
}
}
Backend Architectureβ
The backend architecture implements all security logic through a layered approach: authentication validation, role-based authorization, and transparent tenant filtering.
Controller Template (Security-First)β
// clients.controller.ts - Enhanced existing controller with security
import { Controller, Get, Post, Param, UseGuards } from "@nestjs/common";
import { JwtAuthGuard } from "../auth/guards/jwt-auth.guard";
import { RolesGuard } from "../auth/guards/roles.guard";
import { TenantAccessGuard } from "../auth/guards/tenant-access.guard";
import { Roles } from "../auth/decorators/roles.decorator";
import { UserRole } from "../auth/enums/user-role.enum";
@UseGuards(JwtAuthGuard, RolesGuard, TenantAccessGuard)
@Controller("clients")
export class ClientsController {
constructor(private readonly clientsService: ClientsService) {}
@Get()
@Roles(
UserRole.ADMIN,
UserRole.ACCOUNT_MANAGER,
UserRole.TAX_SPECIALIST,
UserRole.CLIENT,
)
async findAll() {
// Service automatically filters by user's client_access - no explicit filtering needed
return this.clientsService.findAll();
}
@Get(":id")
@Roles(
UserRole.ADMIN,
UserRole.ACCOUNT_MANAGER,
UserRole.TAX_SPECIALIST,
UserRole.CLIENT,
)
async findOne(@Param("id") id: string) {
// TenantAccessGuard already validated user can access this client
return this.clientsService.findOne(id);
}
}
Prisma Middleware for Automatic Filteringβ
// middleware/prisma-tenant.middleware.ts - Automatic query filtering
export function configurePrismaTenantMiddleware(
prisma: PrismaClient,
tenantContext: TenantContextService,
) {
prisma.$use(async (params, next) => {
const user = tenantContext.getCurrentUser();
if (!user) {
return next(params);
}
// Apply tenant filtering based on model
if (params.model === "Client") {
if (params.action === "findMany" || params.action === "findFirst") {
params.args.where = {
...params.args.where,
id: { in: user.clientAccess },
};
}
}
if (params.model === "Reclamation") {
params.args.where = {
...params.args.where,
clientId: { in: user.clientAccess },
};
}
return next(params);
});
}
Unified Project Structureβ
emtb/
βββ .github/ # CI/CD workflows
βββ apps/ # Application packages (existing)
β βββ frontend/ # Next.js application
β β βββ src/
β β β βββ components/ # UI components (security-agnostic)
β β β βββ pages/ # Next.js 14 app router
β β β βββ services/ # API client services
β β β βββ contexts/ # React contexts
β β βββ package.json
β βββ api/ # NestJS backend application
β βββ src/
β β βββ auth/ # Authentication & authorization (NEW)
β β βββ users/ # User management (NEW)
β β βββ clients/ # Client management (ENHANCED)
β β βββ reclamations/ # Tax claims (ENHANCED)
β β βββ prisma/ # Database client (ENHANCED)
β βββ package.json
βββ packages/ # Shared packages
β βββ shared/ # Shared types/utilities
β β βββ src/
β β β βββ types/ # TypeScript interfaces
β β β βββ constants/ # Shared constants
β β βββ package.json
β βββ config/ # Shared configuration
βββ docs/ # Documentation
β βββ prd.md
β βββ architecture.md # This document
β βββ security/ # Security documentation
βββ .env.example
βββ package.json
βββ README.md
Development Workflowβ
Prerequisitesβ
node --version # v18+ required
npm --version # v9+ required
docker --version # v20+ required (for PostgreSQL)
Initial Setupβ
# Install dependencies
npm install
# Setup environment files
cp .env.example apps/api/.env
cp .env.example apps/frontend/.env.local
# Start PostgreSQL database
docker run -d --name emtb-postgres -e POSTGRES_PASSWORD=password -p 5432:5432 postgres:15
# Run database migrations
cd apps/api && npx prisma migrate dev
Development Commandsβ
# Start all services
npm run dev
# Start frontend only
npm run dev:frontend
# Start backend only
npm run dev:api
# Run tests
npm run test
npm run test:security # Security-focused tests
Deployment Architectureβ
Deployment Strategyβ
Frontend Deployment:
- Platform: Cloud Static Hosting
- Build Command:
npm run build:frontend - CDN/Edge: CDN with global edge caching
Backend Deployment:
- Platform: Cloud Web Service
- Build Command:
npm run build:api - Database: Cloud PostgreSQL with automated backups
Environmentsβ
| Environment | Frontend URL | Backend URL | Purpose |
|---|---|---|---|
| Development | http://localhost:3000 | http://localhost:3001 | Local development with full RBAC testing |
| Staging | https://staging.your-domain.com | https://api-staging.your-domain.com | Pre-production RBAC validation |
| Production | https://app.your-domain.com | https://api.your-domain.com | Live environment with full security compliance |
Security and Performanceβ
Security Requirementsβ
Frontend Security:
- CSP Headers: Strict content security policy
- XSS Prevention: Next.js built-in XSS protection + Content Security Policy enforcement
- Secure Storage: JWT tokens in HTTP-only cookies or secure localStorage with encryption
Backend Security:
- Input Validation: Class-validator decorators on all DTOs
- Rate Limiting: 100 requests/minute per user, 1000/minute per IP
- CORS Policy: Restricted to frontend domains only
Authentication Security:
- Token Storage: JWT in HTTP-only, secure, SameSite cookies
- Session Management: JWT-based session management with automatic token refresh
Performance Optimizationβ
Frontend Performance:
- Bundle Size Target: < 500KB initial load
- Loading Strategy: Lazy loading for admin components
- Caching Strategy: Next.js ISR + SWR for API data
Backend Performance:
- Response Time Target: < 200ms for filtered queries, < 50ms RBAC overhead
- Database Optimization: Composite indexes on (client_id, created_at)
Testing Strategyβ
Test Organizationβ
apps/api/tests/
βββ unit/
β βββ auth/guards/
β βββ services/
βββ integration/
β βββ rbac-scenarios.spec.ts
β βββ tenant-isolation.spec.ts
βββ security/
βββ penetration-test.spec.ts
βββ data-leakage.spec.ts
Security Test Exampleβ
describe("Tenant Isolation (Integration)", () => {
it("should prevent cross-tenant data access", async () => {
const response = await request(app.getHttpServer())
.get("/api/clients")
.set("Authorization", `Bearer ${accountManager1Token}`)
.expect(200);
const clientIds = response.body.map((c) => c.id);
expect(clientIds).toContain("client-1");
expect(clientIds).not.toContain("unauthorized-client-3");
});
});
Coding Standardsβ
Critical Fullstack Rulesβ
- JWT Token Handling: Always use API client service - never make direct HTTP calls without proper token management
- Server-Side Validation: All authorization decisions must happen server-side - frontend never enforces security rules
- Tenant Context Access: Always use TenantContextService.getCurrentUser() - never access user context directly from JWT
- Database Queries: All Prisma queries automatically filtered through middleware - never bypass with raw queries
- Error Handling: Use standard error handlers with audit logging - never expose internal security details to frontend
- Route Protection: Only validate authentication (logged in?) in frontend - authorization (what access?) handled by API
- Password Security: Always hash passwords using bcrypt or argon2 before storing
Naming Conventionsβ
| Element | Frontend | Backend | Example |
|---|---|---|---|
| Components | PascalCase | - | ClientList.tsx |
| Services | camelCase + 'Service' | PascalCase + 'Service' | clientService.ts / ClientsService |
| API Routes | - | kebab-case | /api/clients |
| Guards | - | PascalCase + 'Guard' | TenantAccessGuard |
Error Handling Strategyβ
Error Response Formatβ
interface ApiError {
error: {
code: string;
message: string;
details?: Record<string, any>;
timestamp: string;
requestId: string;
};
}
Backend Error Handlingβ
@Catch(ForbiddenException, UnauthorizedException)
export class AuthExceptionFilter implements ExceptionFilter {
catch(
exception: ForbiddenException | UnauthorizedException,
host: ArgumentsHost,
) {
// Log security violation with full context (server-side only)
this.auditLog.logSecurityViolation({
requestId: randomUUID(),
userId: request.user?.auth0Id || "anonymous",
action: `${request.method} ${request.path}`,
reason: exception.message,
});
// Return sanitized error to client
response.status(status).json({
error: {
code: status === 401 ? "ERROR_UNAUTHORIZED" : "ERROR_FORBIDDEN",
message: "You do not have permission to access this resource",
timestamp: new Date().toISOString(),
requestId,
},
});
}
}
Monitoring and Observabilityβ
Monitoring Stackβ
- Frontend Monitoring: Cloud platform built-in metrics + browser error tracking
- Backend Monitoring: Cloud application metrics + custom security metrics
- Error Tracking: Winston logging with structured security event logging
Key Metricsβ
Security Metrics:
- Failed authorization attempts per user
- Cross-tenant access attempt rates
- Unusual access pattern detection
- Authorization check response times (< 50ms target)
Checklist Results Reportβ
Architecture Document Status: β COMPLETE
This comprehensive fullstack architecture document successfully addresses the EMTB RBAC enhancement requirements with:
- β Server-centric security model - All security decisions made server-side
- β Minimal database changes - Leveraging existing relationships for tenant isolation
- β Existing technology preservation - NestJS + Next.js + Auth0 + cloud infrastructure maintained
- β Comprehensive security layers - JWT validation, role guards, tenant filtering, audit logging
- β Complete implementation guidance - From database schema to deployment procedures
Key Architectural Decisions:
- No tenant_id columns - Using existing client relationships for data isolation
- Transparent server filtering - Prisma middleware automatically applies tenant context
- Security-agnostic frontend - UI simply displays server-filtered data
- Defense in depth - Multiple security layers (auth, roles, tenant access, audit)
The architecture is ready for implementation following the story sequence defined in the PRD.