Caesar Forum is an internal session registration platform for Caesar.nl, designed for monthly internal events (talks, workshops, discussions). The application allows employees to browse upcoming forum sessions, register/unregister for sessions, and view their registered sessions. The interface is in Dutch and follows a professional corporate aesthetic with Fluent Design principles.
- Communication style: Simple, everyday language (Dutch UI)
- Documentation file: Use README.md only (not replit.md)
- Framework: React 18 with TypeScript
- Routing: Wouter (lightweight client-side routing)
- State Management: TanStack React Query for server state, React Context for user state
- UI Components: shadcn/ui component library built on Radix UI primitives
- Styling: Tailwind CSS with CSS variables for theming (light/dark mode support)
- Build Tool: Vite with HMR support
- Runtime: Node.js with Express
- Language: TypeScript (ESM modules)
- API Pattern: RESTful JSON API at
/api/*endpoints - Development: Vite middleware integration for HMR
- Production: Static file serving from built assets
- ORM: Drizzle ORM with PostgreSQL dialect
- Schema Validation: Zod with drizzle-zod integration
- Primary Storage: Microsoft Graph API (shared calendar)
- Error Handling: User-friendly Dutch error messages when Graph API unavailable (no fallback to mock data)
- Schema Location:
shared/schema.tscontains all type definitions
-
Authentication: Azure AD application with client credentials flow
-
Library: @azure/msal-node for token acquisition, @microsoft/microsoft-graph-client for API calls
-
Scope: Calendars.ReadWrite on shared mailbox
-
Service Location:
server/microsoft-graph.ts -
Environment Variables Required:
AZURE_CLIENT_ID: Azure AD application client IDAZURE_CLIENT_SECRET: Application secretAZURE_TENANT_ID: Azure AD tenant ID
-
Categories from Outlook: Events can have multiple categories from Outlook (e.g., "Talk", "Workshop", "Demo", "Brainstorm", "Hackathon", "Promotion"). All categories are shown as-is with no mapping. Filters only appear for categories that have events.
-
Multiple Speakers: All "required" attendees are treated as speakers. If no required attendees exist, falls back to the event organizer. Sessions can have multiple speakers, which are displayed with stacked avatars in the card view and listed individually in the detail view. Users who register via the app are added as "optional" attendees so they don't interfere with speaker detection.
-
Speaker Photos: Fetched automatically from Microsoft 365 via
/api/users/{email}/photoendpoint. Uses the speaker's email to retrieve their M365 profile photo. -
All-day Event: An all-day event determines the Forum date and title; only sessions on that same date are shown
-
Session URLs: User-friendly URLs using slugs (e.g.,
/sessies/angular-signal-forms-99v7g9). Slugs are auto-generated from title + hash suffix for uniqueness. -
Custom Slugs via Back-matter: Organizers can set custom slugs by adding YAML-style metadata at the end of the session description in Outlook:
--- slug: mijn-custom-slug ---The back-matter block is stripped from the displayed description.
-
Session Capacity: Organizers can set a maximum number of attendees by adding
capacityto the back-matter:--- capacity: 12 ---When capacity is set:
- The attendee count displays as "X van Y deelnemers" (e.g., "3 van 12 deelnemers")
- When full (attendees >= capacity), the registration button is disabled with text "Sessie is vol"
- Users already registered can still unregister
-
"Eten & Drinken" Category: Sessions with the "Eten & Drinken" (Food & Drinks) category receive special visual treatment:
- Distinctive food-themed background pattern on session cards
- Utensils icon displayed next to the category badge
- Category colors follow Outlook's category color scheme
-
Overlap Warnings: When a user tries to register for a session that overlaps with another session they're already registered for, an amber warning is displayed with the conflicting session details. Users can still proceed with registration if desired.
-
Auto-suggest Food & Drinks: The system automatically suggests "Eten & Drinken" sessions that fall between sessions a user is already registered for, making it easier to plan meals during the forum day.
- Retry Mechanism: All Graph API calls use exponential backoff with jitter (max 3 retries, 1-30 second delays)
- Token Refresh: 401 errors trigger automatic token invalidation and re-acquisition
- 403 Handling: Permission errors are logged but not retried (indicates mailbox access issues)
- 429 Throttling: Respects Microsoft's Retry-After header, otherwise uses exponential backoff
- Logging: All API requests/responses logged with timestamps, method, endpoint, status, and duration
- Authentication Monitoring: Separate logging for auth failures to aid troubleshooting
- Provider: Microsoft Entra ID (Azure AD) with OAuth 2.0 authorization code flow + PKCE
- Library: @azure/msal-node for server-side authentication
- Session Store: connect-pg-simple (PostgreSQL-backed session store)
- Routes:
GET /auth/login- Initiates OAuth flow with PKCEGET /auth/redirect- Handles OAuth callback, stores user in sessionGET /auth/logout- Clears session and redirects to Entra logoutGET /api/me- Returns authenticated user from session (401 if not logged in)
- Environment Variables Required:
SESSION_SECRET: Secret for signing session cookies- Same Azure credentials as Graph API (AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_TENANT_ID)
- Frontend Integration: UserContext fetches /api/me on mount and provides login/logout functions
- Registration Protection: All registration APIs require authenticated session (returns 401 otherwise)
-
Monorepo Structure: Client (
client/), server (server/), and shared code (shared/) in single repository with path aliases (@/,@shared/) -
Type Safety: Zod schemas in shared directory ensure runtime validation matches TypeScript types across frontend and backend
-
Component Library: shadcn/ui provides accessible, customizable components without external dependencies - components are copied into the codebase rather than imported from npm
-
Outlook is Leading: All session categories come directly from Outlook calendar events. The app only shows filters for categories that have events. No hardcoded category mappings.
-
Hero Section: The home page features a hero section with:
- Random cover photo from a pool of 5 compressed images (~300KB each for performance)
- Forum title and date from the all-day calendar event
- Session and attendee statistics
- Located in
client/src/components/HeroSection.tsx - Cover images stored in
attached_assets/directory
- PostgreSQL: Primary database (configured via
DATABASE_URLenvironment variable) - Drizzle Kit: Database migrations and schema push (
db:pushscript)
- Microsoft Graph API: Calendar integration with shared mailbox
- Google Fonts: Inter font family loaded via CDN
- connect-pg-simple: PostgreSQL session store (available but not currently active)
@tanstack/react-query: Server state management@azure/msal-node: Microsoft identity platform authentication@microsoft/microsoft-graph-client: Microsoft Graph API clientdrizzle-orm/drizzle-zod: Database ORM and validationexpress: HTTP server frameworkzod: Schema validationwouter: Client-side routingdate-fns: Date formatting utilitieslucide-react: Icon library
Build and run the application in a container:
# Build the container
docker build -t caesar-forum .
# Run the container (set environment variables)
docker run -p 5000:5000 \
-e AZURE_CLIENT_ID=your-client-id \
-e AZURE_CLIENT_SECRET=your-client-secret \
-e AZURE_TENANT_ID=your-tenant-id \
-e DATABASE_URL=your-database-url \
-e SESSION_SECRET=your-session-secret \
-e APP_URL=https://your-domain.com \
caesar-forumThe container exposes port 5000 and runs the production build.