Technology Stack Analysis¶
1. Summary¶
This document provides a comparative analysis of technology stacks, hosting solutions, and managed services for the SIS platform. The analysis is based on the current project status and priorities:
- MVP Scope: Student and teacher management, roles/permissions system
- Critical Requirement: Multitenancy architecture from day one
- Goals: Minimize administrative overhead, reduce manual intervention, faster resolution
- Deferred: External integrations, scalability optimization
2. Project Constraints & Requirements¶
2.1 Functional Requirements (MVP)¶
| Requirement | Impact on Stack |
|---|---|
| Complex relational data model (20+ entities) | Needs robust ORM with migrations |
| RBAC with 12+ roles | Framework with middleware/guard support |
| Document uploads | Object storage integration |
| i18n (Italian/English) | Framework-level i18n support |
| Audit logging | Database triggers or application-level hooks |
2.2 Non-Functional Requirements¶
| Requirement | Impact on Stack |
|---|---|
| Multitenancy | Schema-per-tenant OR row-level isolation |
| GDPR compliance | Data isolation, consent management, audit trails |
| Response time <500ms | Adequate for any modern framework |
| WCAG 2.1 AA | Frontend framework with a11y support |
2.3 Team & Budget Assumptions¶
- Small team (2-4 developers)
- Preference for managed services to reduce ops overhead
- No dedicated DevOps initially
3. Backend Framework Analysis¶
3.1 NestJS (Node.js + TypeScript)¶
Architecture Fit:
| Aspect | Assessment |
|---|---|
| RBAC | Built-in Guards and decorators (@Roles(), @Permissions()) |
| Multitenancy | Prisma supports schema-per-tenant via $extends |
| API Generation | OpenAPI/Swagger auto-generation |
| Validation | class-validator with DTOs |
| Testing | Jest integration out of box |
Pros: - Single language frontend + backend accelerates development - Prisma provides type-safe database access with excellent migration tooling - Modular architecture aligns with domain separation (students, teachers, admissions) - Large npm ecosystem for utilities - Excellent IDE support (VS Code)
Cons: - Multitenancy requires custom implementation or third-party packages - Node.js memory management needs attention for large data exports - Prisma has some limitations with complex raw queries
3.2 Django (Python)¶
Runtime: Python 3.11+
Framework: Django 5+ with Django REST Framework
ORM: Django ORM
Multitenancy: django-tenants
Architecture Fit:
| Aspect | Assessment |
|---|---|
| RBAC | django-guardian for object-level permissions |
| Multitenancy | django-tenants is production-proven |
| API Generation | drf-spectacular for OpenAPI |
| Validation | Serializers + model validation |
| Admin UI | Django Admin included |
Pros:
- Django Admin provides immediate back-office interface
- django-tenants is the most mature multitenancy solution available
- Excellent for data-heavy applications
- Built-in i18n framework
- Strong ORM for complex queries
Cons: - Two languages in stack (Python + JavaScript for frontend) - Django REST Framework adds boilerplate - Async support is newer and less mature - Deployment slightly more complex (WSGI/ASGI servers)
3.3 ASP.NET Core (C#)¶
Architecture Fit:
| Aspect | Assessment |
|---|---|
| RBAC | ASP.NET Identity + Policy-based authorization |
| Multitenancy | ABP Framework or Finbuckle.MultiTenant |
| API Generation | Swashbuckle/NSwag |
| Validation | Data annotations + FluentValidation |
| Admin UI | ABP includes admin module |
Pros: - ABP Framework includes multitenancy, audit logging, RBAC out of box - Excellent performance characteristics - Strong enterprise tooling and debugging - Entity Framework migrations are robust
Cons: - ABP has steep learning curve - Smaller web ecosystem compared to Node/Python - Team expertise requirement - Higher memory consumption
3.4 Go¶
Architecture Fit:
| Aspect | Assessment |
|---|---|
| RBAC | Casbin is powerful but requires setup |
| Multitenancy | Manual implementation required |
| API Generation | swaggo/swag |
| Validation | go-playground/validator |
Pros: - Single binary deployment - Lowest resource consumption - Casbin is a powerful policy engine - Excellent for future microservices
Cons: - Slowest development velocity for CRUD - Most multitenancy work is manual - Verbose for rapid prototyping - Smaller talent pool for web development
3.5 Backend Comparison Matrix¶
| Criterion | NestJS | Django | ASP.NET | Go |
|---|---|---|---|---|
| Dev Speed | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ |
| RBAC Maturity | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| Multitenancy | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐ |
| Complex Relations | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
| Type Safety | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| Ecosystem | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ |
| Hiring Pool | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ |
4. Database Analysis¶
5.1 PostgreSQL¶
Capabilities: - Row-level security for multitenancy - Schema-per-tenant support - JSONB for flexible custom fields - Excellent with Prisma/TypeORM/Django ORM - Free and open source
Multitenancy Strategies:
| Strategy | Pros | Cons |
|---|---|---|
| Schema-per-tenant | Strong isolation, easy backup/restore per tenant | More complex migrations, connection pooling |
| Row-level security | Single schema, simpler ops | Requires careful policy management |
| Separate databases | Maximum isolation | Highest operational overhead |
5.2 Other Databases¶
| Database | Notes |
|---|---|
| MySQL | Viable but weaker schema/RLS support |
| SQL Server | Good features but licensing costs apply |
| MongoDB | NoSQL - different paradigm from relational model |
| CockroachDB | Distributed SQL, higher complexity |
6. Managed Services & BaaS Analysis¶
6.1 Supabase¶
| Aspect | Assessment |
|---|---|
| Database | PostgreSQL with automatic backups |
| Auth | Built-in with RLS integration |
| Storage | S3-compatible for documents |
| Multitenancy | RLS-based (row-level), not schema-per-tenant |
Pros: - Fast time to market - Auth + Storage + DB in one platform - Row-level security is first-class
Cons: - RLS-based multitenancy only (not schema isolation) - Vendor lock-in concerns - Edge Functions less mature than dedicated backend
6.2 Firebase / Google Cloud¶
| Aspect | Assessment |
|---|---|
| Database | Firestore (NoSQL) or Cloud SQL (PostgreSQL) |
| Auth | Firebase Auth is mature |
| Storage | Google Cloud Storage |
| Multitenancy | Manual implementation |
Pros: - Firebase Auth is mature - Real-time capabilities built-in - Google Cloud SQL for PostgreSQL
Cons: - Firestore is NoSQL (different paradigm for relational data) - Cloud SQL + Firebase = multiple services to manage
6.3 AWS Amplify¶
| Aspect | Assessment |
|---|---|
| Database | RDS PostgreSQL or DynamoDB |
| Auth | Cognito (complex but powerful) |
| Storage | S3 |
| Multitenancy | Manual with RDS, or DynamoDB partitioning |
Pros: - Enterprise-grade infrastructure - RDS PostgreSQL is solid - S3 for document storage
Cons: - Cognito has steep learning curve - Amplify abstractions can be limiting
6.4 Neon (Serverless PostgreSQL)¶
| Aspect | Assessment |
|---|---|
| Database | PostgreSQL with branching |
| Auth | Not included |
| Storage | Not included |
| Multitenancy | Full PostgreSQL schema support |
Pros: - True PostgreSQL with all features - Database branching for dev/preview environments - Schema-per-tenant works fully - Scales to zero
Cons: - Database only - need separate auth/storage - Cold starts on free tier - Newer service
6.5 PlanetScale¶
| Aspect | Assessment |
|---|---|
| Database | MySQL (Vitess) |
| Branching | Yes, with safe migrations |
| Multitenancy | Schema-per-tenant possible |
Pros: - Excellent branching and migration workflow - Good performance
Cons: - MySQL not PostgreSQL - Foreign key constraints had limitations (now resolved)
6.6 Managed Services Comparison¶
| Service | DB Type | Auth | Storage | Multitenancy |
|---|---|---|---|---|
| Supabase | PostgreSQL | Yes | Yes | RLS-based |
| Firebase | NoSQL/SQL | Yes | Yes | Manual |
| AWS Amplify | PostgreSQL/DynamoDB | Yes | Yes | Manual |
| Neon | PostgreSQL | No | No | Schema-per-tenant |
| PlanetScale | MySQL | No | No | Schema-per-tenant |
7. Hosting & Deployment Analysis¶
7.1 Railway¶
| Aspect | Assessment |
|---|---|
| Ease of Deploy | Git push deployment |
| PostgreSQL | Managed, included |
| Scaling | Vertical + horizontal |
| Region | US, EU |
Pros: - Simple deployment experience - Managed PostgreSQL included - Preview environments per PR - Good logging and monitoring
Cons: - Smaller than major clouds - Limited regions - No built-in CDN
7.2 Render¶
| Aspect | Assessment |
|---|---|
| Ease of Deploy | Git push deployment |
| PostgreSQL | Managed, free tier available |
| Scaling | Automatic |
| Region | US, EU, Singapore |
Pros: - Free tier available for testing - PostgreSQL included - Auto-scaling available - Preview environments
Cons: - Free tier has cold starts - Less intuitive UI than Railway
7.3 Fly.io¶
| Aspect | Assessment |
|---|---|
| Ease of Deploy | Dockerfile required |
| PostgreSQL | Fly Postgres (managed) |
| Scaling | Global edge deployment |
| Region | Global (30+ regions) |
Pros: - Global edge deployment - Free tier available - Supports any Docker container
Cons: - Requires Docker knowledge - Fly Postgres is self-managed (not fully managed) - Steeper learning curve
7.4 Vercel¶
| Aspect | Assessment |
|---|---|
| Ease of Deploy | Git push, instant |
| Backend | Serverless functions only |
| Database | External only (Vercel Postgres is Neon) |
Pros: - Best-in-class for Next.js - Excellent preview deployments - Edge functions available
Cons: - Not suitable for traditional backend (NestJS, Django) - Database is external - Per-seat pricing model
7.5 Traditional Cloud (AWS/GCP/Azure)¶
| Aspect | Assessment |
|---|---|
| Flexibility | Maximum |
| Managed Services | Extensive |
| DevOps Required | Yes |
Notes: Requires dedicated DevOps expertise. Suitable for scale phase with Kubernetes.
7.6 Cloudflare Workers¶
| Aspect | Assessment |
|---|---|
| Ease of Deploy | Wrangler CLI, Git integration |
| Backend Support | JavaScript/TypeScript only (no Node.js APIs) |
| Database | D1 (SQLite), or external via HTTP |
| Region | Global edge (300+ locations) |
Critical Limitation: NestJS Incompatibility
Cloudflare Workers uses V8 isolates, not Node.js. This means:
| NestJS Dependency | Workers Support | Issue |
|---|---|---|
| Express/Fastify | No | Requires Node.js http module |
| Prisma ORM | No | Requires Node.js runtime |
| File System | No | No fs module |
| Native modules | No | No node_modules with native bindings |
Alternative Frameworks for Workers:
| Framework | Workers Compatible | Trade-offs |
|---|---|---|
| Hono | Yes | No DI, no decorators, lighter weight |
| itty-router | Yes | Minimal, no validation built-in |
| ElysiaJS | No (Bun only) | - |
Database Options on Workers:
| Database | Workers Support | Notes |
|---|---|---|
| Cloudflare D1 | Yes (native) | SQLite-based, no schema-per-tenant |
| Neon (HTTP) | Yes (via driver) | Adds latency |
| PlanetScale | Yes (HTTP driver) | MySQL, not PostgreSQL |
| Prisma Accelerate | Yes (proxy) | Adds latency |
Note: Cloudflare Workers is not compatible with NestJS and Prisma. Cloudflare services can be used for other layers (see Hybrid Architecture).
7.8 Hosting Comparison Matrix¶
| Platform | Setup Ease | PostgreSQL | Scaling | DevOps Need |
|---|---|---|---|---|
| Railway | ⭐⭐⭐⭐⭐ | Included | Good | None |
| Render | ⭐⭐⭐⭐⭐ | Included | Good | None |
| Fly.io | ⭐⭐⭐ | Included* | Excellent | Low |
| Vercel | ⭐⭐⭐⭐⭐ | External | Auto | None |
| DigitalOcean | ⭐⭐⭐⭐ | Included | Manual | Low |
| CF Workers | ⭐⭐⭐⭐ | D1 only | Excellent | Low |
| AWS/GCP/Azure | ⭐⭐ | Yes | Unlimited | High |
8. Hybrid Cloudflare Architecture¶
A hybrid architecture leverages Cloudflare's edge services while hosting the core backend elsewhere. This approach addresses Cloudflare Workers' limitations for Node.js-based backends.
8.1 Architecture Overview¶
┌─────────────────────────────────────────────────────────────────────────┐
│ CLOUDFLARE EDGE │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Cloudflare CDN │ │ Cloudflare WAF │ │ DDoS Protection │ │
│ │ (Static Assets) │ │ (Security) │ │ │ │
│ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │
│ │ │ │ │
│ ┌────────▼────────────────────▼────────────────────▼────────┐ │
│ │ Cloudflare DNS │ │
│ │ (Proxy mode enabled for API) │ │
│ └────────────────────────────┬──────────────────────────────┘ │
└───────────────────────────────┼─────────────────────────────────────────┘
│
┌───────────────────────┼───────────────────────┐
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ FRONTEND │ │ BACKEND │ │ STORAGE │
│ │ │ │ │ │
│ Cloudflare │ │ PaaS Provider │ │ Cloudflare R2 │
│ Pages │ │ (Railway, │ │ │
│ │ │ Render, etc) │ │ (S3-compat) │
│ React SPA │ │ │ │ │
│ Static build │ │ NestJS API │ │ Documents, │
│ │ │ + Prisma │ │ Uploads │
└───────────────┘ └───────┬───────┘ └───────────────┘
│
▼
┌───────────────┐
│ DATABASE │
│ │
│ PostgreSQL │
│ (Managed) │
└───────────────┘
8.4 Architecture Approaches Comparison¶
| Approach | Pros | Cons |
|---|---|---|
| Full Cloudflare (Workers + D1) | Lowest latency, simplest ops | Can't use NestJS/Prisma, limited DB |
| Hybrid Cloudflare | NestJS compatible, edge benefits | Multiple providers to manage |
| Single PaaS (Railway/Render only) | Simplest architecture | No edge caching, no CDN |
| Vercel + External API | Great DX for Next.js | Per-seat pricing, separate backend needed |
9. Authentication Services¶
9.1 Clerk¶
Pros: - Developer-friendly experience - Pre-built React components - Organizations & RBAC built-in - Free tier available (10k MAU)
Cons: - Pricing scales with users - Less control than self-hosted
9.2 Auth0¶
Pros: - Enterprise-grade - Extensive customization - RBAC and organizations
Cons: - Complex pricing structure - Can be complex for simple use cases
9.3 Self-Hosted (Passport.js / Django Auth)¶
Pros: - Full control - No per-user costs - Data stays in your DB
Cons: - Security responsibility on team - More development time
10. Stack Combinations¶
10.1 NestJS + React + Hybrid Cloudflare¶
┌─────────────────────────────────────────────────────────────────┐
│ CLOUDFLARE EDGE │
│ DNS (Proxied) + CDN + WAF + DDoS Protection │
└──────────────────────────┬──────────────────────────────────────┘
│
┌───────────────────┼───────────────────┐
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ FRONTEND │ │ BACKEND │ │ STORAGE │
│ │ │ │ │ │
│ Cloudflare │ │ NestJS + Prisma │ │ Cloudflare R2 │
│ Worker │ │ │ │ │
│ │ │ Hosted on: │ │ S3-compatible │
│ React 18 + │ │ Railway or │ │ │
│ TypeScript + │ │ Render │ │ Documents, │
│ TanStack Query │ │ │ │ Uploads │
│ + shadcn/ui │ │ │ │ │
└─────────────────┘ └────────┬────────┘ └─────────────────┘
│
▼
┌─────────────────┐
│ DATABASE │
│ │
│ PostgreSQL │
│ Schema-per- │
│ tenant │
└─────────────────┘
Components: - Frontend: Cloudflare Pages with React 18 + TypeScript + TanStack Query + shadcn/ui - Backend: NestJS + Prisma on Railway or Render - Database: PostgreSQL with schema-per-tenant multitenancy - Storage: Cloudflare R2 - Auth: Clerk (managed) or self-hosted (Passport.js + JWT) - Email: Resend or SendGrid - Edge Logic (optional): Cloudflare Workers for tenant resolution
10.2 Django Stack¶
Backend: Django 5 + DRF + django-tenants
Frontend: React or Vue.js
Database: PostgreSQL (schema-per-tenant via django-tenants)
Hosting: Railway or Render
Auth: Django built-in + django-guardian
Trade-off: Django Admin provides immediate back-office functionality but requires managing two languages (Python + JavaScript).
11. Migration Path¶
Phase 1: MVP¶
Architecture: NestJS monolith on Railway
Database: Managed PostgreSQL (Railway) with service-layer tenantId filtering
Cache/Queue: Not yet deployed (request-scoped permission memoization only)
Frontend: 2-3 MFEs on Cloudflare Workers (shell + students + teachers)
Storage: Cloudflare R2
Auth: Custom JWT (Passport.js)
Monitoring: Railway built-in logs + Sentry for error tracking
Focus: Student/teacher management, RBAC with Entity-Scope model, basic attendance, substitution workflow.
Phase 2: Growth (Months 7–12)¶
+ Redis caching layer for hot data (tenant configs, permission sets, timetables)
+ BullMQ job queues for background processing
+ Cloudflare CDN rules for API response caching (public data)
+ PostgreSQL RLS policies as defense-in-depth safety net
+ PostgreSQL read replica for reporting queries
+ Additional MFEs: attendance, admissions, communications, timetabling
+ Email integration (Resend/SendGrid) via BullMQ workers
+ Centralized log aggregation (Pino structured logging already implemented)
Focus: Full feature set, performance optimization, operational observability.
Phase 3: Scale (Months 12–24)¶
+ Dockerize NestJS (already container-ready)
+ Migrate to Kubernetes (DigitalOcean K8s or AWS EKS)
+ Split hot modules into independent services (admissions, timetabling)
+ PostgreSQL connection pooling (PgBouncer)
+ Consider moving to schema-per-tenant if isolation requirements increase
+ API gateway (Kong or AWS API Gateway) in front of services
+ CI/CD pipeline (GitHub Actions → Docker → K8s)
Decision point: If a single school grows beyond ~10,000 users or if enterprise clients require stronger data isolation, evaluate schema-per-tenant migration. The tenant_id column approach makes this migration additive (add schema routing) rather than destructive.
12. Decision Points¶
| Decision | Options | Considerations |
|---|---|---|
| Backend Framework | NestJS, Django, ASP.NET, Go | Team expertise, dev speed, multitenancy maturity |
| ORM | Prisma, Django ORM, EF Core, GORM | Type safety, migrations, query complexity |
| Frontend | React, Vue.js, Next.js | Ecosystem, learning curve, full-stack needs |
| Frontend Hosting | Cloudflare Pages, Vercel, same as backend | CDN needs, preview deploys, pricing model |
| Database | PostgreSQL, MySQL | Multitenancy support, RLS, schema features |
| Multitenancy | Schema-per-tenant, RLS, separate DBs | Isolation needs, operational complexity |
| Backend Hosting | Railway, Render, Fly.io, DO, AWS/GCP | DevOps capacity, region needs, scaling |
| Object Storage | Cloudflare R2, S3, DO Spaces | Egress costs, S3 compatibility |
| CDN/Security | Cloudflare, AWS CloudFront | WAF features, DDoS, caching needs |
| Auth | Clerk, Auth0, self-hosted | Control vs convenience, per-user costs |
Appendix: Decision Log¶
| Date | Decision | Decided By | Context |
|---|---|---|---|
| 2025-02 | NestJS over Django/Go | Team | Dev speed priority, single language |
| 2025-02 | RLS over schema-per-tenant | Team | Simpler ops for MVP, acceptable isolation |
| 2025-02 | Custom auth over Clerk/Auth0 | Team | Entity-Scope model needs full control |
| 2025-02 | MFEs over monolithic SPA | Team | Independent deploys, team scalability |
| 2025-02 | Railway over Render/Fly.io | Team | Best DX, managed PostgreSQL + Redis |
| 2025-02 | BullMQ over pg-boss | Team | More mature, Redis dual-use for caching |
| 2025-02 | Cloudflare R2 over S3 | Team | Zero egress, edge integration |
| 2026-02 | No repository layer — direct Prisma | Team | Prisma already is a typed repository; CRUD modules too simple to justify wrapping |
| 2026-02 | No domain models yet — revisit per-module | Team | No business logic to encapsulate; premature abstraction for anagraphic CRUD |
| 2026-02 | Separate docs per concern | Team | Deduplication; each doc authoritative for its concern |