Skip to content

Backend API for multi-tenant SaaS (Linear-style task management). NestJS, Prisma, PostgreSQL (RLS), Redis, BullMQ. Auth, RBAC, projects & tasks, Stripe billing.

Notifications You must be signed in to change notification settings

devshinthant/run-way

Repository files navigation

πŸš€ Run Way API - Building a Modern SaaS Backend

A production-ready NestJS REST API with multi-tenant architecture, enterprise-grade RBAC, and scalable infrastructure.

πŸ“– About This Project

Run Way is a comprehensive backend API designed for modern SaaS applications. Built with NestJS 11 and TypeScript, it provides a solid foundation for building multi-tenant applications with role-based access control, secure authentication, and scalable architecture patterns.

Why This Stack?

After 3+ years of full-stack development, I've learned that the best projects start with a solid foundation. This API demonstrates:

  • Enterprise patterns: Multi-tenancy, RBAC, and organization-scoped data isolation
  • Modern tooling: Prisma ORM, Redis caching, BullMQ queues, PostgreSQL RLS
  • Security first: JWT auth, rate limiting, email verification, row-level security
  • Developer experience: TypeScript, Swagger docs, Docker setup, clean architecture

Tech Stack

Core Framework

  • NestJS 11 - Progressive Node.js framework
  • TypeScript - Type-safe development
  • Prisma ORM - Modern database toolkit
  • PostgreSQL 15 - Robust relational database

Infrastructure

  • Redis - Caching & session storage
  • BullMQ - Job queue for background tasks
  • Docker - Containerization
  • Row-Level Security (RLS) - Database-level multi-tenancy

Security & Auth

  • JWT - Access & refresh tokens
  • Passport - Authentication strategies
  • Bcrypt - Password hashing
  • Helmet - Security headers
  • Rate Limiting - DDoS protection

Communication

  • Nodemailer - Email service
  • Handlebars - Email templates
  • Resend - Email delivery

Developer Experience

  • Swagger/OpenAPI - API documentation
  • ESLint - Code linting
  • Prettier - Code formatting
  • Jest - Testing framework

πŸ—οΈ Architecture Overview

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Client Applications                   β”‚
β”‚              (Web, Mobile, Desktop Apps)                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β”‚
                     β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    API Gateway Layer                      β”‚
β”‚  β€’ Authentication (JWT)                                  β”‚
β”‚  β€’ Rate Limiting                                         β”‚
β”‚  β€’ Request Validation                                    β”‚
β”‚  β€’ Organization Context                                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β”‚
                     β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                  Business Logic Layer                     β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚   Auth       β”‚  β”‚ Organizationsβ”‚  β”‚   Projects    β”‚ β”‚
β”‚  β”‚   Users      β”‚  β”‚   Roles      β”‚  β”‚   Tasks      β”‚ β”‚
β”‚  β”‚   Permissionsβ”‚  β”‚   Billing    β”‚  β”‚   Billing   β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β”‚
                     β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Data Access Layer                      β”‚
β”‚  β€’ Prisma ORM                                            β”‚
β”‚  β€’ Row-Level Security (RLS)                              β”‚
β”‚  β€’ Transaction Management                                β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β”‚
                     β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Infrastructure Layer                   β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚  PostgreSQL  β”‚  β”‚    Redis     β”‚  β”‚   BullMQ     β”‚ β”‚
β”‚  β”‚  (Database)  β”‚  β”‚   (Cache)    β”‚  β”‚   (Queue)    β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Key Architectural Decisions

  1. Multi-Tenancy via RLS

    • Database-level isolation using PostgreSQL RLS
    • Organization context enforced at query level
    • Prevents data leakage between organizations
  2. Modular Architecture

    • Feature-based modules (auth, users, organizations, etc.)
    • Clear separation of concerns
    • Easy to scale and maintain
  3. Permission-Based Access Control

    • Fine-grained permissions
    • Organization-scoped permissions
    • Dynamic role-permission assignments
  4. Queue-Based Processing

    • Async email sending via BullMQ
    • Scalable background job processing
    • Retry mechanisms for failed jobs

πŸ“‹ Current Features

βœ… Authentication & Authorization

  • User registration with email verification
  • JWT-based authentication (access + refresh tokens)
  • Password reset flow
  • Rate limiting on sensitive endpoints
  • Session management

βœ… Multi-Tenant Organizations

  • Create and manage organizations
  • Organization membership management
  • Member invitations with role assignment
  • Organization-scoped data isolation
  • Soft delete support

βœ… Role-Based Access Control (RBAC)

  • Create custom roles per organization
  • Define granular permissions
  • Assign permissions to roles
  • Assign roles to users
  • Dynamic permission checking

βœ… User Management

  • User profile management
  • User CRUD operations
  • Soft delete support
  • Email verification workflow

βœ… Email Services

  • Email verification
  • Password reset emails
  • Queue-based email processing
  • Handlebars email templates
  • Resend integration

βœ… Security Features

  • Row-Level Security (RLS) in PostgreSQL
  • Organization context guards
  • Permission-based access control
  • Request validation
  • Security headers (Helmet)
  • CORS configuration
  • CSRF protection

πŸš€ Quick Start

Prerequisites

  • Node.js (v18 or higher)
  • pnpm (or npm/yarn)
  • Docker and Docker Compose
  • PostgreSQL 15 (via Docker)
  • Redis (via Docker)

Installation

  1. Clone the repository

    git clone <repository-url>
    cd run-way
  2. Install dependencies

    pnpm install
  3. Set up environment variables

    Create a .env file in the root directory:

    # Application
    APP_NAME=Run Way
    PORT=3000
    FRONTEND_URL=http://localhost:3000
    
    # Database
    DATABASE_HOST=localhost
    DATABASE_PORT=5432
    DATABASE_USER=app_user
    DATABASE_PASSWORD=app_password
    DATABASE_NAME=mydatabase
    
    # JWT
    JWT_SECRET=your-secret-key-change-in-production
    JWT_EXPIRE_IN=3600
    JWT_REFRESH_SECRET=your-refresh-secret-key-change-in-production
    JWT_REFRESH_EXPIRE_IN=604800
    
    # Redis
    REDIS_HOST=localhost
    REDIS_PORT=6379
    
    # Email (Resend)
    RESEND_API_KEY=your-resend-api-key
    FROM_NAME=Run Way
    FROM_EMAIL=noreply@example.com
    VERIFICATION_DELAY=5000
  4. Start Docker services

    docker-compose up -d

    This starts:

    • PostgreSQL (port 5432)
    • Shadow PostgreSQL (port 5433)
    • Redis (port 6379)
    • Adminer (port 8080) - Database admin UI
  5. Run database migrations

    pnpm prisma migrate deploy
  6. Generate Prisma Client

    pnpm prisma generate
  7. Start the development server

    pnpm run start:dev

The API will be available at http://localhost:3000

Access Points


πŸ“š API Endpoints

Authentication (/auth)

Method Endpoint Description Auth Required
POST /auth/register Register a new user ❌
POST /auth/login Login user ❌
GET /auth/profile Get current user profile βœ…
POST /auth/refresh-token Refresh access token ❌
POST /auth/forget-password Request password reset ❌
POST /auth/reset-password Reset password with token ❌

Users (/users)

Method Endpoint Description Auth Required
GET /users List all users βœ…
GET /users/:id Get user by ID βœ…
POST /users/create Create a new user βœ…
DELETE /users/:id Delete user βœ…

Organizations (/organizations)

Method Endpoint Description Auth Required Permission Required
POST /organizations Create organization βœ… -
GET /organizations/:id Get organization by ID βœ… ORGANIZATIONS.READ
GET /organizations/user/organizations Get user's organizations βœ… ORGANIZATIONS.READ
DELETE /organizations/:id Delete organization βœ… ORGANIZATIONS.DELETE
POST /organizations/invite-member Invite member to organization βœ… ORGANIZATIONS.INVITE_MEMBER
GET /organizations/:id/members Get organization members βœ… ORGANIZATIONS.GET_MEMBERS

Roles (/roles)

Method Endpoint Description Auth Required Permission Required
GET /roles Get all roles βœ… ROLES.READ
POST /roles Create role βœ… ROLES.CREATE
PATCH /roles/:id Update role βœ… ROLES.UPDATE
DELETE /roles/:id Delete role βœ… ROLES.DELETE

Permissions (/permissions)

Method Endpoint Description Auth Required Permission Required
GET /permissions Get all permissions βœ… PERMISSIONS.READ
POST /permissions Create permission βœ… PERMISSIONS.CREATE
PUT /permissions/:id Update permission βœ… PERMISSIONS.UPDATE
DELETE /permissions/:id Delete permission βœ… PERMISSIONS.DELETE

Email (/email)

Method Endpoint Description Auth Required
GET /email/verify Verify email with token ❌
POST /email/resend-email-verification Resend verification email ❌

πŸ—„οΈ Database Schema

Core Models

  • User: User accounts with email verification
  • Organization: Multi-tenant organizations
  • OrganizationMember: User-organization relationships with status
  • Role: Organization-scoped roles
  • Permission: Organization-scoped permissions
  • RolePermission: Many-to-many relationship between roles and permissions
  • OrganizationMemberRole: Many-to-many relationship between members and roles

Supporting Models

  • EmailVerification: Email verification tokens
  • PasswordReset: Password reset tokens

Security

  • Row-Level Security (RLS): Database-level security for multi-tenant data isolation
  • Soft Delete: deletedAt fields on User, Organization, OrganizationMember, and Role
  • Indexes: Optimized indexes on foreign keys and frequently queried fields

πŸ” Security Features

  • βœ… Row-Level Security (RLS): Database-level security for multi-tenant data isolation
  • βœ… JWT Authentication: Secure token-based authentication with refresh tokens
  • βœ… Rate Limiting: Protection against brute force attacks
  • βœ… Email Verification: Required for account activation
  • βœ… Password Hashing: Bcrypt for secure password storage
  • βœ… Helmet: Security headers
  • βœ… CORS: Configurable cross-origin resource sharing
  • βœ… Input Validation: class-validator for request validation
  • βœ… Organization Context Guards: Ensure users can only access their organization's data
  • βœ… Permission Guards: Fine-grained access control

πŸ“¦ Available Scripts

# Development
pnpm run start:dev      # Start in watch mode
pnpm run start:debug    # Start in debug mode

# Production
pnpm run build          # Build for production
pnpm run start:prod     # Start production server

# Database
pnpm prisma migrate dev  # Create and apply migration
pnpm prisma generate    # Generate Prisma Client
pnpm prisma studio      # Open Prisma Studio

# Code Quality
pnpm run lint           # Run ESLint
pnpm run format         # Format code with Prettier

# Testing
pnpm run test           # Run unit tests
pnpm run test:e2e       # Run E2E tests
pnpm run test:cov       # Run tests with coverage

🐳 Docker Services

The docker-compose.yaml includes:

  • PostgreSQL: Main database (port 5432)
  • Shadow PostgreSQL: For Prisma migrations (port 5433)
  • Redis: Cache and queue (port 6379)
  • Adminer: Database administration UI (port 8080)

πŸ“– Learning Resources


🀝 Contributing

  1. Create a feature branch
  2. Make your changes
  3. Add tests if applicable
  4. Ensure all tests pass
  5. Submit a pull request

πŸ“„ License

UNLICENSED - Private project


Last updated: January 2025

About

Backend API for multi-tenant SaaS (Linear-style task management). NestJS, Prisma, PostgreSQL (RLS), Redis, BullMQ. Auth, RBAC, projects & tasks, Stripe billing.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published