Skip to content

Repository files navigation

Society Maintenance Tracker

Live Deployed Link --> https://societymaintancetracker.onrender.com/

A full-stack, enterprise-grade apartment society maintenance management platform built with Next.js 14/15 (TypeScript, React, Tailwind CSS) and Prisma ORM.

The platform bridges communication between apartment residents and society administration, providing transparent complaint lifecycle tracking, dynamic overdue escalation, photo evidence attachments, pinned society notices, and automated email updates.


Table of Contents

  1. Key Features
  2. Tech Stack
  3. Quickstart & Local Setup
  4. Pre-Seeded Demo Accounts
  5. Environment Variables (.env.example)
  6. Database Schema & ER Model
  7. Comprehensive API Documentation
  8. System Design Highlights
  9. Deployment Guide (Vercel / Render / Railway)
  10. Packaging & Deliverables

Key Features

  • Role-Based Access Control (RBAC): Distinct permissions and workflows for RESIDENT and ADMIN users.
  • Complaint Lifecycle & Audit Trail: Full state transitions (OPEN $\rightarrow$ IN_PROGRESS $\rightarrow$ RESOLVED) with immutable timestamped logs capturing actor name, role, and action notes.
  • Dynamic Overdue Escalation: Configurable threshold days; overdue complaints bubble to the top of the admin triage queue with visual alerts.
  • Photo Evidence Pipeline: Drag-and-drop file upload with preview, file size/type validation, and full-resolution lightbox viewer.
  • Notice Board & Broadcast System: Pinned important notices with automatic email dispatch to all registered residents.
  • Dual-Mode Notification Engine: Supports live SMTP delivery and includes a built-in In-App Outbox Inspector (/admin/outbox) for immediate evaluation without external SMTP credentials.
  • Admin Analytics Dashboard: Real-time KPI summary cards, facility category breakdown charts (Recharts), and status distributions.

Tech Stack

Layer Technology
Framework Next.js 14/15 (App Router, TypeScript)
Frontend UI React 18/19, Tailwind CSS, Lucide Icons
Charts & Visuals Recharts Data Visualizations
ORM & Database Prisma ORM with SQLite (Local) / PostgreSQL (Production)
Auth & Security JWT (JSON Web Tokens), bcryptjs password hashing
Notifications Nodemailer (SMTP) + Database Outbox Logger

Quickstart & Local Setup

Prerequisites

  • Node.js 18.x or 20.x+
  • npm or yarn

1. Clone & Install Dependencies

git clone <repository-url>
cd society-maintenance-tracker
npm install

2. Configure Environment

Copy the example environment file:

cp .env.example .env

3. Initialize & Seed Database

Run Prisma migrations and populate the database with realistic test data (admins, residents, active/overdue complaints, notices, audit history):

npx prisma db push
npm run prisma:seed

4. Start Development Server

npm run dev

Open http://localhost:3000 in your browser.


Pre-Seeded Demo Accounts

The database comes pre-populated with ready-to-test accounts. You can also use the 1-Click Quick Demo Login buttons on the login page:

Role Email Password Details
Estate Admin admin@society.com Admin@123 Full admin privileges, overdue controls, outbox logs
Resident 1 john.doe@society.com Resident@123 John Doe (Flat A-101) - Has active/overdue plumbing ticket
Resident 2 jane.smith@society.com Resident@123 Jane Smith (Flat B-204) - Has elevator ticket
Resident 3 robert.chen@society.com Resident@123 Robert Chen (Flat C-305) - Has electrical ticket

Environment Variables (.env.example)

# Database Connection (SQLite default for zero-setup local dev; change to postgresql:// for production)
DATABASE_URL="file:./dev.db"

# JWT Secret for Session Signing
JWT_SECRET="society_maintenance_tracker_jwt_secret_key_2026_unthinkable"

# Base Application URL
NEXT_PUBLIC_APP_URL="http://localhost:3000"

# Optional SMTP Settings (If omitted, emails are logged to the in-app outbox inspector at /admin/outbox)
SMTP_HOST=""
SMTP_PORT="587"
SMTP_USER=""
SMTP_PASS=""
SMTP_FROM="Society Admin <noreply@societytracker.com>"

# Default Overdue Threshold (Days)
DEFAULT_OVERDUE_DAYS="3"

Database Schema & ER Model

┌────────────────────────────────┐       1:N       ┌──────────────────────────────┐
│             User               ├─────────────────►│          Complaint           │
├────────────────────────────────┤                 ├──────────────────────────────┤
│ id (PK)                        │                 │ id (PK)                      │
│ name                           │                 │ ticketNumber (UK)            │
│ email (UK)                     │                 │ title                        │
│ password (Hash)                │                 │ description                  │
│ role (RESIDENT | ADMIN)        │                 │ category (PLUMBING, etc.)    │
│ flatNumber                     │                 │ priority (LOW, MEDIUM, HIGH) │
│ phoneNumber                    │                 │ status (OPEN, IN_PROGRESS,   │
│ createdAt / updatedAt          │                 │         RESOLVED)            │
└───────┬───────────────────┬────┘                 │ photoUrl                     │
        │                   │                      │ residentId (FK)              │
        │ 1:N               │ 1:N                  │ createdAt / resolvedAt       │
        ▼                   ▼                      └──────────────┬───────────────┘
┌───────────────┐   ┌──────────────────────────────┐              │ 1:N
│    Notice     │   │    ComplaintStatusHistory    │◄─────────────┘
├───────────────┤   ├──────────────────────────────┤
│ id (PK)       │   │ id (PK)                      │
│ title         │   │ complaintId (FK)             │
│ content       │   │ fromStatus                   │
│ isImportant   │   │ toStatus                     │
│ authorId (FK) │   │ actorId (FK)                 │
│ createdAt     │   │ actorName                    │
└───────────────┘   │ actorRole                    │
                    │ note                         │
                    │ createdAt                    │
                    └──────────────────────────────┘

┌──────────────────────────────┐       ┌──────────────────────────────┐
│        SystemSetting         │       │           EmailLog           │
├──────────────────────────────┤       ├──────────────────────────────┤
│ id (PK)                      │       │ id (PK)                      │
│ key (UK, e.g. OVERDUE_DAYS)  │       │ recipientEmail / Name        │
│ value                        │       │ subject                      │
│ description                  │       │ type (STATUS_CHANGE, etc.)   │
│ updatedAt                    │       │ contentHtml                  │
└──────────────────────────────┘       │ status (SENT | SIMULATED)    │
                                       │ createdAt                    │
                                       └──────────────────────────────┘

Comprehensive API Documentation

1. Authentication Endpoints

POST /api/auth/register

Registers a new resident or admin account.

  • Request Body:
    {
      "name": "Alex Morgan",
      "email": "alex@society.com",
      "password": "Password@123",
      "role": "RESIDENT",
      "flatNumber": "A-502",
      "phoneNumber": "+1 555-0199"
    }
  • Response (201 Created):
    {
      "message": "Registration successful",
      "user": { "id": "...", "name": "Alex Morgan", "email": "alex@society.com", "role": "RESIDENT" },
      "token": "eyJhbGciOiJIUzI1NiIs..."
    }

POST /api/auth/login

Authenticates a user and returns a signed JWT token (also sets HTTP-only cookie).

  • Request Body:
    { "email": "admin@society.com", "password": "Admin@123" }

GET /api/auth/me

Fetches authenticated user profile from active session.

POST /api/auth/logout

Clears authentication cookie and terminates session.


2. Complaints Endpoints

GET /api/complaints

Fetches complaints. If accessed by a resident, returns only their own complaints. If accessed by an admin, returns all society complaints with overdue tickets surfaced at the top.

  • Query Parameters:
    • category (PLUMBING, ELECTRICAL, ELEVATOR, SECURITY, CLEANLINESS, CARPENTRY, OTHER, ALL)
    • status (OPEN, IN_PROGRESS, RESOLVED, ALL)
    • search (Search by ticket number, title, or resident details)
    • dateFrom / dateTo (YYYY-MM-DD range)
    • overdueOnly (true / false)
  • Sample Response:
    {
      "complaints": [
        {
          "id": "clx123",
          "ticketNumber": "CMP-2026-0001",
          "title": "Kitchen pipe leaking",
          "category": "PLUMBING",
          "priority": "HIGH",
          "status": "OPEN",
          "photoUrl": "/uploads/complaint_1.jpg",
          "isOverdue": true,
          "daysOpen": 5,
          "createdAt": "2026-08-17T10:00:00.000Z",
          "resident": { "name": "John Doe", "flatNumber": "A-101" }
        }
      ],
      "thresholdDays": 3,
      "count": 1
    }

POST /api/complaints

Raises a new complaint (Resident only).

  • Request Body:
    {
      "title": "Corridor light fixture broken",
      "description": "Hallway light outside flat 204 is non-functional.",
      "category": "ELECTRICAL",
      "photoUrl": "/uploads/photo_123.jpg"
    }

GET /api/complaints/:id

Retrieves detailed complaint information including full chronological lifecycle audit trail.

PATCH /api/complaints/:id

Updates status and priority with mandatory audit logging (Admin only).

  • Request Body:
    {
      "status": "IN_PROGRESS",
      "priority": "HIGH",
      "note": "Electrician team dispatched with replacement ballast."
    }
  • Triggers asynchronous email notification to the resident.

3. Notices & Broadcasts

GET /api/notices

Retrieves all society notices. Pinned important notices are ordered first.

POST /api/notices

Publishes a new society notice (Admin only).

  • Request Body:
    {
      "title": "⚡ Scheduled Power Maintenance This Saturday",
      "content": "Power maintenance will be carried out between 10 AM and 2 PM.",
      "isImportant": true
    }
  • Setting isImportant: true pins the notice to the top and triggers an email broadcast to all residents.

4. System Settings & Analytics

GET /api/settings

Returns current system settings (e.g., overdueThresholdDays).

POST /api/settings

Updates overdue threshold in days (Admin only).

  • Request Body:
    { "overdueThresholdDays": 5 }

GET /api/dashboard

Returns aggregated analytics metrics (Admin only):

  • Total, Open, In Progress, Resolved, and Overdue complaint counts.
  • Facility breakdown by category and priority.
  • Recent audit history feed.

POST /api/upload

Accepts multipart/form-data image file upload (image/jpeg, image/png, image/webp), validates $\le 5\text{MB}$, stores file, and returns public URL.

GET /api/outbox

Returns the recent notification outbox log for in-browser inspection.


System Design Highlights

Refer to SYSTEM_DESIGN.md for the complete 800-word architectural write-up covering:

  1. Complaint History Model: Event-sourced audit logging with atomic transaction integrity.
  2. Overdue Detection: Dynamic SLA calculation and queue bubbling.
  3. Photo Asset Pipeline: Secure MIME verification, sanitized storage, and lightbox viewing.
  4. Notification Architecture: Dual-mode SMTP delivery with fallback database logging.

Deployment Guide (Vercel / Render / Railway)

Deploying to Vercel (Recommended)

  1. Push repository to GitHub.
  2. Import project into Vercel.
  3. Under Environment Variables, set:
    • DATABASE_URL: Your PostgreSQL / Supabase / Neon connection string.
    • JWT_SECRET: A secure random 32-character string.
    • NEXT_PUBLIC_APP_URL: Your production Vercel domain.
  4. Set Build Command: prisma generate && next build.
  5. Deploy!

Deploying to Render / Railway

  1. Create a new Web Service connecting to your GitHub repository.
  2. Select Node.js environment.
  3. Set Build Command: npm install && npx prisma generate && npm run build.
  4. Set Start Command: npm start.
  5. Add PostgreSQL database and link DATABASE_URL.

Packaging & Deliverables

To generate the standalone submission archive:

npm run package:zip

This produces society-maintenance-tracker.zip containing all clean source code, configuration files, and documentation.

Releases

Packages

Contributors

Languages