Table of Contents
The Challenge
The digital landscape for spiritual services, astrological consultations, and reiki sessions is dominated by outdated web platforms with clunky booking interfaces, lack of real-time scheduling, and zero personalization. To address this, the AATMANOVA Digital Platform was conceived as a high-performance spiritual SaaS. The core problem was designing a system capable of handling complex numerology calculations, dynamic booking slots for therapists/consultants, and providing secure, fast, and personalized spiritual readings powered by AI.
A key technical requirement was preparing the system to scale from a robust modular monolith into a microservices-ready setup. To achieve this, the architecture had to enforce strict domain boundaries between bookings, user accounts, and numerology computation engines, ensuring zero circular imports and complete developer velocity.
The requirement: Build a scalable, developer-friendly modular spiritual SaaS with highly reliable booking management, high-performance Vedic numerology calculation engines, and a unified TypeScript developer experience across a NestJS backend and Vite frontend.
Architecture & Solution
AATMANOVA is designed around a strictly structured modular monolith using NestJS on the backend and Vite+React on the frontend. The backend acts as a secure, typed Gateway coordinating astrological modules, user sessions, and calendar updates.
Modular Monolith Breakdown
| Layer | Components | Role |
|---|---|---|
| Vite Presentation | React 18 SPA + CSS Modules | Highly responsive user portal and therapist administration interface. |
| Modular Core | NestJS Domain Modules | Domain boundaries ensuring strict feature isolation (Auth, Booking, Calculators). |
| Persistance & Cache | Prisma + PostgreSQL + Redis | Atomic transaction logs for session booking and cached astronomical values. |
Tech Stack
| Layer | Technology | Role |
|---|---|---|
| Backend Framework | NestJS 10 | Enterprise-grade modular monolith orchestration and dependency injection. |
| Frontend Framework | React 18 | Client-side reactive interface with pure, customized interactive layouts. |
| Bundler | Vite 5 | Ultra-fast client builds and development hot module replacement. |
| Database | PostgreSQL 16 | Relational database handling user accounts, bookings, and audit records. |
| ORM | Prisma ORM | Strictly typed database access and migration mapping. |
| Caching Layer | Redis | Ephemeral session locks for slot bookings and calculated numerology caches. |
| Validation | Zod | Strictly typed runtime schema assertion. |
| Containerization | Docker | Consistent environment mapping for local infrastructure services. |
Key Engineering Decisions
1. Modular Monolith Architecture with NestJS
To satisfy the deletion test and maintain long-term maintainability, the backend uses NestJS modules to completely decouple domain logic. This prepares the codebase for eventual microservices separation.
// src/numerology/numerology.module.ts
import { Module } from '@nestjs/common';
import { NumerologyController } from './numerology.controller';
import { NumerologyService } from './numerology.service';
import { NumerologyPolicy } from './numerology.policy';
@Module({
imports: [],
controllers: [NumerologyController],
providers: [NumerologyService, NumerologyPolicy],
exports: [NumerologyService],
})
export class NumerologyModule {}2. Vedic Numerology Calculation Engine
Vedic Numerology requires deterministic computations based on birth dates and names. We encapsulated these calculation algorithms inside pure policies with zero side effects, allowing for complete testability.
// src/numerology/numerology.policy.ts
export class NumerologyPolicy {
calculateDestinyNumber(birthDate: Date): number {
const digits = birthDate.toISOString().split('T')[0].replace(/-/g, '');
return this.reduceToSingleDigit(digits);
}
private reduceToSingleDigit(numStr: string): number {
let sum = numStr.split('').reduce((acc, val) => acc + parseInt(val, 10), 0);
while (sum > 9 && sum !== 11 && sum !== 22) { // 11 & 22 are master numbers
sum = sum.toString().split('').reduce((acc, val) => acc + parseInt(val, 10), 0);
}
return sum;
}
}3. Concurrency-Safe Slot Booking Locks
Spiritual consultants have strict, non-overlapping schedules. To avoid double-booking slots under high concurrent request volume, we implemented a lightweight distributed lock using Redis before committing the transaction to PostgreSQL.
// src/bookings/bookings.service.ts
import { Injectable, ConflictException } from '@nestjs/common';
import { RedisService } from '../infrastructure/redis.service';
@Injectable()
export class BookingsService {
constructor(private readonly redis: RedisService) {}
async acquireBookingLock(slotId: string, durationSec = 10): Promise<boolean> {
const lockKey = `lock:slot:${slotId}`;
const acquired = await this.redis.setNX(lockKey, 'locked', durationSec);
if (!acquired) {
throw new ConflictException('This consultation slot is currently being booked.');
}
return true;
}
}4. Zero-Leak Environment Configurations
Environment parameters are isolated inside a dedicated config parser. This fails the server immediately at startup if any required parameter is missing or misconfigured.
// src/config/env.validation.ts
import { z } from 'zod';
export const envSchema = z.object({
DATABASE_URL: z.string().url(),
REDIS_URL: z.string().url(),
PORT: z.coerce.number().default(4000),
JWT_SECRET: z.string().min(32),
});
export function validateEnv(config: Record<string, any>) {
const result = envSchema.safeParse(config);
if (!result.success) {
throw new Error(`Invalid environment setup: ${JSON.stringify(result.error.format())}`);
}
return result.data;
}Deployment
Quick Start
Launch local infrastructure services:
# Spin up PostgreSQL and Redis
docker compose up -d postgres redis
# Run schema migrations and seed local DB
npx prisma migrate dev --name init
npm run seed
# Run the NestJS development API
npm run start:devService Map
| Service | Technology | Port / Access |
|---|---|---|
| Core API Gateway | NestJS | PORT_API (4000) |
| Admin dashboard | Vite SPA | PORT_ADMIN (3001) |
| Relational Database | PostgreSQL | PORT_DB (5416) |
| Cache Store | Redis | PORT_REDIS (6382) |
Architecture Feedback
Spotted a potential optimization or antipattern? Let me know.