The Eventer backend is a modern API server leveraging Elysia.js on Bun runtime for exceptional performance and developer experience. It serves as the core data layer for event management operations with a focus on type safety and maintainability.
- Performance: ~10x faster than Express.js
- Type Safety: End-to-end TypeScript inference
- Developer Experience: Built-in validation, documentation, testing
- Ecosystem: Native Bun integration with modern APIs
- Speed: 3x faster startup, 20% faster execution than Node.js
- Built-in Tools: WebSocket, SQLite, test runner, bundler
- Memory Efficiency: Lower memory footprint
- TypeScript Native: No compilation step needed in development
- Type Safety: Schema-first with generated types
- Performance: Minimal overhead, optimized queries
- Migration: Robust versioning and rollback support
- Multi-database: SQLite (dev), PostgreSQL/MySQL (production)
apps/backend/
├── src/
│ ├── index.ts # Server bootstrap
│ ├── env.ts # Environment validation (Zod)
│ ├── client.ts # Database client configuration
│ │
│ ├── infrastructure/ # External concerns
│ │ ├── auth/ # Authentication providers
│ │ │ ├── google.provider.ts
│ │ │ └── jwt.provider.ts
│ │ └── db/ # Database layer
│ │ ├── index.ts # Connection setup
│ │ ├── schema.ts # Drizzle schemas
│ │ └── migrations/ # Version-controlled changes
│ │
│ ├── modules/ # Domain modules (clean architecture)
│ │ ├── home/ # Health/status endpoints
│ │ ├── auth/ # Authentication logic
│ │ │ ├── auth.route.ts
│ │ │ ├── auth.service.ts
│ │ │ └── dtos/
│ │ ├── user/ # User management
│ │ │ ├── user.route.ts
│ │ │ ├── user.service.ts
│ │ │ ├── user.repository.ts
│ │ │ ├── user.model.ts
│ │ │ └── dtos/
│ │ ├── event/ # Event CRUD
│ │ └── agenda/ # Schedule management
│ │
│ └── shared/ # Cross-cutting concerns
│ ├── repository.ts # Base repository with common patterns
│ ├── schemas.ts # Shared Zod validation schemas
│ └── middleware/ # Custom middleware
│ ├── auth.middleware.ts
│ ├── cors.middleware.ts
│ └── validation.middleware.ts
│
├── drizzle/ # Database artifacts
│ ├── migrations/ # Generated SQL migrations
│ └── meta/ # Migration metadata
│
├── drizzle.config.ts # ORM configuration
├── vitest.config.ts # Test configuration
└── package.json # Dependencies & scripts
- Resource-based URLs:
/api/events,/api/users - HTTP Verbs: GET (read), POST (create), PUT (update), DELETE (remove)
- Status Codes: Consistent use of HTTP standards
- Content-Type: JSON for data exchange
// Consistent error response format
{
error: true,
code: "VALIDATION_ERROR",
message: "Invalid email format",
details: { field: "email", received: "invalid-email" }
}// Query parameters for pagination
GET /api/events?page=1&limit=20&sort=createdAt&order=desc
// Response format
{
data: [...],
pagination: {
page: 1,
limit: 20,
total: 156,
totalPages: 8,
hasNext: true,
hasPrev: false
}
}// Clean, declarative route definitions
export const userRouter = new Elysia({ prefix: "/users" })
.use(authMiddleware)
.get("/", userController.list, {
query: t.Object({
page: t.Optional(t.Number()),
limit: t.Optional(t.Number()),
}),
})
.post("/", userController.create, {
body: CreateUserSchema,
});// Business logic separation
export class UserService {
constructor(
private userRepository: UserRepository,
private emailService: EmailService
) {}
async createUser(dto: CreateUserDTO): Promise<UserResponse> {
// Validation, business rules, side effects
const existingUser = await this.userRepository.findByEmail(dto.email);
if (existingUser) {
throw new ConflictError("Email already exists");
}
const user = await this.userRepository.create(dto);
await this.emailService.sendWelcome(user.email);
return this.toResponse(user);
}
}// Data access abstraction
export class UserRepository extends BaseRepository<UserType> {
async findByEmail(email: string): Promise<UserType | null> {
return this.db.select().from(users).where(eq(users.email, email)).get();
}
async findActiveUsers(): Promise<UserType[]> {
return this.db.select().from(users).where(eq(users.isActive, true)).all();
}
}# Quick start
cd apps/backend
bun install
cp .env.example .env
bun run db:migrate
bun dev
# Development server runs on http://localhost:4000
# API documentation at http://localhost:4000/swagger# Schema changes workflow
bun run db:generate # Create migration from schema changes
bun run db:migrate # Apply pending migrations
bun run db:studio # Visual database browser
# Development utilities
bun run db:push # Push schema without migration (dev only)
bun run db:pull # Reverse engineer from existing DB# Unit tests with Vitest
bun run test # Run once
bun run test:watch # Watch mode for development
bun run test:coverage # Generate coverage report
# Integration tests
bun run test:integration
# Type checking
bun run typecheck- Connection Pooling: Configured for concurrent load
- Query Optimization: Drizzle generates efficient SQL
- Indexing Strategy: Database indexes on frequently queried fields
- Prepared Statements: Automatic statement preparation and caching
- Bun Advantages: Native speed improvements over Node.js
- Memory Management: Efficient garbage collection patterns
- HTTP/2 Support: Modern protocol support for better throughput
- Streaming: Large response streaming for file operations
// Multi-layer caching approach
class CacheService {
// L1: In-memory for hot data
private memoryCache = new Map();
// L2: Redis for distributed caching
private redisCache: RedisClient;
// L3: Database with proper indexes
async get(key: string) {
return (
this.memoryCache.get(key) ||
(await this.redisCache.get(key)) ||
(await this.database.query(key))
);
}
}- Login: Email/password or OAuth (Google)
- JWT Generation: Access token (15min) + Refresh token (7 days)
- Token Validation: Middleware validates on protected routes
- Token Refresh: Automatic refresh when access token expires
// Zod schemas for runtime validation
export const CreateEventSchema = z.object({
name: z.string().min(1).max(255),
description: z.string().optional(),
startDate: z.coerce.date(),
endDate: z.coerce.date(),
location: z.string().min(1),
capacity: z.number().int().positive(),
});- CORS: Configurable origins for cross-origin requests
- Rate Limiting: Prevent abuse with request throttling
- Helmet: Security headers for common vulnerabilities
- Input Sanitization: XSS prevention on all user inputs
# Docker composition for production
services:
api:
image: eventer-backend:latest
replicas: 3
environment:
NODE_ENV: production
DATABASE_URL: postgresql://...
database:
image: postgres:15
volumes:
- db_data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
nginx:
image: nginx:alpine
# Load balancer + SSL termination- Health Checks:
/api/healthendpoint for load balancer - Metrics: Prometheus metrics for performance monitoring
- Logging: Structured JSON logs with correlation IDs
- Error Tracking: Sentry integration for error reporting
- Performance: APM tools for request tracing
- Horizontal Scaling: Stateless design allows multiple instances
- Database Scaling: Read replicas for query distribution
- Caching: Redis cluster for distributed caching
- Queue Processing: Background job processing for heavy operations
This backend architecture provides a robust, scalable foundation for the Eventer platform while maintaining excellent developer experience and performance characteristics.