Housingram API - Architecture & System Design Documentation

Note: For detailed API endpoint documentation, request/response formats, and interactive testing, please visit the Swagger Documentation (or Production API Docs).

Table of Contents


Architecture Overview

Housingram is a multi-tenant property management system designed for real estate builders/developers to manage their projects, units, and sales teams independently with complete data isolation.

Key Design Principles

  1. Schema-per-Tenant Isolation: Each tenant (builder) gets a dedicated PostgreSQL schema
  2. Repository Pattern: Clean separation between data access and business logic
  3. DTO Pattern: Input validation and output transformation
  4. Middleware Chain: Layered security and request processing
  5. Audit Logging: Complete audit trail of all data mutations

Technology Stack

Runtime: Node.js 18+ Framework: Express.js Database: PostgreSQL 15+ (with Sequelize ORM) Authentication: JWT (JSON Web Tokens) Security: bcryptjs, RBAC middleware Validation: Joi schemas Documentation: Swagger/OpenAPI 3.0 Logging: Winston with daily rotation Migrations: Umzug Containerization: Docker & Docker Compose

Multi-Tenant Strategy

Schema-per-Tenant Architecture

graph TB subgraph "PostgreSQL Database" subgraph "Public Schema" T[tenants table] SA[Super Admin users] end subgraph "Tenant 1 Schema" T1U[users] T1P[projects] T1UN[units] T1A[audit_logs] end subgraph "Tenant 2 Schema" T2U[users] T2P[projects] T2UN[units] T2A[audit_logs] end subgraph "Tenant N Schema" TNU[users] TNP[projects] TNUN[units] TNA[audit_logs] end end T -->|references| T1U T -->|references| T2U T -->|references| TNU T1P -->|contains| T1UN T2P -->|contains| T2UN TNP -->|contains| TNUN style T fill:#ff9999 style SA fill:#ff9999 style T1U fill:#99ccff style T2U fill:#99ff99 style TNU fill:#ffcc99

Why Schema-per-Tenant?


Database Schema

Public Schema

The public schema stores tenant metadata and Super Admin users.

erDiagram TENANTS { int id PK string name string contact enum subscription_type "Basic, Premium" string schema_name UK "e.g., tenant_1" boolean is_active timestamp created_at timestamp updated_at } SUPER_ADMIN_USERS { int id PK string name string email UK string password_hash enum role "Super Admin" boolean is_active timestamp created_at timestamp updated_at }

Tenant Schema

Each tenant has an isolated schema with the following structure:

erDiagram USERS { int id PK int tenant_id FK string name string email UK string password_hash enum role "Admin, Sales, Viewer" boolean is_active timestamp created_at timestamp updated_at } PROJECTS { int id PK int tenant_id FK string name string location text description int total_units enum status "Planning, Under Construction, Completed, On Hold" boolean is_active timestamp created_at timestamp updated_at } UNITS { int id PK int project_id FK string unit_number int floor decimal area int bedrooms int bathrooms decimal price enum status "Available, Booked, Sold" int booked_by FK timestamp booked_at timestamp sold_at boolean is_active timestamp created_at timestamp updated_at } AUDIT_LOGS { int id PK int user_id FK string action "CREATE, UPDATE, DELETE" string entity_type "user, project, unit" int entity_id json changes timestamp created_at } PROJECTS ||--o{ UNITS : "contains" USERS ||--o{ UNITS : "books" USERS ||--o{ AUDIT_LOGS : "performs"

Key Relationships


Authentication Flow

Two Separate Authentication Paths

sequenceDiagram participant C as Client participant API as API Server participant PUB as Public Schema participant TNT as Tenant Schema Note over C,TNT: Super Admin Authentication C->>API: POST /v1/auth/super-admin/login
{email, password} API->>PUB: Query public.users WHERE role='Super Admin' PUB-->>API: Super Admin User API->>API: Verify password + Generate JWT API-->>C: {token, user}
Token contains: {userId, role, isSuperAdmin} Note over C,TNT: Tenant User Authentication C->>API: POST /v1/auth/login
{email, password} API->>PUB: Find tenant by user email PUB-->>API: tenant_id, schema_name API->>TNT: Query {schema_name}.users WHERE email TNT-->>API: Tenant User API->>API: Verify password + Generate JWT API-->>C: {token, user}
Token contains: {userId, role, tenantId, tenantSchema}

JWT Token Structure

Super Admin Token:

{
  "userId": 1,
  "email": "superadmin@housingram.com",
  "role": "Super Admin",
  "isSuperAdmin": true,
  "iat": 1234567890,
  "exp": 1234654290
}

Tenant User Token:

{
  "userId": 5,
  "email": "admin@acmebuilders.com",
  "role": "Admin",
  "tenantId": 1,
  "tenantSchema": "tenant_1",
  "iat": 1234567890,
  "exp": 1234654290
}

Request Processing Flow

Complete Request Lifecycle

flowchart TD Start([HTTP Request]) --> Auth{Auth Middleware
authenticateToken} Auth -->|No Token| Reject1[401 Unauthorized] Auth -->|Invalid Token| Reject1 Auth -->|Valid Token| ReqType{Request Type?} ReqType -->|Super Admin| SAPath[Use Public Schema] ReqType -->|Tenant User| TResolver[Tenant Resolver
Middleware] TResolver --> SetSchema[Set search_path to
tenant schema] SetSchema --> RBAC SAPath --> RBAC{RBAC Middleware
checkPermission} RBAC -->|Insufficient
Permissions| Reject2[403 Forbidden] RBAC -->|Authorized| Validate{Validation
Middleware} Validate -->|Invalid Data| Reject3[400 Bad Request] Validate -->|Valid Data| Controller[Controller
Business Logic] Controller --> Service[Service Layer] Service --> Repo[Repository Layer] Repo --> DB[(PostgreSQL
Appropriate Schema)] DB --> Repo Repo --> Service Service --> Controller Controller --> Audit{Mutation Operation?} Audit -->|Yes| AuditLog[Audit Log Middleware
Record action] Audit -->|No| Response AuditLog --> Response[Success Response
200/201] Response --> End([HTTP Response]) Reject1 --> End Reject2 --> End Reject3 --> End style Auth fill:#e1f5ff style RBAC fill:#fff4e1 style Validate fill:#f0e1ff style Audit fill:#e1ffe8 style Response fill:#e8ffe1

Middleware Chain Details

  1. Authentication Middleware (auth.js)
  2. Tenant Resolver Middleware (tenantResolver.js)
  3. RBAC Middleware (rbac.js)
  4. Validation Middleware (validate.js)
  5. Audit Logger Middleware (auditLogger.js)

Role-Based Access Control

User Roles & Permissions Matrix

Resource Action Super Admin Tenant Admin Sales Viewer
TenantsCreate
TenantsRead
TenantsUpdate
TenantsActivate/Deactivate
UsersCreate
UsersRead
UsersUpdate
UsersDelete
ProjectsCreate
ProjectsRead
ProjectsUpdate
ProjectsDelete
UnitsCreate
UnitsRead
UnitsUpdate
UnitsBook
UnitsDelete
Audit LogsRead

Role Descriptions

🔴 Super Admin (Public Schema)

🔵 Admin (Tenant Schema)

🟢 Sales (Tenant Schema)

🟡 Viewer (Tenant Schema)


Tenant Onboarding Flow

Creating a New Tenant (Builder)

sequenceDiagram participant SA as Super Admin participant API as API Server participant PUB as Public Schema participant DB as PostgreSQL participant TNT as Tenant Schema SA->>API: POST /v1/super-admin/tenants
{name, contact, admin details} API->>API: Validate tenant data API->>PUB: INSERT INTO public.tenants PUB-->>API: tenant_id, schema_name (e.g., tenant_3) API->>DB: CREATE SCHEMA tenant_3 DB-->>API: Schema created API->>DB: Run tenant migrations on tenant_3 Note over API,DB: Creates users, projects,
units, audit_logs tables DB-->>API: Tables created API->>TNT: INSERT INTO tenant_3.users
{admin details, role='Admin'} TNT-->>API: Admin user created API->>PUB: UPDATE tenants SET is_active=true API-->>SA: Success Response
{tenant, admin_credentials} Note over SA: Admin can now login with
provided credentials

Automatic Schema Provisioning

When a new tenant is created:

  1. Record inserted in public.tenants table
  2. New PostgreSQL schema created (e.g., tenant_3)
  3. All tenant migrations executed on new schema
  4. Admin user created in tenant schema
  5. Credentials returned to Super Admin

Quick Start Guide

Prerequisites

Setup in 3 Steps

1. Start the Application

docker-compose up -d

2. Run Migrations & Seed Data

docker-compose exec app npm run migrate:public
docker-compose exec app npm run seed:super-admin

3. Access the Application

Service URL
APIhttp://localhost:3000
Swagger API Docshttp://localhost:3000/api-docs
Production APIhttps://real-estate-multi-tenant-api.onrender.com
Production Docshttps://real-estate-multi-tenant-api.onrender.com/api-docs

Default Super Admin Credentials

For development/testing:

⚠️ Change these credentials immediately in production!

Testing Workflow Example

flowchart LR A[1. Login as
Super Admin] --> B[2. Create
Tenant] B --> C[3. Login as
Tenant Admin] C --> D[4. Create
Project] D --> E[5. Create
Units] E --> F[6. Create
Sales User] F --> G[7. Login as
Sales] G --> H[8. Book
Unit] H --> I[9. View
Audit Logs] style A fill:#ff9999 style C fill:#99ccff style G fill:#99ff99

Step-by-Step Testing

  1. Login as Super Admin → Use default credentials
  2. Create Tenant → POST /v1/super-admin/tenants
  3. Login as Tenant Admin → Use credentials returned in step 2
  4. Create Project → POST /v1/projects
  5. Create Units → POST /v1/units (link to project)
  6. Create Sales User → POST /v1/users with role "Sales"
  7. Login as Sales User → GET sales user token
  8. Book a Unit → POST /v1/units/:id/book
  9. View Audit Logs → GET /v1/audit-logs
💡 Tip: Use Swagger UI for interactive testing with pre-filled examples!

Additional Documentation


Security Features


Built with ❤️ for Real Estate Builders & Developers

Generated on: