We follow a Clean Architecture approach with clear separation of concerns:
┌─────────────────────────────────────────────────────────────┐
│ Presentation Layer │
│ (React Components, Pages, UI State Management with Zustand)│
└─────────────────────────────────────────────────────────────┘
↕️
┌─────────────────────────────────────────────────────────────┐
│ Application Layer │
│ (tRPC Client, React Query, Custom Hooks) │
└─────────────────────────────────────────────────────────────┘
↕️
┌─────────────────────────────────────────────────────────────┐
│ API Layer │
│ (tRPC Routers, Middleware) │
└─────────────────────────────────────────────────────────────┘
↕️
┌─────────────────────────────────────────────────────────────┐
│ Business Logic │
│ (Services, Use Cases, Domain Rules) │
└─────────────────────────────────────────────────────────────┘
↕️
┌─────────────────────────────────────────────────────────────┐
│ Data Access Layer │
│ (Mongoose Models, Repositories) │
└─────────────────────────────────────────────────────────────┘
↕️
┌─────────────────────────────────────────────────────────────┐
│ Database │
│ (MongoDB) │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ AI Service (Python) │
│ (FastAPI, LangChain, LangGraph, OpenAI GPT-4) │
│ │
│ Features: │
│ • AI Description Generator (GPT-4o-mini) │
│ • Comment Moderation (profanity + LLM analysis) │
│ • Smart Recommendations (personalized events) │
│ • Analytics Insights (natural language analysis) │
│ • Event Q&A Chatbot (context-aware responses) │
└─────────────────────────────────────────────────────────────┘
- Abstracts data access logic from business logic
- Located in:
backend/src/repositories/ - Benefits: Easy testing, database independence, centralized queries
// Example: UserRepository
export class UserRepository {
async findByEmail(email: string) { }
async create(userData: CreateUserDTO) { }
async update(id: string, data: UpdateUserDTO) { }
async delete(id: string) { }
}- Encapsulates business rules and use cases
- Located in:
backend/src/services/ - Benefits: Reusable logic, testable, separation from API layer
// Example: AuthService
export class AuthService {
constructor(
private userRepository: UserRepository,
private emailService: EmailService
) {}
async signupAcademic(data: SignupDTO) {
// Business logic here
}
}- Creates complex objects with different configurations
- Used for: User creation (Academic vs Vendor vs Admin)
- Benefits: Encapsulates creation logic, reduces duplication
// Example: UserFactory
export class UserFactory {
static createAcademicUser(data: AcademicSignupDTO) { }
static createVendorUser(data: VendorSignupDTO) { }
static createAdminUser(data: AdminSignupDTO) { }
}- Different email strategies for different scenarios
- Used for: Verification emails, notifications, receipts
- Benefits: Easy to add new email types, testable
// Example: Email Strategies
export interface EmailStrategy {
getSubject(): string;
getTemplate(data: any): string;
}
export class VerificationEmailStrategy implements EmailStrategy { }
export class WelcomeEmailStrategy implements EmailStrategy { }- Request/response processing pipeline
- Used for: Authentication, authorization, logging, error handling
- Benefits: Reusable, composable, separation of concerns
// Example: Auth Middleware
const isAuthenticated = t.middleware(async ({ ctx, next }) => {
if (!ctx.user) throw new TRPCError({ code: 'UNAUTHORIZED' });
return next({ ctx: { user: ctx.user } });
});- Event emitters for notifications and side effects
- Used for: Email notifications, system notifications
- Benefits: Decoupled components, scalable
// Example: Event Emitter
eventEmitter.on('user.registered', async (user) => {
await emailService.sendVerification(user);
await notificationService.create(user.id, 'Welcome!');
});- Services receive dependencies via constructor
- Benefits: Testable (easy mocking), loose coupling
// Example: DI in Services
export class EventService {
constructor(
private eventRepository: EventRepository,
private notificationService: NotificationService,
private emailService: EmailService
) {}
}- Zod schemas as DTOs for validation
- Located in:
backend/src/shared/types.tsand feature-specific files - Benefits: Type safety, validation, documentation
// Example: DTOs with Zod
export const SignupAcademicSchema = z.object({
email: z.string().email(),
password: z.string().min(8),
firstName: z.string().min(2),
lastName: z.string().min(2),
studentId: z.string(),
role: z.enum(['Student', 'Staff', 'TA', 'Professor'])
});- For building complex queries and filters
- Used for: Event search, filtering, sorting
- Benefits: Fluent API, readable code
// Example: Query Builder
const events = await EventQueryBuilder
.create()
.filterByType('Workshop')
.filterByDate(startDate, endDate)
.searchByName('AI')
.sortByDate('asc')
.paginate(page, limit)
.execute();- Formats data for API responses
- Located in:
backend/src/presenters/ - Benefits: Consistent API responses, security (hide sensitive fields)
// Example: UserPresenter
export class UserPresenter {
static toPublic(user: UserDocument) {
return {
id: user._id,
email: user.email,
firstName: user.firstName,
role: user.role,
// Exclude: password, tokens, etc.
};
}
}- Smart components (containers) handle logic
- Presentational components handle UI
- Benefits: Testable, reusable UI components
- Reusable React logic
- Located in:
event-manager/src/hooks/ - Examples:
useAuth,useEvents,useDebounce
- Complex components with multiple sub-components
- Used for: DataTable, Forms, Dialogs
- Benefits: Flexible API, composition
- Context providers for global state
- Used for: Auth, Theme, Notifications
- Located in:
event-manager/src/app/providers.tsx
backend/
├── src/
│ ├── config/ # Configuration files
│ ├── models/ # Mongoose models (Data layer)
│ ├── repositories/ # Repository pattern (NEW)
│ ├── services/ # Business logic (NEW)
│ ├── routers/ # tRPC routers (API layer)
│ ├── middleware/ # tRPC middleware (NEW)
│ ├── presenters/ # Response formatters (NEW)
│ ├── validators/ # Zod schemas (NEW)
│ ├── events/ # Event emitters (NEW)
│ ├── factories/ # Object factories (NEW)
│ ├── utils/ # Utility functions
│ ├── shared/ # Shared types
│ └── __tests__/ # Test files (NEW)
│ ├── unit/ # Unit tests
│ ├── integration/ # Integration tests
│ └── e2e/ # End-to-end tests
event-manager/
├── src/
│ ├── app/ # App configuration
│ ├── components/ # UI components
│ │ ├── ui/ # shadcn components
│ │ ├── layout/ # Layout components
│ │ └── features/ # Feature-specific components (NEW)
│ ├── features/ # Feature modules
│ │ └── [feature]/
│ │ ├── components/ # Feature components
│ │ ├── hooks/ # Feature hooks (NEW)
│ │ ├── pages/ # Feature pages
│ │ ├── services/ # Feature services (NEW)
│ │ └── __tests__/ # Feature tests (NEW)
│ ├── hooks/ # Global hooks
│ ├── lib/ # Libraries & utilities
│ ├── store/ # Zustand stores
│ └── __tests__/ # Global tests (NEW)
-
Unit Tests - Test individual functions/methods
- Services, Repositories, Utilities
- Framework: Jest
- Coverage target: 80%+
-
Integration Tests - Test API endpoints
- tRPC routers with test database
- Framework: Jest + Supertest
- Coverage target: 70%+
-
E2E Tests - Test full user flows
- Complete scenarios (signup → login → create event)
- Framework: Jest
- Coverage target: Critical paths only
-
Component Tests - Test UI components
- Framework: Vitest + React Testing Library
- Coverage target: 70%+
-
Integration Tests - Test feature flows
- User interactions, API calls
- Framework: Vitest + MSW (Mock Service Worker)
- Coverage target: 60%+
-
E2E Tests - Test full application
- Framework: Playwright
- Coverage target: Critical user journeys
- ✅
strict: true - ✅
noImplicitAny: true - ✅
strictNullChecks: true
- No
anytypes (useunknownwith type guards) - No unused variables
- Consistent naming conventions
- Max function length: 50 lines
- Max file length: 300 lines
- JSDoc comments for all public functions
- README in each feature folder
- Architecture Decision Records (ADR) for major decisions
- Database Indexing - Index frequently queried fields
- Query Optimization - Use lean() for read-only queries
- Caching - React Query for client-side caching
- Code Splitting - Lazy load routes
- Image Optimization - WebP format, lazy loading
- Bundle Size - Tree shaking, code splitting
- Input Validation - Zod validation on all inputs
- SQL Injection Prevention - Mongoose parameterized queries
- XSS Prevention - DOMPurify for user content
- CSRF Protection - SameSite cookies
- Rate Limiting - Prevent brute force attacks
- JWT Security - Short-lived access tokens, refresh tokens
- Password Hashing - bcrypt with salt rounds
- Environment Variables - Never commit secrets
- Horizontal Scaling - Stateless API design
- Database Sharding - Ready for MongoDB sharding
- Microservices Ready - Modular architecture
- Event-Driven - Ready for message queues (RabbitMQ, Kafka)
- CDN Integration - Static assets on CDN
- Load Balancing - Ready for multiple instances
This architecture ensures:
- ✅ Maintainability
- ✅ Testability
- ✅ Scalability
- ✅ Security
- ✅ Performance
- ✅ Team Collaboration