This PR implements multi-tenant support for StellarEduPay, enabling multiple schools to operate independently within a single deployment. Each school maintains its own student records, fee structures, payment history, and Stellar wallet configuration.
| File | Description |
|---|---|
backend/src/models/schoolModel.js |
School model with unique identifiers and tenant configuration |
backend/src/controllers/schoolController.js |
CRUD endpoints for school management |
backend/src/middleware/schoolContext.js |
Middleware to resolve school context from request headers |
scripts/migrate-default-school.js |
Migration script for existing deployments |
| File | Changes |
|---|---|
backend/src/models/studentModel.js |
Added required schoolId field and composite indexes |
backend/src/models/paymentModel.js |
Added required schoolId field and school-scoped indexes |
backend/src/routes/schoolRoutes.js |
New school management routes |
{
schoolId: String, // Auto-generated (e.g. "SCH-3F2A")
name: String, // Human-readable name
slug: String, // URL-safe identifier (unique)
stellarAddress: String, // School's Stellar wallet
network: String, // 'testnet' | 'mainnet'
isActive: Boolean, // Soft-delete flag
adminEmail: String, // Optional admin contact
address: String, // Optional school address
createdAt: Date,
updatedAt: Date
}All tenant-scoped models now require a schoolId field:
- Students:
schoolId+studentIdcomposite unique index - Payments: All queries are school-scoped via compound indexes
Requests must include one of the following headers:
| Header | Example Value | Priority |
|---|---|---|
X-School-ID |
SCH-3F2A |
Primary |
X-School-Slug |
lincoln-high |
Secondary |
Middleware validates school existence and active status, attaching req.school and req.schoolId to downstream handlers.
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/schools |
Create new school |
GET |
/api/schools |
List all active schools |
GET |
/api/schools/:schoolSlug |
Get school details |
PATCH |
/api/schools/:schoolSlug |
Update school settings |
DELETE |
/api/schools/:schoolSlug |
Soft-delete school |
Existing single-school deployments must run the migration script before deploying:
MONGO_URI=mongodb://... SCHOOL_WALLET_ADDRESS=G... node scripts/migrate-default-school.jsThe script:
- Creates a "Default School" record with
schoolId = SCH-DEFAULT - Back-fills
schoolIdon all existing documents
- Multiple schools can be created and managed independently
- Each school has its own Stellar wallet configuration
- Schools operate on independent networks (testnet/mainnet)
- All data queries are scoped to the requesting school
- Schools cannot access other schools' data
- Existing deployments can be migrated without data loss
- Soft-delete support for school deactivation
None — The migration script ensures backward compatibility for existing deployments.
- All existing tests pass without modification
- New tests for school context middleware should be added
- Integration tests for multi-school scenarios recommended
- Closes #34: Multi-School Support Architecture
- Code follows project style guidelines
- Documentation updated in
docs/architecture.md - Migration script tested on sample data
- No console errors or warnings
- All models have proper indexes for query performance