ocg-server
Active contributors: Sergio Castaño Arteaga, Cintia Sánchez García, Sako Mammadov
Purpose
ocg-server is the main Rust web server for the GOUP Alliance platform. It serves all HTML pages using server-side rendering with MiniJinja templates, implements OAuth and password authentication, manages background workers for event discovery, job discovery, meetings, notifications, and payments, and exposes both public and authenticated HTTP endpoints.
Directory layout
ocg-server/
├── Cargo.toml
├── Dockerfile
├── Dockerfile.dev
├── build.rs # embeds OCG_COMMIT_SHA at compile time
├── src/
│ ├── main.rs # entry point, wires all subsystems
│ ├── config.rs # Figment config (YAML + OCG_* env vars)
│ ├── router.rs # axum router, routes, middleware setup
│ ├── router/
│ │ ├── api.rs # /api/* routes
│ │ └── dashboard.rs # /dashboard/* routes
│ ├── auth.rs # auth layer setup, session store, OAuth/OIDC flows
│ ├── auth/ # tests
│ ├── db.rs # DynDB trait + PgDB implementation
│ ├── db/ # per-domain DB modules (alliance, auth, event, group, …)
│ ├── handlers.rs # re-exports for handlers
│ ├── handlers/ # HTTP handler modules per domain
│ │ ├── alliance.rs / alliance/
│ │ ├── auth.rs / auth/
│ │ ├── dashboard/ # per-section dashboard handlers
│ │ ├── event.rs / event/
│ │ ├── group.rs / group/
│ │ ├── images.rs / images/
│ │ ├── meetings.rs / meetings/
│ │ ├── payments.rs / payments/
│ │ ├── site.rs / site/ # public site pages (home, explore, landscape, jobs, …)
│ │ ├── api/ # JSON API handlers
│ │ ├── extractors.rs # custom axum extractors
│ │ └── error.rs # shared error types
│ ├── services.rs # re-exports for services
│ ├── services/ # background workers
│ │ ├── event_discovery.rs # You.com-powered event scraping
│ │ ├── job_discovery.rs # You.com-powered job scraping
│ │ ├── meetings.rs # Google Meet / Zoom link management
│ │ ├── notifications.rs # email delivery queue worker
│ │ ├── payments.rs # Stripe checkout and refund manager
│ │ ├── recording_publishing.rs # YouTube upload worker
│ │ └── images.rs # image storage (DB or S3)
│ ├── templates.rs # re-exports for templates
│ ├── templates/ # MiniJinja template structs per domain
│ ├── types.rs # re-exports for domain types
│ ├── types/ # domain type definitions
│ ├── integrations.rs / integrations/ # You.com search client
│ ├── activity_tracker.rs # tracks user page activity
│ ├── validation.rs # garde validation helpers
│ └── util.rs # shared utilities
├── templates/ # HTML templates (.jinja)
└── static/ # static assets embedded at build time
Key abstractions
| Abstraction | File | Description |
|---|---|---|
DynDB |
ocg-server/src/db.rs |
Arc<dyn …> trait object composed of all domain DB sub-traits |
PgDB |
ocg-server/src/db.rs |
Concrete deadpool-postgres implementation of DynDB |
AuthnBackend |
ocg-server/src/auth.rs |
axum-login backend; supports GitHub/Google/LinkedIn OAuth2 and OpenID Connect |
SessionStore |
ocg-server/src/auth.rs |
Database-backed tower-sessions session store |
Config |
ocg-server/src/config.rs |
Figment root config; merged from YAML file and OCG_* env vars |
BackgroundTasks |
ocg-server/src/main.rs |
CancellationToken + TaskTracker wiring for all background workers |
PgNotificationsManager |
ocg-server/src/services/notifications.rs |
Queues and delivers email notifications via Lettre/SMTP |
PgPaymentsManager |
ocg-server/src/services/payments/manager.rs |
Checkout, refund, and webhook reconciliation logic |
MeetingsManager |
ocg-server/src/services/meetings.rs |
Manages Google Meet and Zoom link lifecycles |
ManualEventDiscovery |
ocg-server/src/services/event_discovery.rs |
On-demand You.com event scraping trigger |
ManualJobDiscovery |
ocg-server/src/services/job_discovery.rs |
On-demand You.com job scraping trigger |
How it works
Startup sequence
sequenceDiagram
participant main
participant Config
participant PgDB
participant Workers
participant Router
participant TCPListener
main->>Config: load YAML + OCG_* env vars
main->>PgDB: create deadpool-postgres pool
main->>Workers: start meetings, recording, event_discovery, job_discovery workers
main->>Workers: start notifications manager worker
main->>Workers: setup payments manager
main->>Router: router::setup() with all shared state
main->>TCPListener: bind addr from config
TCPListener-->>main: serve until SIGTERM / ctrl+c
main->>Workers: cancellation_token.cancel() + wait
Request lifecycle
sequenceDiagram
participant Client
participant TraceLayer
participant AuthLayer
participant CacheHeaders
participant Handler
participant DynDB
Client->>TraceLayer: HTTP request
TraceLayer->>AuthLayer: pass through
AuthLayer->>AuthLayer: load session from DB
AuthLayer->>CacheHeaders: authenticated or anonymous context
CacheHeaders->>Handler: inject State, session
Handler->>DynDB: query / mutate
DynDB-->>Handler: result
Handler-->>Client: HTML (MiniJinja) or JSON response
Routing structure
The router is built in ocg-server/src/router.rs. Routes are grouped as:
- Public site (
/,/explore,/jobs,/landscape,/search, …) — rendered with shared cache headers - Auth (
/auth/login,/auth/oauth/github,/auth/oauth/google, …) - Alliance pages (
/:alliance_name,/:alliance_name/group/:group_name/…) - Event pages (
/:alliance_name/group/:group_name/event/:event_id/…) - Dashboard (
/dashboard/…) — login-required, per-alliance/group management - API (
/api/…) — JSON endpoints used by HTMX partial updates - Images (
/images/…) - Static assets — embedded via
rust-embed, served with long-lived cache headers
Middleware layers (inner to outer): TraceLayer, SetResponseHeaderLayer (cache/commit-SHA headers), AuthManagerLayer (axum-login), MessagesManagerLayer (flash messages).
Auth system
See features/auth.md for a detailed walkthrough. At the router level, protected routes use login_required!(AuthnBackend, login_url = LOG_IN_URL) from axum-login.
Configuration
ocg-server accepts a YAML config file (-c path/to/config.yaml) and environment variables prefixed OCG_ with __ as a nesting separator. Required fields: db, email, server.addr, server.base_url. Optional sections: meetings, payments, recording_publishing, integrations.you_com.
Integration points
| Integration | Config section | Purpose |
|---|---|---|
| PostgreSQL | db |
All persistence via deadpool-postgres |
| SMTP | email |
Notification delivery via Lettre |
| GitHub OAuth2 | server.oauth2.github |
Social login |
| Google OIDC | server.oidc.google |
Social login |
| LinkedIn OIDC | server.oidc.linkedin |
Social login |
| Google Meet | meetings.google_meet |
Meeting link provisioning |
| Zoom | meetings.zoom |
Meeting link provisioning |
| Stripe | payments.provider = stripe |
Checkout and refunds |
| YouTube | recording_publishing.youtube |
Post-event recording upload |
| You.com | integrations.you_com |
AI-powered event and job discovery |
| S3 | images.provider = s3 |
Image storage (alternative to DB) |
Entry points for modification
- Add a new page: create a handler in
ocg-server/src/handlers/site/and register it inocg-server/src/router.rs. - Add a background worker: implement the worker in
ocg-server/src/services/, start it inmain.rs::main(). - Add a DB operation: implement the method on the appropriate sub-trait in
ocg-server/src/db/and add it to theDynDBcomposed trait inocg-server/src/db.rs. - Add a new config key: add the field to the relevant struct in
ocg-server/src/config.rsand document theOCG_env variable.