Skip to content

Kv-Logics/agflow-saas

Repository files navigation

⚡ AgFlow

Elite Multi-Tenant Task Management System

Built for CDI Software Engineering Internship 2026

Demo Video Live Demo TypeScript Node.js React


📌 What is AgFlow?

AgFlow Dashboard — Kanban Board with Sprint Burndown

Main workspace — Kanban board, sprint burndown chart, and real-time task stats

AgFlow is a production-grade, full-stack multi-tenant task management platform built to demonstrate proficiency in scalable web applications, RESTful API design, and relational database architecture.

Multiple organisations (tenants) can use the application simultaneously with complete data isolation — Tenant A can never access Tenant B's data, enforced at the database query level via middleware on every single request.


🎯 Why AgFlow?

Every feature in this project maps directly to a skill from the CDI Software Engineering Intern role — not as a checklist exercise, but as a working, deployed system:

Requirement How AgFlow demonstrates it
Full-Stack Development React 19 frontend + Node.js/Express backend
Relational Databases PostgreSQL schema via Prisma ORM with foreign-key constraints and indexed queries
Authentication Systems JWT auth with Bcrypt hashing + automated temporary password generation via email
Performance Optimisation Optimistic UI on the Kanban board — zero-latency drag interactions
Cloud & Docker Containerised with Docker Compose locally, live API deployed to cloud
System Design Logical data isolation, RBAC middleware, role promotion approval workflow

🚀 Live Demo

URL: https://agflow-saas.vercel.app

Demo Video: Watch on Google Drive

Demo Credentials (pre-seeded):

Tenant Role Email Password
Acme Corp Super Admin admin@acme.com password123
Acme Corp Developer dev@acme.com password123
Globex Inc Super Admin admin@globex.com password123

Isolation demo: Log in as admin@acme.com and admin@globex.com in two separate incognito windows simultaneously. Every task, project, and audit entry is completely invisible across tenants.


🏗️ Architecture Overview

┌─────────────────────────────────────────────────────┐
│                   React Frontend                    │
│         (Vite + Tailwind 4 + Framer Motion)         │
└────────────────────┬────────────────────────────────┘
                     │ HTTP / REST
┌────────────────────▼────────────────────────────────┐
│              Express.js API Gateway                 │
│    JWT Auth → Tenant Resolver → Role Check          │
│                  (Middleware Chain)                 │
└──────┬───────────────┬───────────────┬──────────────┘
       │               │               │
┌──────▼──────┐ ┌──────▼──────┐ ┌─────▼───────┐
│ Auth Service│ │ Task Service│ │  Analytics  │
│ JWT + Bcrypt│ │ CRUD + Audit│ │  Burndown   │
│ Nodemailer  │ │ Optimistic  │ │  Dashboard  │
└──────┬──────┘ └──────┬──────┘ └─────┬───────┘
       │               │               │
┌──────▼───────────────▼───────────────▼──────────────┐
│                PostgreSQL Database                  │
│         Row-level tenantId isolation                │
│              Prisma ORM + Migrations                │
└─────────────────────────────────────────────────────┘

🔐 Multi-Tenancy: How Data Isolation Works

Every table in the database has a tenantId column. When a user logs in, their tenantId is embedded in the JWT payload. Every API request passes through a middleware chain that:

  1. Verifies the JWT signature
  2. Extracts tenantId from the token
  3. Attaches it to req.user.tenantId
  4. Forces every Prisma query to scope to where: { tenantId: req.user.tenantId }

It is architecturally impossible for a user to access another tenant's data — even if they know a resource ID belonging to a different organisation.


👥 RBAC — Role-Based Access Control

Three roles with distinct permissions, enforced at the middleware layer before requests ever reach a controller:

Permission SUPER_ADMIN PROJECT_MANAGER DEVELOPER
Create / Delete Projects
Invite Team Members
Create Tasks
Assign Tasks
Update Task Status
Add Comments
Request Role Promotion
Approve / Reject Promotions
View Audit Log
View Sprint Analytics

✨ Features

🏛️ Core (Internship Requirements)

Feature Details
🏢 Multi-tenant Architecture Complete data isolation via JWT-scoped tenantId on every query
🔐 RBAC Three roles — SUPER_ADMIN, PROJECT_MANAGER, DEVELOPER — enforced by middleware
Task Management Create, assign, update, delete — with priorities (HIGH / MEDIUM / LOW) and status tracking
📁 Project Management Organise tasks into projects, each scoped to a tenant

🧠 Advanced System Design Features

These features go beyond the internship brief and demonstrate production-level engineering thinking.


🔁 Role Promotion Workflow

DEVELOPER  ──► requests promotion ──►  SUPER_ADMIN (email alert)
                                              │
                                    ┌─────────▼──────────┐
                                    │  Approve / Reject  │
                                    └─────────┬──────────┘
                                              │
                               JWT permissions updated dynamically
  • Developer submits a promotion request from their dashboard
  • Super Admin receives an automated email notification via Nodemailer
  • Admin approves or rejects with one click — role and JWT payload update instantly
  • No manual database edits required
Pending Approvals — Super Admin view

Developer's view — promotion request submitted and waiting for Super Admin approval

Role Permissions panel close-up

Super Admin's view — same requests now showing Approve / Reject action buttons

Promotion Approval email to Super Admin

Real email alert sent to Super Admin via Nodemailer — triggered when a Developer requests PROJECT_MANAGER promotion


👥 Team Management

Team Management — Super Admin view

Super Admin view — manage member roles in real time with inline role dropdowns

Team Management — Developer view

Developer view — same page, different permissions. Role dropdowns hidden, promotion request shows "Waiting for Approval"


Automated Member Onboarding

Admin clicks "Invite User"
       │
       ▼
Backend generates secure 8-char random password
       │
       ▼
Bcrypt hashes it → stored in DB
       │
       ▼
Nodemailer (SMTP) emails plain-text credentials to invitee
       │
       ▼
User logs in → prompted to change password
Automated welcome email with temporary credentials

Real email received in Gmail — auto-generated temporary password delivered via Nodemailer SMTP


📜 Immutable Audit Trail

Every mutation in the workspace writes a permanent, append-only record:

Field Example Value
actor user_abc123
action TASK_STATUS_CHANGED
entityType Task
entityId task_xyz789
timestamp 2026-04-24T10:32:00Z
Supervisor Dashboard

Supervisor Dashboard — real-time activity monitoring with sprint pace and status

Detailed Activity Trail

Detailed Activity Trail — immutable logs showing actor, event type, and state transitions


⚡ Optimistic UI on Kanban Board

User drags card          React state updates instantly (0ms delay)
      │                         │
      │                         ▼
      │                  UI shows new position
      │
      ▼
PATCH /api/tasks/:id  (async, background)
      │
      ├── Success → nothing changes, already correct
      └── Failure → card snaps back to original column
  • Built with @dnd-kit for accessible, performant drag interactions
  • Perceived latency = zero — no waiting for network
  • Graceful rollback on API failure keeps data consistent

🎨 Frontend

Feature Details
🗂️ Kanban Board Drag-and-drop columns (To DoIn ProgressDone) via @dnd-kit
📉 Sprint Burndown Chart Chart.js — plots ideal vs actual task completion velocity
🔀 List / Kanban Toggle Switch views without losing state
🎯 Priority Filters Filter tasks by HIGH, MEDIUM, LOW instantly
🌙 Glassmorphism Dark UI Tailwind CSS 4 + Framer Motion — smooth, premium transitions
📱 Fully Responsive Optimised for desktop and mobile screen sizes

🔒 Backend & Security

Feature Details
🔑 JWT Authentication Stateless sessions — tenantId + role embedded in token payload
🔐 Bcrypt Password Hashing Industry-standard hashing with configurable salt rounds
📨 Nodemailer SMTP Transactional emails for invites and role-change alerts
🛡️ Input Validation All POST / PATCH routes validated before touching controllers
🚨 Global Error Handler Consistent { success, message, code } shape across all errors
🚦 Rate Limiting express-rate-limit on auth routes — blocks brute force attacks

🐳 DevOps & Deployment

Feature Details
🐳 Docker Compose docker compose up — spins up app + database in one command
🏭 Production Config Separate docker-compose.prod.yml for production deployments
☁️ Live Deployment Frontend live at agflow-saas.vercel.app

🗄️ Database Schema (ERD)

┌──────────────┐       ┌──────────────┐       ┌──────────────┐
│   Tenants    │       │    Users     │       │   Projects   │
├──────────────┤       ├──────────────┤       ├──────────────┤
│ id (PK)      │──┐    │ id (PK)      │   ┌───│ id (PK)      │
│ name         │  │    │ tenantId(FK) │───┘   │ tenantId(FK) │
│ slug         │  └────│ email        │       │ name         │
│ createdAt    │       │ passwordHash │       │ description  │
└──────────────┘       │ role         │       │ createdAt    │
                       │ createdAt    │       └──────┬───────┘
                       └──────┬───────┘              │
                              │                ┌──────▼───────┐
                              │                │    Tasks     │
                       ┌──────▼───────┐        ├──────────────┤
                       │  AuditLogs   │        │ id (PK)      │
                       ├──────────────┤        │ tenantId(FK) │
                       │ id (PK)      │        │ projectId(FK)│
                       │ tenantId(FK) │        │ assigneeId   │
                       │ actorId (FK) │        │ title        │
                       │ action       │        │ status       │
                       │ entityType   │        │ priority     │
                       │ entityId     │        │ createdAt    │
                       │ timestamp    │        └──────┬───────┘
                       └──────────────┘               │
                                               ┌──────▼───────┐
                                               │   Comments   │
                                               ├──────────────┤
                                               │ id (PK)      │
                                               │ taskId (FK)  │
                                               │ authorId(FK) │
                                               │ content      │
                                               │ createdAt    │
                                               └──────────────┘

🛠️ Tech Stack

Layer Technology
Frontend React 19, Vite, TypeScript
Styling Tailwind CSS 4, Framer Motion
Charts Chart.js
Drag & Drop @dnd-kit
Backend Node.js, Express.js
ORM Prisma
Database PostgreSQL (prod) / SQLite (local dev)
Auth JWT + Bcrypt
Email Nodemailer (SMTP)
Deployment Vercel (frontend)
DevOps Docker, Docker Compose

🏃 Running Locally

Option 1 — Docker (recommended, one command)

git clone https://github.com/Kv-Logics/agflow-saas.git
cd agflow-saas
cp server/.env.example server/.env
docker compose up

App runs at http://localhost:5173

Option 2 — Manual setup

Backend:

cd server
npm install
cp .env.example .env
# Fill in your PostgreSQL connection string and SMTP credentials in .env
npx prisma migrate dev
npm run seed
npm run dev

Frontend:

cd client
npm install
npm run dev

🌱 Seed Data

Running npm run seed in the server directory creates:

  • 2 tenants: Acme Corp and Globex Inc
  • 4 users across both tenants covering all 3 roles
  • Sample projects and tasks in various statuses (To Do, In Progress, Done)
  • Ready-to-run data for the isolation proof demo

🔌 API Endpoints

Auth

Method URL Min Role Description
POST /api/auth/register Public Create new tenant + admin user
POST /api/auth/login Public Login, receive JWT
POST /api/auth/invite SUPER_ADMIN Generate temp password and email new user

Roles & Approvals

Method URL Min Role Description
POST /api/auth/role/:id DEVELOPER Request role promotion to Project Manager
POST /api/approvals/:id/resolve SUPER_ADMIN Approve or reject a promotion request

Tasks

Method URL Min Role Description
GET /api/tasks DEVELOPER List all tasks for the tenant
POST /api/tasks PROJECT_MANAGER Create a new task
PATCH /api/tasks/:id DEVELOPER Update task status (supports optimistic UI)
DELETE /api/tasks/:id SUPER_ADMIN Delete a task

Projects

Method URL Min Role Description
GET /api/projects DEVELOPER List all projects for the tenant
POST /api/projects SUPER_ADMIN Create a new project

Admin

Method URL Min Role Description
GET /api/tasks/history/audit SUPER_ADMIN Fetch the immutable audit log
PATCH /api/users/:id/role SUPER_ADMIN Directly update a user's role

💡 Design Decisions

Why tenantId over schema-per-tenant? Schema-per-tenant provides the strongest isolation but requires a dynamic migration job every time a new organisation registers, significantly increasing operational complexity. For this scale, tenantId with strict middleware enforcement delivers the same security guarantee with far simpler infrastructure. The codebase is structured so PostgreSQL Row-Level Security (RLS) can be added as a second isolation layer for enterprise deployments.

Why Prisma over raw SQL? Type safety from schema definition through to query execution means a tenant isolation error — such as a missing tenantId filter — surfaces as a compile-time error rather than a live data leak. Automated migration history also keeps schema changes version-controlled alongside application code.

Why JWT over server-side sessions? Stateless authentication means the API can scale horizontally without a shared session store. Embedding tenantId and role directly in the token payload makes every request self-contained and eliminates an extra database lookup per request.

Scaling path: Application-level tenantId filtering → PostgreSQL Row-Level Security as a database-layer guarantee → Redis token caching to reduce auth overhead → schema-per-tenant for enterprise customers requiring strict DB-level isolation.


📁 Project Structure

agflow-saas/
├── client/                    # React frontend
│   ├── src/
│   │   ├── components/        # Reusable UI components
│   │   ├── pages/             # Route-level page components
│   │   ├── hooks/             # Custom React hooks
│   │   └── lib/               # API client, utilities
├── server/                    # Express backend
│   ├── src/
│   │   ├── routes/            # Express route definitions
│   │   ├── controllers/       # Request handlers
│   │   ├── services/          # Business logic
│   │   ├── middleware/        # Auth, tenant resolver, RBAC checks
│   │   └── prisma/            # Schema and migrations
├── docker-compose.yml         # Local dev stack
├── docker-compose.prod.yml    # Production stack
└── project_summary.txt        # Project overview

Built with ⚡ for the CDI Software Engineering Internship 2026

Live Demo · Repository

About

Enterprise-grade project and task management system enabling multiple organizations to securely manage teams, projects, approvals, and sprint workflows with complete data isolation and role-based access control.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors