Initializing
Back to Projects
Year2024
DomainFullstack
AccessOpen Source
Complexity0 / 10
Next.jsExpresstRPCPostgreSQLRedisTurborepoMulti-tenantGovernmentCivic Services
FullstackProduction

Town Committee Management System (TCMS)

A production-grade multi-tenant monorepo for managing town committee operations with citizen services, building permits, lease management, room rentals, and comprehensive admin dashboard.

Parsing system architecture diagram...

Technology Stack

LayerTechnologyVersion/Details
FrontendNext.js16.0.7
BackendExpress4.18.2
API LayertRPC11.7.2
DatabasePostgreSQL15 Alpine
ORMPrisma5.18.0
CacheRedis7 Alpine
AuthenticationNextAuth.js5.0.0-beta.30
ValidationZod3.22.4
FormsReact Hook Form7.68.0
StateTanStack Query5.90.12
PaymentsRazorpay2.9.6
StylingTailwind CSS4.x
MonorepoTurborepoLatest
Package Managerpnpm8+
DeploymentDocker, NGINXLatest

Purpose and Philosophy

The Town Committee Management System (TCMS) is a comprehensive platform designed to digitize and streamline civic operations for town committees and municipal bodies. The system embodies the principle that government services should be accessible, transparent, and efficient for citizens while providing powerful administrative tools for committee staff.

The project follows a multi-tenant architecture supporting multiple town committees with complete data isolation. Each tenant operates independently with their own branding, configuration, and user base while sharing the same underlying infrastructure. This SaaS-like model enables cost-effective deployment for multiple municipalities.

Core Design Principles

  1. Citizen-Centric Services: All citizen-facing features prioritize accessibility, mobile-first responsiveness, and intuitive user experience. Services like building permits, room rentals, and lease agreements guide users through multi-step wizard processes.
  1. Type-Safe Development: The monorepo uses tRPC for end-to-end type safety between frontend and backend. Shared packages (shared-types, validators, utils) ensure consistent types across all applications.
  1. Aadhaar Integration: Real-time Aadhaar-based citizen identification enables duplicate prevention, automatic form population, and secure identity verification for all citizen services.
  1. Payment Flexibility: The system supports both online (Razorpay) and offline (cash/bank transfer) payment modes with admin verification workflows, ensuring accessibility for all citizens regardless of digital literacy.
  1. Role-Based Access Control: Three-tier RBAC (Developer, Admin, Citizen) ensures proper separation of concerns. Developers manage platform configuration, Admins handle daily operations, and Citizens access services.

Architecture Deep Dive

Monorepo Structure

code
TCP/ (Town Committee Project)
├── apps/
│   ├── web/                     # Next.js 16 frontend
│   │   ├── app/                 # App Router pages
│   │   │   ├── page.tsx         # Landing page
│   │   │   ├── auth/            # Authentication pages
│   │   │   ├── permit/          # Building permits
│   │   │   ├── room-rent/       # Room rentals
│   │   │   ├── lease/           # Lease agreements
│   │   │   ├── lease-sale/      # Lease transfers
│   │   │   ├── services/        # Service requests
│   │   │   ├── admin/           # Admin dashboard
│   │   │   └── developer/       # Developer console
│   │   ├── components/          # React components
│   │   └── lib/                 # Utilities & API client
│   │
│   └── api/                     # Express + tRPC backend
│       ├── src/
│       │   ├── index.ts         # Express server entry
│       │   ├── router/          # tRPC routers
│       │   ├── procedures/      # tRPC procedures
│       │   └── prisma/          # Database client
│       └── prisma/
│           └── schema.prisma    # Database schema

├── packages/
│   ├── shared-types/           # Shared TypeScript interfaces
│   ├── validators/             # Shared Zod validation schemas
│   └── utils/                  # Shared utility functions

├── docker/
│   ├── local.compose.yml       # Local development
│   └── prod.compose.yml        # Production deployment

└── nginx/
    └── nginx.conf              # Production reverse proxy

Database Schema

The Prisma schema defines comprehensive data models for all civic operations:

Citizen Management:

prisma
model Citizen {
  id                      String    @id @default(uuid())
  aadhaarNumber           String    @unique
  aadhaarHash             String?   @unique  // Secure lookups
  name                    String
  mobileNumber            String    @unique
  email                   String?   @unique
  fullAddress             String
  kycStatus               String    @default("PENDING")
  
  // Credit Management
  totalCreditAmount       Decimal   @default(0)
  availableCreditAmount   Decimal   @default(0)
  
  buildingPermits BuildingPermit[]
  roomRentals     RoomRental[]
  leaseAgreements LeaseAgreement[]
  leaseSales      LeaseSale[]
  serviceRequests ServiceRequest[]
  payments        Payment[]
}

Building Permits:

prisma
model BuildingPermit {
  id                String    @id @default(uuid())
  applicationNo     String    @unique
  citizenId         String
  landDagNo         String?
  landPattaNo       String?
  buildingType      String?
  buildingCategory  String?
  buildupArea       Decimal?
  applicationStatus String?
  applicationFee    Decimal?
  scrutinyFee       Decimal?
  totalAmountDue    Decimal?
}

Multi-Tenancy Models:

prisma
model Tenant {
  id                    String    @id @default(uuid())
  developerId           String
  name                  String
  slug                  String    @unique
  adminId               String    @unique
  pricingTierId         String
  isWhiteLabeled        Boolean   @default(false)
  customDomain          String?
  
  branding    TenantBranding?
  tenantUsers TenantUser[]
}

model PricingTier {
  id           String   @id @default(uuid())
  developerId  String
  name         String
  monthlyPrice Decimal?
  yearlyPrice  Decimal?
  maxUsers     Int?
  maxStorageGb Int?
  
  tierFeatures TierFeature[]
  tenants      Tenant[]
}

tRPC API Structure

The backend uses tRPC for type-safe API communication:

typescript
// Public procedures
export const publicProcedure = t.procedure;

// Protected procedures (Admin)
export const adminProcedure = t.procedure.use(isAdmin);

// Router example
export const appRouter = router({
  // Citizen services
  citizen: router({
    create: publicProcedure.input(createCitizenSchema).mutation(...),
    getByAadhaar: publicProcedure.input(aadhaarSchema).query(...),
  }),
  
  // Building permits
  permit: router({
    create: publicProcedure.input(permitSchema).mutation(...),
    list: adminProcedure.query(...),
    updateStatus: adminProcedure.input(statusSchema).mutation(...),
  }),
  
  // Room rentals
  roomRent: router({
    create: publicProcedure.input(rentalSchema).mutation(...),
    list: adminProcedure.query(...),
  }),
  
  // Leases
  lease: router({
    create: publicProcedure.input(leaseSchema).mutation(...),
    transfer: publicProcedure.input(transferSchema).mutation(...),
  }),
  
  // Payments
  payment: router({
    initiate: publicProcedure.input(paymentSchema).mutation(...),
    verify: publicProcedure.input(verifySchema).mutation(...),
    verifyOffline: adminProcedure.input(offlineVerifySchema).mutation(...),
  }),
});

Key Features and Functionality

1. Citizen Services

Building Permission (/permit)

  • 5-step wizard: Applicant → Land Details → Building Details → Fees → Receipt
  • Dynamic fee calculation based on building category
  • Application tracking and status updates

Room Rental (/room-rent)

  • 3-step process: Tenant → Room & Rent Details → Receipt
  • Aadhaar-based tenant verification
  • Monthly rent tracking with ledger

Lease Agreements (/lease)

  • 4-step wizard: Applicant → Property → Terms → Receipt
  • Aadhaar citizen lookup with duplicate prevention
  • Payment frequency selection (Quarterly/Yearly)

Lease Sale/Transfer (/lease-sale)

  • 5-step process: Seller → Buyer → Property → Premium → Confirmation → Receipt
  • Dual Aadhaar verification for both parties
  • Premium amount calculation

Service Requests (/services)

  • NOC, Corrections, Complaints, General Queries
  • Single-page form with dropdown selection

2. Authentication & Authorization

NextAuth.js Integration:

  • Credentials provider for email/mobile login
  • Session-based authentication
  • JWT tokens for API security

Role-Based Access:

  • Developer: Platform configuration, tenant management, pricing tiers
  • Admin: Daily operations, citizen management, payments, reports
  • Citizen: Service applications, payment submissions, application tracking

Protected Setup:

  • One-time system initialization at /setup
  • Password-protected with SETUP_PASSWORD
  • 4-step wizard: Auth → Database → Admin User → Developer User

3. Payment Processing

Online Payments (Razorpay):

  • Integration with Razorpay SDK
  • Signature verification for webhook security
  • Real-time payment status tracking

Offline Payments:

  • Cash and Bank Transfer support
  • Proof document upload
  • Admin verification workflow
  • Manual approval/rejection

Receipt Generation:

  • Professional PDF receipts via react-to-print
  • Unique receipt numbers
  • Downloadable and printable

4. Admin Dashboard

Comprehensive admin panel with:

  • Overview: Revenue statistics, permit counts, rental status, service requests
  • Permits: Review and approve building permits
  • Rentals: Track room rentals and occupancy
  • Leases: Manage lease agreements and payments
  • Services: Handle citizen service requests and NOCs
  • Users: Search, filter, and manage registered citizens
  • Settings: Configure pricing rules and fee structures

5. Developer Console

Platform-level controls:

  • Tenant Management: View, edit, and manage all tenants
  • Platform Branding: Customize logo, colors, themes
  • Payment Configuration: Global Razorpay keys and UPI settings
  • Email System: SMTP configuration for system emails
  • System Controls: Maintenance mode, debug flags

6. Multi-Tenancy

Each town committee (tenant) gets:

  • Isolated database records (via tenantId)
  • Custom branding (logo, colors, favicon)
  • Custom domain support
  • Pricing tier allocation
  • Subscription management

Database Models Overview

DomainModels
IdentityCitizen, User, Tenant, TenantUser
BuildingBuildingPermit, FeeStructure
RentalRoomRental, RentPayment, RentLedger
LeaseLeaseAgreement, LeasePayment, LeaseLedger, LeaseSale
PaymentsPayment, CreditLedger
ServicesServiceRequest, SupportTicket
Multi-TenancyTenant, TenantBranding, PricingTier, Feature, TierFeature
SettingsDeveloperSettings, AdminSettings, SystemSettings
AuditAuditLog, CitizenAuditLog, TicketAuditTrail

Development and Operations

Local Development

bash
# Install dependencies
pnpm install

# Start database services
docker-compose -f docker/local.compose.yml up -d

# Setup database
cd apps/api
npx prisma generate
npx prisma migrate dev --name init

# Start all apps
pnpm dev

Production Deployment

bash
# Production Docker
docker-compose -f docker/prod.compose.yml up -d --build

# Environment variables required:
# DATABASE_URL, REDIS_URL, SETUP_PASSWORD
# RAZORPAY_KEY_ID, RAZORPAY_KEY_SECRET
# NEXTAUTH_SECRET, NEXTAUTH_URL

Architecture

code
Internet

NGINX (Port 80/443)
   ├── Rate Limiting (100 req/s)
   ├── Security Headers
   └── SSL/TLS

Next.js App (Port 3000)
   ├── Frontend (SSR)
   └── tRPC API

PostgreSQL (5432) + Redis (6379)

Security Implementation

Authentication

  • NextAuth.js v5 with credentials provider
  • bcrypt password hashing
  • Session-based authentication
  • JWT token management

API Security

  • tRPC middleware for procedure protection
  • Bearer token authorization
  • Input validation with Zod schemas

Infrastructure

  • NGINX rate limiting (100 req/s)
  • Security headers (X-Frame-Options, XSS Protection)
  • Redis password protection
  • Environment variable secrets

Audit Trail

  • Complete audit logging for admin actions
  • Citizen audit logs for profile changes
  • Ticket audit trails for support requests

Lessons Learned and Best Practices

What Worked Well

  1. tRPC Type Safety: End-to-end type safety eliminates runtime errors and improves developer experience
  2. Multi-Tenant Isolation: Clean separation enables safe multi-organization deployment
  3. Zod Validation: Shared validators in packages ensure consistent validation across frontend and backend
  4. Multi-Step Wizards: Progressive form design improves completion rates for complex applications

Areas for Enhancement

  1. Real-time Updates: Could add WebSocket for live status notifications
  2. Mobile Apps: React Native wrapper would extend accessibility
  3. Advanced Reporting: Could add more sophisticated analytics dashboards

Conclusion

The Town Committee Management System represents a comprehensive solution for municipal digitization. With its multi-tenant architecture, type-safe monorepo structure, and extensive citizen services, it provides a robust foundation for efficient civic administration.

The system successfully balances citizen accessibility with administrative control, offering features like Aadhaar verification, flexible payment options, and comprehensive audit trails. The production-ready deployment with Docker and NGINX ensures reliability and scalability for growing municipalities.

Implementation Details

API Endpoints Overview

The tRPC API provides comprehensive endpoints for all services:

Public Endpoints (No Auth Required):

  • citizen.create: Register new citizen with Aadhaar verification
  • citizen.findByMobile: Search citizen by mobile number
  • citizen.findByAadhaar: Search citizen by Aadhaar
  • permit.create: Submit building permit application
  • roomRent.create: Register room rental
  • lease.create: Create new lease agreement
  • lease.transfer: Transfer lease ownership
  • serviceRequest.create: Submit civic service request
  • payment.initiate: Initiate online payment via Razorpay
  • payment.verifyWebhook: Verify payment webhook signature
  • setup.initialize: One-time system initialization

Protected Endpoints (Admin Required):

  • permit.list: Get all permits with filters
  • permit.updateStatus: Approve/reject building permit
  • permit.getById: Get single permit details
  • rental.list: Get all room rentals
  • rental.update: Update rental details
  • lease.list: Get all lease agreements
  • lease.getById: Get lease details
  • payment.verifyOffline: Verify offline payment proof
  • citizen.list: List all registered citizens
  • citizen.manualVerify: Admin manual KYC verification
  • serviceRequest.list: Get all service requests
  • serviceRequest.updateStatus: Update request status

Protected Endpoints (Developer Only):

  • tenant.list: Get all tenants
  • tenant.create: Create new tenant
  • tenant.updateSettings: Update tenant configuration
  • pricing.list: List pricing tiers
  • pricing.create: Create pricing tier
  • developer.updateSettings: Update platform settings
  • developer.updateBranding: Update platform branding

Data Flow Examples

Building Permit Application Flow:

  1. Citizen fills 5-step wizard form
  2. Frontend validates each step with Zod schemas
  3. On final submission, tRPC mutation calls permit.create
  4. API generates unique application number
  5. Fee calculation based on building category and area
  6. Payment page shows options (Online/Offline)
  7. On successful payment, permit status updates to "submitted"
  8. Admin receives notification, reviews, and updates status

Citizen Registration with Aadhaar:

  1. Citizen enters Aadhaar number
  2. API checks for existing record (duplicate prevention)
  3. If new, creates citizen record with "PENDING" KYC status
  4. Mobile/email verification links sent
  5. Admin can manually verify via admin dashboard
  6. KYC status updates to "VERIFIED"

Form Validation Strategies

The system uses Zod schemas for validation across both frontend and backend:

typescript
// Example: Building Permit Schema
export const buildingPermitSchema = z.object({
  applicantType: z.enum(["OWNER", "TENANT", "OTHER"]),
  landDagNo: z.string().min(1, "Dag number required"),
  landPattaNo: z.string().optional(),
  mouza: z.string().optional(),
  revenueCircle: z.string().optional(),
  landArea: z.string().min(1, "Land area required"),
  ownershipType: z.enum(["INDIVIDUAL", "JOINT", "INSTITUTION"]),
  locationRoadName: z.string().min(1, "Road name required"),
  locationWardNo: z.string().min(1, "Ward number required"),
  buildingType: z.enum(["RESIDENTIAL", "COMMERCIAL", "INDUSTRIAL", "MIXED"]),
  buildingCategory: z.enum(["A", "B", "C", "D"]),
  proposedUse: z.string().min(1, "Proposed use required"),
  numFloors: z.number().min(1).max(10),
  buildupArea: z.number().positive(),
});

Credit Management System

The system includes a credit wallet for citizens:

prisma
model CreditLedger {
  id              String   @id @default(uuid())
  citizenId       String
  transactionType String   // PURCHASE, USED, REFUND, ADJUSTMENT
  amount          Decimal
  debitAmount     Decimal  @default(0)
  creditAmount    Decimal  @default(0)
  runningBalance  Decimal?
  referenceTable  String?
  referenceId     String?
  description     String?
  createdAt       DateTime @default(now())
  createdByUserId String?  // Admin who created the credit
}

This enables:

  • Advance payments for services
  • Credit transfers between citizens
  • Refund processing
  • Adjustment for erroneous charges

Pricing and Subscription Model

Multi-tenant pricing tiers allow different municipalities to choose features:

TierMonthly PriceMax UsersFeatures
Basic₹5,0005Core services
Standard₹10,00020+ Reports, Analytics
Premium₹25,000Unlimited+ Custom domain, White-label

Each tier enables specific features defined in the TierFeature model.

Docker Development Environment

The local development uses Docker Compose for database services:

yaml
# docker/local.compose.yml
services:
  postgres:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
      POSTGRES_DB: town_committee
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data

Production NGINX Configuration

The production deployment uses NGINX as reverse proxy:

nginx
# nginx/nginx.conf (simplified)
server {
    listen 80;
    server_name tcms.example.com;

    # Rate limiting
    limit_req zone=api burst=100 nodelay;

    # Security headers
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;

    # Proxy to Next.js
    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

This configuration includes:

  • Rate limiting (100 requests per second)
  • Security headers (X-Frame-Options, CSP, etc.)
  • WebSocket support for hot reload
  • Proper proxy buffering

Summary

The Town Committee Management System (TCMS) demonstrates a production-grade approach to government digitization. Key accomplishments include:

  • Type-safe monorepo with tRPC ensuring end-to-end TypeScript coverage
  • Multi-tenant architecture enabling multiple municipalities on one platform
  • Comprehensive citizen services covering permits, rentals, leases, and service requests
  • Flexible payment options supporting both online and offline transactions
  • Complete audit trail for accountability and transparency
  • Production-ready infrastructure with Docker and NGINX

The project serves as a template for similar government digitization initiatives, providing a balance of accessibility for citizens and control for administrators while maintaining technical excellence through modern development practices.

Architecture Feedback

Spotted a potential optimization or antipattern? Let me know.

Submit a Technical Suggestion