Initializing
Back to Projects
Year2025
DomainFullstack
AccessOpen Source
Complexity9.3 / 10
Live Link
Next.jsNestJSTypeScriptPostgreSQLPrismaRedisMinIOJWTRadix UIFramer MotionDockerMulti-TenancyRazorpayAI/ML
FullstackProduction

PMS — Multi-Tenant Portfolio Management Platform

Comprehensive SaaS platform for portfolio building, course management, e-commerce, bookings, and AI-powered divination services with multi-tenancy and custom domain support.

Core Modules0+
API Endpoints0+
Database Models0+
User Roles0

Table of Contents


The Challenge

Building a comprehensive platform that enables users to create and manage personal portfolios, sell products and services, conduct online courses, handle appointment bookings, and access AI-powered divination services — all within a single unified system with multi-tenant isolation and custom domain support.

The Portfolio Management System (PMS) addresses the need for professionals, businesses, and content creators to have a comprehensive online presence without managing multiple disconnected platforms. Users can build their portfolio, sell digital/physical products, offer services with booking capabilities, and deliver online courses — all from one administration interface.

The requirement: Create a production-grade multi-tenant SaaS platform with portfolio builder, e-commerce capabilities, course management system (LMS), appointment scheduling, payment processing, and AI-powered services for numerology, astrology, and Lo Shu grid analysis.


Architecture & Solution

The system follows a modern monorepo architecture with separate frontend and backend applications:

Parsing system architecture diagram...

Project Structure

code
PMS/
├── apps/
│   ├── backend/         # NestJS API (Port 3001)
│   │   └── src/
│   │       ├── auth/    # JWT, 2FA, Roles
│   │       ├── tenant/  # Multi-tenancy
│   │       ├── user/   # User management
│   │       ├── portfolio/
│   │       ├── course/  # LMS
│   │       ├── product/
│   │       ├── service/
│   │       ├── booking/
│   │       ├── payment/ # Razorpay
│   │       └── ai/     # AI services
│   └── frontend/       # Next.js 16 (Port 3000)
│       ├── app/
│       │   ├── (auth)/  # Login, Register
│       │   ├── (dashboard)/ # Main app
│       │   ├── (admin)/ # Admin panel
│       │   ├── learn/   # Course player
│       │   ├── p/       # Public portfolio
│       │   └── developer/ # Developer tools
│       └── components/
├── docker-compose.yml
└── scripts/             # Deployment & utilities

Tech Stack

LayerTechnologyVersion
FrontendNext.js16.x
UI LibraryReact19.x
ComponentsRadix UIlatest
StylingTailwind CSS4.x
AnimationFramer Motion12.x
ChartsRecharts3.x
BackendNestJS11.x
DatabasePostgreSQL16
ORMPrisma5.x
CachingRedis7.x
StorageMinIOlatest
AuthJWT + Passport
PaymentRazorpay2.x
ContainerDocker Compose

Key Engineering Decisions

1. Multi-Tenant Architecture with Data Isolation

The platform implements logical multi-tenancy with tenant-scoped data access:

typescript
// backend/src/common/guards/tenant.guard.ts
@Injectable()
export class TenantGuard implements CanActivate {
  async canActivate(context: ExecutionContext): Promise<boolean> {
    const request = context.switchToHttp().getRequest();
    const user = request.user;
    
    if (!user?.tenantId) {
      throw new UnauthorizedException('Tenant context required');
    }
    
    // Attach tenant ID to request for downstream use
    request.tenantId = user.tenantId;
    
    return true;
  }
}

// Prisma query with tenant scope
const products = await prisma.product.findMany({
  where: {
    tenantId: request.tenantId,
    ...filters
  }
});

2. JWT Authentication with Refresh Tokens

Secure authentication with access and refresh token rotation:

typescript
// auth.service.ts
async generateTokens(user: User) {
  const payload = { 
    sub: user.id, 
    email: user.email, 
    role: user.role,
    tenantId: user.tenantId 
  };
  
  const accessToken = this.jwtService.sign(payload, {
    expiresIn: '15m',
    secret: process.env.JWT_SECRET
  });
  
  const refreshToken = this.jwtService.sign(payload, {
    expiresIn: '7d',
    secret: process.env.JWT_REFRESH_SECRET
  });
  
  // Store refresh token hash for verification
  await this.redis.set(`refresh:${user.id}`, 
    await bcrypt.hash(refreshToken, 10), 
    60 * 60 * 24 * 7
  );
  
  return { accessToken, refreshToken };
}

3. Course Progress Tracking with Granular Completion

The LMS tracks lesson completion at the most granular level:

typescript
// course.service.ts
async markLessonComplete(userId: string, lessonId: string) {
  const progress = await prisma.courseProgress.create({
    data: {
      userId,
      lessonId,
      completedAt: new Date(),
    }
  });
  
  // Check if module is complete
  const moduleLessons = await prisma.lesson.findMany({
    where: { moduleId: progress.lesson.moduleId }
  });
  
  const completedCount = await prisma.courseProgress.count({
    where: {
      userId,
      lesson: { moduleId: progress.lesson.moduleId }
    }
  });
  
  if (completedCount === moduleLessons.length) {
    await this.completeModule(userId, progress.lesson.moduleId);
  }
  
  return progress;
}

4. AI-Powered Divination Services

The platform integrates multiple AI services for divination:

typescript
// ai/loshu.service.ts
async function calculateLoShuGrid(dob: string): Promise<LoShuResult> {
  const digits = extractDigits(dob);
  const grid = buildLoShuGrid(digits);
  
  // Calculate career line (sum of specific cells)
  const career = grid[0] + grid[2] + grid[4] + grid[6] + grid[8];
  const health = grid[2] + grid[4] + grid[6];
  const emotions = grid[1] + grid[3] + grid[5] + grid[7];
  
  // Identify missing numbers
  const missing = findMissingNumbers(grid);
  
  // Generate personality insights
  const personality = generatePersonalityInsight(grid, missing);
  
  return {
    grid,
    career,
    health,
    emotions,
    missing,
    personality,
    favorableNumbers: findFavorableNumbers(grid),
    unfavorableNumbers: findUnfavorableNumbers(grid),
  };
}

5. Payment Integration with Razorpay

Complete payment flow with webhook handling:

typescript
// payment.service.ts
async function createOrder(amount: number, currency: string = 'INR') {
  const razorpay = new Razorpay({
    key_id: process.env.RAZORPAY_KEY_ID,
    key_secret: process.env.RAZORPAY_KEY_SECRET,
  });
  
  const order = await razorpay.orders.create({
    amount: amount * 100, // Convert to paise
    currency,
    receipt: `order_${Date.now()}`,
    payment_capture: 1,
  });
  
  return order;
}

async function verifyWebhook(payload: string, signature: string) {
  const expected = crypto
    .createHmac('sha256', process.env.RAZORPAY_WEBHOOK_SECRET)
    .update(payload)
    .digest('hex');
  
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

Core Modules

Authentication & Authorization

FeatureImplementation
JWT Access Tokens15-minute expiration
Refresh Tokens7-day rotation with hash storage
2FATOTP with QR code setup
RolesDEVELOPER, ADMIN, USER, GUEST
Password ResetEmail-based with tokens

User Management

FeatureDescription
Profile ManagementAvatar, bio, social links
Role AssignmentHierarchical access control
User InvitationEmail-based tenant onboarding
Session ManagementActive sessions listing and revocation

Portfolio Builder

FeatureDescription
Custom SlugPublic URL like p/username
Theme SelectionMultiple portfolio themes
Section BuilderDrag-and-drop section ordering
AnalyticsVisitor tracking
Custom DomainsMap own domain to portfolio

AI Integration

Lo Shu Grid Analysis

The Lo Shu magic square analysis calculates personality traits based on birth date:

typescript
// Lo Shu Grid Structure
{
  4: 9: 2
  3: 5: 7
  8: 1: 6
  
  // Positions: Career, Friends, Family, etc.
  // Missing numbers indicate weaknesses
  // Repeated numbers indicate strengths
}

Vedic Numerology

Core numbers calculated from birth date and name:

NumberSignificance
Life Path NumberOverall life journey
Destiny NumberLife purpose
Soul NumberInner desires
Personality NumberExternal expression
Lucky NumberFavorable numbers

Astrology Integration

Birth chart calculation with planetary positions:

  • Moon Sign (Rashi)
  • Ascendant (Lagna)
  • Nakshatra (Birth Star)
  • Dasha periods (Antardasha, Mahadasha)

E-Commerce Features

Products Module

FeatureDescription
Product TypesPhysical, Digital, Service
Inventory TrackingStock levels with alerts
VariantsSize, color, etc.
PricingBase price, sale price, compare price
Digital DownloadsPresigned URL generation

Services Module

FeatureDescription
Service TypesOne-time, Recurring
DurationTime-based pricing
AvailabilityCalendar-based slots
PricingHourly, session-based

Booking System

FeatureDescription
Calendar ViewInteractive slot selection
Time ZonesUTC conversion for global clients
Buffer TimeGap between appointments
CancellationConfigurable policies
RemindersEmail/SMS notifications

LMS Platform

Course Structure

code
Course
├── Modules
│   ├── Lessons
│   │   ├── Video Content
│   │   ├── Text/Markdown
│   │   ├── Quiz
│   │   └── Discussion
│   └── Module Quiz
└── Final Assessment

Features

FeatureDescription
Video HostingMinIO S3 storage with streaming
Progress TrackingGranular lesson completion
QuizzesMultiple choice, true/false
CertificatesAuto-generated PDF on completion
DiscussionsPer-lesson Q&A threads
Drip ContentScheduled content release

Certificate Generation

typescript
// certificate.service.ts
async function generateCertificate(userId: string, courseId: string) {
  const course = await prisma.course.findUnique({ where: { id: courseId }});
  const user = await prisma.user.findUnique({ where: { id: userId }});
  
  // Calculate completion percentage
  const progress = await this.getCourseProgress(userId, courseId);
  
  if (progress < 100) {
    throw new BadRequestException('Course not completed');
  }
  
  // Generate PDF certificate
  const pdf = await this.pdfGenerator.generate({
    userName: user.name,
    courseName: course.title,
    completionDate: new Date(),
    certificateId: `CERT-${Date.now()}`,
  });
  
  return pdf;
}

Multi-Tenancy

Domain Management

FeatureDescription
Subdomains{tenant}.aatmanova.in
Custom Domainsshop.example.com
SSLAuto-provisioned via Let's Encrypt
Tenant IsolationLogical data separation by tenantId

Developer Dashboard

The DEVELOPER role has access to platform-wide controls:

  • Tenant management
  • User management across tenants
  • System-wide audit logs
  • Platform analytics
  • Feature flags
  • System configuration

Deployment

Local Development

bash
# Start infrastructure
docker compose up -d

# Run migrations
npm run prisma:migrate

# Seed system
npm run seed

# Start apps
npm run dev

Services

ServicePortDescription
PostgreSQL5433Primary database
Redis6379Cache & sessions
MinIO9001File storage
MailHog8025Email testing
Frontend3000Next.js app
Backend3001NestJS API

Production Deployment

The project supports deployment via custom scripts:

bash
# Deploy to production
./scripts/full_deploy.ps1

Roadmap

  • Phase 1 — Core Platform (Complete) - Auth, Tenant, User management
  • Phase 2 — Portfolio Builder (Complete) - Public profiles, custom domains
  • Phase 3 — E-Commerce (Complete) - Products, Services, Bookings
  • Phase 4 — LMS Platform (Complete) - Courses, Progress, Certificates
  • Phase 5 — AI Services (Complete) - Lo Shu, Numerology, Astrology
  • Phase 6 — Payments (Complete) - Razorpay integration
  • Phase 7 — Multi-Tenancy (Complete) - Custom domains, tenant isolation
  • Phase 8 — Advanced Analytics (In Progress) - Platform-wide insights
  • Phase 9 — Mobile Apps (Planned) - iOS/Android companions
  • Phase 10 — White-label (Planned) - Full branding customization

Conclusion

The Portfolio Management System (PMS) represents a comprehensive multi-tenant SaaS platform that consolidates portfolio building, e-commerce, course management, and AI-powered divination services into a single unified system. The platform enables users to establish their online presence without managing multiple disconnected tools.

The production-ready architecture with NestJS backend, Next.js frontend, PostgreSQL database, Redis caching, and MinIO storage provides enterprise-grade performance and reliability. The multi-tenant design with custom domain support enables the platform to serve multiple organizations from a single deployment while maintaining data isolation and security.

AI integration for Lo Shu grid analysis, Vedic numerology, and astrology adds unique value propositions that differentiate this platform from generic portfolio builders. The comprehensive LMS with progress tracking, quizzes, and certificate generation enables professional course delivery, while the e-commerce modules support both physical and digital product sales with integrated booking capabilities.

Architecture Feedback

Spotted a potential optimization or antipattern? Let me know.

Submit a Technical Suggestion