Aller au contenu principal

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​

DateVersionDescriptionAuthor
2025-09-09v1.0Initial fullstack architecture for RBAC implementationWinston (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​

CategoryTechnologyVersionPurposeRationale
Frontend LanguageTypeScript^5.0.0Type-safe frontend developmentExisting choice - provides type safety for role-based UI components
Frontend FrameworkNext.js14.x (App Router)React-based web applicationExisting choice - App Router provides excellent route protection patterns
UI Component LibraryMaterial-UI (MUI)^5.14.0React component libraryExisting choice - role-based component rendering fits MUI patterns
State ManagementReact ContextBuilt-inAuthentication and role stateUse React Context for auth state rather than adding Redux complexity
Backend LanguageTypeScript^5.0.0Type-safe API developmentExisting choice - shared types between frontend/backend crucial for RBAC
Backend FrameworkNestJS^10.0.0Enterprise Node.js frameworkExisting choice - guards and decorators perfect for role-based authorization
API StyleREST with SwaggerOpenAPI 3.0RESTful API with documentationExisting choice - adding security schemas to existing Swagger setup
DatabasePostgreSQL^15.0Relational databaseExisting choice - excellent support for complex queries and constraints
ORMPrisma^5.0.0Type-safe database clientExisting choice - middleware enables transparent tenant filtering
CacheRedis (if needed)^7.0Session and API cachingOptional addition only if performance requires it
File StorageCloud StorageCurrentDocument and file storageExisting choice - maintain current file handling approach
AuthenticationJWTStandardUser authentication and JWTJWT-based authentication with custom claims for roles and client access
Frontend TestingJest + React Testing Library^29.0 / ^13.0Component and integration testingExisting testing approach - add role-based test scenarios
Backend TestingJest + Supertest^29.0 / ^6.0API testing frameworkExisting testing approach - add authorization test scenarios
E2E TestingPlaywright or Cypress^1.40 / ^13.0End-to-end testingChoose based on existing preference - test role-based workflows
Build Toolnpm workspacesBuilt-inMonorepo package managementExisting choice - maintains current build processes
BundlerNext.js built-inWebpack 5Frontend bundlingExisting choice - no changes needed
IaC ToolDeployment DashboardWeb-basedInfrastructure managementExisting choice - no complex IaC needed for current scale
CI/CDGitHub ActionsBuilt-inAutomated testing and deploymentRecommended addition - automate security testing
MonitoringCloud MetricsBuilt-inBasic performance monitoringExisting choice - sufficient for current needs
LoggingWinston or Pino^3.8 / ^8.0Structured logging with security audit trailsAddition required - audit logging for RBAC compliance
CSS FrameworkMaterial-UI Theming^5.14.0Styling and themingExisting 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(): UserContext
  • filterByClientAccess<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​

Key Endpoints Used:

  • GET /users/{id} - Retrieve user profile and custom claims
  • PATCH /users/{id} - Update user metadata including role and client_access
  • POST /users/{id}/roles - Assign roles to users
  • GET /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​

EnvironmentFrontend URLBackend URLPurpose
Developmenthttp://localhost:3000http://localhost:3001Local development with full RBAC testing
Staginghttps://staging.your-domain.comhttps://api-staging.your-domain.comPre-production RBAC validation
Productionhttps://app.your-domain.comhttps://api.your-domain.comLive 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​

ElementFrontendBackendExample
ComponentsPascalCase-ClientList.tsx
ServicescamelCase + '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:

  1. No tenant_id columns - Using existing client relationships for data isolation
  2. Transparent server filtering - Prisma middleware automatically applies tenant context
  3. Security-agnostic frontend - UI simply displays server-filtered data
  4. 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.