# White-Label University Portal - Developer Guide ## ๐Ÿ“š Table of Contents 1. [Architecture Overview](#architecture-overview) 2. [Getting Started](#getting-started) 3. [API Documentation](#api-documentation) 4. [Database Schema](#database-schema) 5. [Multi-Tenant Architecture](#multi-tenant-architecture) 6. [Performance Optimization](#performance-optimization) 7. [Deployment Guide](#deployment-guide) 8. [Testing](#testing) 9. [Contributing](#contributing) 10. [Troubleshooting](#troubleshooting) --- ## ๐Ÿ—๏ธ Architecture Overview ### Technology Stack - **Frontend**: Next.js 14, React 19, TypeScript, Tailwind CSS - **Backend**: Next.js API Routes, Prisma ORM - **Database**: PostgreSQL (primary), Redis (caching) - **AI**: OpenRouter AI integration - **CDN**: Multi-provider support (AWS S3, Cloudflare, Cloudinary) - **Deployment**: Vercel, Docker, Kubernetes ### System Architecture ``` โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Frontend โ”‚ โ”‚ API Layer โ”‚ โ”‚ Database โ”‚ โ”‚ (Next.js) โ”‚โ—„โ”€โ”€โ–บโ”‚ (Next.js) โ”‚โ—„โ”€โ”€โ–บโ”‚ (PostgreSQL) โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ–ผ โ–ผ โ–ผ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ CDN Layer โ”‚ โ”‚ Cache Layer โ”‚ โ”‚ AI Services โ”‚ โ”‚ (Multi-CDN) โ”‚ โ”‚ (Redis) โ”‚ โ”‚ (OpenRouter) โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ``` ### Multi-Tenant Design The platform uses a **database-per-tenant** approach with shared application code: - **Data Isolation**: Each university's data is completely isolated - **Shared Infrastructure**: Common codebase and infrastructure - **Dynamic Configuration**: University-specific settings and branding - **Scalable Architecture**: Horizontal scaling support --- ## ๐Ÿš€ Getting Started ### Prerequisites - **Node.js**: 18.x or higher - **PostgreSQL**: 14.x or higher - **Redis**: 6.x or higher - **Git**: Latest version - **Docker**: (optional, for containerized development) ### Installation 1. **Clone the Repository** ```bash git clone https://github.com/your-org/university-portal.git cd university-portal ``` 2. **Install Dependencies** ```bash npm install ``` 3. **Environment Setup** ```bash cp .env.example .env.local # Edit .env.local with your configuration ``` 4. **Database Setup** ```bash npx prisma generate npx prisma db push npx prisma db seed ``` 5. **Start Development Server** ```bash npm run dev ``` ### Environment Variables ```env # Database DATABASE_URL="postgresql://user:password@localhost:5432/university_portal" # Redis REDIS_HOST="localhost" REDIS_PORT="6379" REDIS_PASSWORD="" REDIS_DB="0" # AI Services OPENROUTER_API_KEY="your-api-key" OPENROUTER_BASE_URL="https://openrouter.ai/api/v1" # CDN Configuration AWS_ACCESS_KEY_ID="your-access-key" AWS_SECRET_ACCESS_KEY="your-secret-key" AWS_REGION="us-east-1" AWS_S3_BUCKET="your-bucket" # Application NEXT_PUBLIC_APP_URL="http://localhost:3000" NEXTAUTH_SECRET="your-secret" NEXTAUTH_URL="http://localhost:3000" ``` --- ## ๐Ÿ“ก API Documentation ### Authentication All API endpoints require university context via headers: ```http X-University-Id: university-id X-University-Slug: university-slug ``` ### Core Endpoints #### Universities ```http GET /api/universities POST /api/universities GET /api/universities/[slug] PUT /api/universities/[slug] DELETE /api/universities/[slug] ``` #### Content Management ```http GET /api/content POST /api/content GET /api/content/[id] PUT /api/content/[id] DELETE /api/content/[id] ``` #### Programs ```http GET /api/programs POST /api/programs GET /api/programs/[id] PUT /api/programs/[id] DELETE /api/programs/[id] ``` #### Domains ```http GET /api/domains POST /api/domains GET /api/domains/[id] PUT /api/domains/[id] DELETE /api/domains/[id] POST /api/domains/[id]/validate POST /api/domains/[id]/renew-ssl ``` #### Deployments ```http GET /api/deployments POST /api/deployments GET /api/deployments/[id] POST /api/deployments/[id]/execute POST /api/deployments/[id]/rollback ``` ### Response Format All API responses follow a consistent format: ```json { "success": true, "data": { // Response data }, "message": "Operation completed successfully", "timestamp": "2025-01-01T00:00:00.000Z" } ``` ### Error Handling ```json { "success": false, "error": "Error message", "code": "ERROR_CODE", "timestamp": "2025-01-01T00:00:00.000Z" } ``` --- ## ๐Ÿ—„๏ธ Database Schema ### Core Models #### University ```prisma model University { id String @id @default(uuid()) slug String @unique name String shortName String? domain String? subdomain String? branding Json contact Json features Json ai Json status UniversityStatus @default(ACTIVE) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations assets UniversityAsset[] content UniversityContent[] programs AcademicProgram[] knowledge AIKnowledgeBase[] domains DomainConfig[] deployments DeploymentConfig[] cdnConfig CDNConfig? cdnAssets CDNAsset[] } ``` #### UniversityContent ```prisma model UniversityContent { id String @id @default(uuid()) universityId String title String content String contentType ContentType language Language @default(ENGLISH) isPublished Boolean @default(false) metadata Json? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt university University @relation(fields: [universityId], references: [id], onDelete: Cascade) } ``` #### AcademicProgram ```prisma model AcademicProgram { id String @id @default(uuid()) universityId String title String description String level ProgramLevel duration String fees Json? requirements Json? isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt university University @relation(fields: [universityId], references: [id], onDelete: Cascade) } ``` ### Domain Management #### DomainConfig ```prisma model DomainConfig { id String @id @default(uuid()) universityId String type DomainType domain String subdomain String? sslStatus SSLStatus @default(PENDING) sslExpiryDate DateTime? dnsStatus DNSStatus @default(PENDING) isActive Boolean @default(false) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt university University @relation(fields: [universityId], references: [id], onDelete: Cascade) sslConfig SSLConfig? dnsConfig DNSConfig? analytics DomainAnalytics[] } ``` ### Enums ```prisma enum UniversityStatus { ACTIVE INACTIVE SUSPENDED } enum ContentType { ABOUT NEWS EVENTS RESEARCH CAMPUS } enum Language { ENGLISH ARABIC } enum ProgramLevel { UNDERGRADUATE POSTGRADUATE PHD } enum DomainType { SUBDOMAIN CUSTOM_DOMAIN } enum SSLStatus { PENDING ACTIVE EXPIRED ERROR } ``` --- ## ๐Ÿข Multi-Tenant Architecture ### Data Isolation The platform ensures complete data isolation between universities: ```typescript // Data isolation middleware export async function validateUniversityAccess(request: NextRequest): Promise { const university = getUniversityFromHeaders(request); if (!university) { throw new Error('University context required'); } // Verify university exists and is active const dbUniversity = await prisma.university.findUnique({ where: { id: university.id, status: 'ACTIVE' }, }); if (!dbUniversity) { throw new Error('University not found or inactive'); } return university; } ``` ### University Context ```typescript // University provider for React components export function UniversityProvider({ children, initialUniversity }: UniversityProviderProps) { const [university, setUniversity] = useState(initialUniversity); // Load university data based on cookies or headers const loadUniversity = async () => { const response = await fetch('/api/universities/current'); const data = await response.json(); setUniversity(data); }; return ( {children} ); } ``` ### Dynamic Branding ```typescript // Dynamic branding component export function DynamicBranding() { const { university } = useUniversity(); if (!university) return null; const { branding } = university; return (
{university.name}

{university.name}

); } ``` --- ## โšก Performance Optimization ### Caching Strategy ```typescript // Redis caching implementation export class CacheManager { async getUniversity(slug: string): Promise { const cacheKey = `university:${slug}`; // Try cache first const cached = await this.client.get(cacheKey); if (cached) { return JSON.parse(cached); } // Query database const university = await prisma.university.findUnique({ where: { slug }, include: { assets: true, programs: true } }); // Cache result if (university) { await this.client.setEx(cacheKey, 1800, JSON.stringify(university)); } return university; } } ``` ### Query Optimization ```typescript // Optimized database queries export class QueryOptimizer { async getPrograms(universityId: string, options: any) { const { page = 1, limit = 10, search } = options; const skip = (page - 1) * limit; const where = { universityId, isActive: true, ...(search && { OR: [ { title: { contains: search, mode: 'insensitive' } }, { description: { contains: search, mode: 'insensitive' } }, ], }), }; // Parallel queries for better performance const [programs, total] = await Promise.all([ prisma.academicProgram.findMany({ where, skip, take: limit }), prisma.academicProgram.count({ where }), ]); return { programs, total, page, totalPages: Math.ceil(total / limit) }; } } ``` ### CDN Integration ```typescript // Multi-provider CDN support export class CDNManager { async uploadAsset(file: File, path: string): Promise { const config = await this.getCDNConfig(); let cdnUrl: string; switch (config.provider) { case 'AWS_S3': cdnUrl = await this.uploadToS3(file, path, config); break; case 'CLOUDFLARE': cdnUrl = await this.uploadToCloudflare(file, path, config); break; case 'CLOUDINARY': cdnUrl = await this.uploadToCloudinary(file, path, config); break; default: throw new Error('Unsupported CDN provider'); } return { originalPath: path, cdnUrl, optimizedUrls: {} }; } } ``` --- ## ๐Ÿš€ Deployment Guide ### Environment Setup 1. **Production Environment** ```bash # Set production environment variables export NODE_ENV=production export DATABASE_URL="postgresql://..." export REDIS_URL="redis://..." ``` 2. **Database Migration** ```bash npx prisma migrate deploy npx prisma generate ``` 3. **Build Application** ```bash npm run build ``` ### Docker Deployment ```dockerfile # Dockerfile FROM node:18-alpine WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY . . RUN npm run build EXPOSE 3000 CMD ["npm", "start"] ``` ```yaml # docker-compose.yml version: '3.8' services: app: build: . ports: - "3000:3000" environment: - DATABASE_URL=${DATABASE_URL} - REDIS_URL=${REDIS_URL} depends_on: - postgres - redis postgres: image: postgres:14 environment: POSTGRES_DB: university_portal POSTGRES_USER: ${DB_USER} POSTGRES_PASSWORD: ${DB_PASSWORD} redis: image: redis:6-alpine ``` ### Vercel Deployment 1. **Connect Repository** - Link your GitHub repository to Vercel - Configure environment variables 2. **Deploy** ```bash vercel --prod ``` 3. **Custom Domain** - Add custom domain in Vercel dashboard - Configure DNS records --- ## ๐Ÿงช Testing ### Unit Tests ```typescript // Example unit test import { describe, it, expect } from 'vitest'; import { CacheManager } from '../lib/cache'; describe('CacheManager', () => { it('should cache and retrieve university data', async () => { const cache = new CacheManager(config); const university = { id: '1', name: 'Test University' }; await cache.set('university:test', university); const retrieved = await cache.get('university:test'); expect(retrieved).toEqual(university); }); }); ``` ### Integration Tests ```typescript // Example integration test import { describe, it, expect } from 'vitest'; import { createMocks } from 'node-mocks-http'; import handler from '../pages/api/universities'; describe('/api/universities', () => { it('should return universities list', async () => { const { req, res } = createMocks({ method: 'GET', headers: { 'x-university-id': 'test-university' }, }); await handler(req, res); expect(res._getStatusCode()).toBe(200); expect(JSON.parse(res._getData())).toHaveProperty('data'); }); }); ``` ### Load Testing ```typescript // Example load test import { LoadTester } from '../lib/loadTesting'; const config = { name: 'API Load Test', duration: 300, users: 50, targetRPS: 10, scenarios: [ { name: 'Get Universities', weight: 100, requests: [ { method: 'GET', url: '/api/universities', expectedStatus: 200, }, ], }, ], }; const tester = new LoadTester(config); const results = await tester.run(); ``` --- ## ๐Ÿค Contributing ### Development Workflow 1. **Fork the Repository** ```bash git clone https://github.com/your-username/university-portal.git cd university-portal ``` 2. **Create Feature Branch** ```bash git checkout -b feature/your-feature-name ``` 3. **Make Changes** - Follow the coding standards - Add tests for new features - Update documentation 4. **Submit Pull Request** ```bash git push origin feature/your-feature-name # Create PR on GitHub ``` ### Coding Standards - **TypeScript**: Strict mode enabled - **ESLint**: Airbnb configuration - **Prettier**: Consistent formatting - **Conventional Commits**: Standard commit messages ### Code Review Process 1. **Automated Checks** - Linting and formatting - Type checking - Unit tests - Integration tests 2. **Manual Review** - Code quality review - Security review - Performance review 3. **Approval** - At least 2 approvals required - All checks must pass --- ## ๐Ÿ”ง Troubleshooting ### Common Issues 1. **Database Connection** ```bash # Check database connection npx prisma db push # Reset database npx prisma migrate reset ``` 2. **Redis Connection** ```bash # Check Redis connection redis-cli ping # Clear cache redis-cli flushall ``` 3. **Build Issues** ```bash # Clear Next.js cache rm -rf .next npm run build ``` ### Debug Mode ```bash # Enable debug logging DEBUG=* npm run dev # Database queries DEBUG=prisma:query npm run dev # Redis operations DEBUG=redis npm run dev ``` ### Performance Monitoring ```typescript // Monitor query performance const queryOptimizer = getQueryOptimizer(); const stats = queryOptimizer.getQueryStats(); console.log('Query Statistics:', stats); // Monitor cache performance const cache = getCacheInstance(); const cacheStats = await cache.getStats(); console.log('Cache Statistics:', cacheStats); ``` --- ## ๐Ÿ“ž Support ### Getting Help - **Documentation**: This developer guide - **Issues**: GitHub Issues - **Discussions**: GitHub Discussions - **Email**: dev-support@your-domain.com ### Resources - **API Reference**: `/api/docs` - **Database Schema**: `prisma/schema.prisma` - **Component Library**: Storybook documentation - **Performance Dashboard**: `/admin/performance` --- **Last Updated**: January 2025 **Version**: 1.0 **Platform**: White-Label University Portal