Admin Backend Overview

The admin_backend_api is a Shelf-based HTTP server that provides administrative management capabilities for the ContainerPub platform. It handles user management, Keycloak-based authentication, feature role assignment, early access administration, and platform observability.

Architecture

Server Entry Point

dart
bin/server.dart

The server initializes logging, loads configuration from environment variables, sets up the Keycloak client, initializes the database, and starts the HTTP server on the configured port (default: 8081).

Middleware Pipeline

The request pipeline applies middleware in this order:

  • logRequests() - Built-in Shelf request logging
  • corsMiddleware() - Allows all origins, methods, and custom headers (including dev-auth bypass headers)
  • errorHandlingMiddleware() - Catches unhandled exceptions, returns 500 with Sentry reporting
  • jsonContentTypeMiddleware() - Adds application/json content-type if missing
  • Router - The mounted admin router handles all route matching

Project Structure

Diagram
admin_backend_api/
├── bin/
│   └── server.dart              # Entry point
├── lib/
│   ├── app.dart                 # App factory (creates the Handler pipeline)
│   ├── app_context.dart         # AppContext: config + keycloak + DB init
│   ├── auth/
│   │   ├── admin_auth_middleware.dart  # Bearer token validation
│   │   ├── admin_principal.dart        # AdminPrincipal data class
│   │   ├── admin_role.dart             # AdminRole enum (viewer / full_admin)
│   │   ├── authorization.dart          # Write-access guard middleware
│   │   └── request_context.dart        # Request extension for adminPrincipal
│   ├── common/
│   │   ├── common.dart                # Shared Logger
│   │   ├── error_reporting.dart       # Sentry + logging error capture
│   │   ├── json_middleware.dart       # CORS, JSON content-type, error handling
│   │   ├── json_response.dart         # Convenience JSON response helpers
│   │   ├── masking.dart               # Email masking utility
│   │   └── request_parsing.dart       # JSON body reader + int parser
│   ├── config/
│   │   └── app_config.dart            # Env-based configuration
│   ├── handlers/
│   │   ├── auth_handler.dart          # Login/refresh/logout/verify/me
│   │   ├── users_handler.dart         # User CRUD + status management
│   │   ├── tiers_handler.dart         # Tier CRUD + assignment
│   │   ├── organizations_handler.dart # Org CRUD + membership
│   │   ├── user_feature_roles_handler.dart  # Feature role grant/remove/stats
│   │   ├── early_access_features_handler.dart  # Feature flag CRUD
│   │   ├── early_access_request_handler.dart   # EA request management
│   │   ├── early_access_form_schema_handler.dart # Form schema management
│   │   └── observability_handler.dart  # System metrics + logs
│   ├── routes/
│   │   └── admin_router.dart         # All route registrations
│   └── services/
│       ├── users_service.dart               # User CRUD, status, temp passwords
│       ├── tiers_service.dart               # Tier CRUD + assignment logic
│       ├── organizations_service.dart       # Org CRUD + membership logic
│       ├── user_feature_roles_service.dart  # Keycloak role grant/remove/stats
│       ├── feature_flags_service.dart       # Feature flag CRUD
│       ├── early_access_admin_service.dart  # EA request logic
│       ├── early_access_form_schema_admin_service.dart # Form schema logic
│       ├── observability_service.dart       # InfluxDB queries + PII sanitization
│       └── token_claims_parser.dart         # JWT role extraction
└── test/
    └── server_test.dart           # Auth middleware + masking tests

Authentication & Authorization

The admin backend uses Keycloak OIDC for authentication and role-based access control (RBAC) for authorization.

Admin Roles

RolePermissionDescription
full_admin Read + Write Full administrative access
viewer Read only Can view data but not modify

Two-Layer Middleware

Layer 1: adminAuthMiddleware — Validates the Bearer token via Keycloak introspection, extracts roles from the JWT, and constructs an AdminPrincipal. Returns 401 if token is missing or invalid, 403 if the user lacks any admin role.

Layer 2: requireWriteAccess() — Checks the AdminPrincipal role. If viewer (no canWrite), returns 403. Applied only to write operations (POST, PUT, PATCH, DELETE).

Route-Level Auth

Routes use two helper functions:

  • _withAuth() — Read access (adminAuthMiddleware only)
  • _withWriteAuth() — Write access (adminAuthMiddleware + requireWriteAccess)

Handlers & Services

Auth Handler

Manages admin session lifecycle: login, token refresh, logout, session verification, and current user info.

Users Handler

Full user management: list, get, update, disable (block), enable, delete (soft-delete), and temporary password generation.

Organizations Handler

Create, read, update organizations. Add and remove members.

Tiers Handler

Define service tiers and assign/unassign users to them.

User Feature Roles Handler

Manage Keycloak client-level feature roles: view assigned roles, grant new roles, remove roles, and get aggregate role statistics.

Early Access Handlers

Three handlers manage the early access system:

  • Request Handler — Review, approve, reject early access requests with capacity enforcement
  • Features Handler — Manage feature flags for early access
  • Form Schema Handler — Define and manage registration form schemas

Observability Handler

System-wide monitoring: error rate overview, log retrieval, error log filtering, and load metrics from InfluxDB.

Database Tables

The admin backend initializes these PostgreSQL tables on startup:

TablePurpose
tiers Service tier definitions (name, description, metadata)
user_tiers Junction: user_uuid → tier_id assignments
organizations Organization definitions (name, owner)
organization_members Junction: user_uuid → org_uuid with role

It also uses shared tables from the database package:

  • users — User accounts and status
  • user_information — Extended user profile data
  • early_access_requests — Early access registration requests
  • early_access_features — Feature flag configuration
  • early_access_audit_logs — Admin action audit trail
  • early_access_form_schemas — Registration form definitions

Key Design Patterns

  • Handler-Service Separation — Handlers parse requests and format responses. Business logic lives in services.
  • Soft-Delete — Users are never physically removed. disableUser() sets status = 'blocked', deleteUser() sets status = 'deleted'.
  • Email Masking — Emails in list responses are masked (e.g., jo***@example.com). Names show only initials (JD***).
  • Temporary Passwords — Generated with Random.secure(), hashed via BCrypt, and emailed to users.
  • Audit Logging — The early access system records all admin actions with actor, action, and metadata.
  • Error Reporting — All unhandled errors are captured by ErrorReporting.captureException() and sent to both console and Sentry.

Configuration

Environment variables (via .env file):

VariableDescription
KEYCLOAK_URLKeycloak server URL
KEYCLOAK_REALMKeycloak realm name
KEYCLOAK_CLIENT_IDAdmin client ID
KEYCLOAK_CLIENT_SECRETAdmin client secret
DATABASE_URLPostgreSQL connection string
FULL_ADMIN_ROLE Role name for write access (default: full_admin)
VIEWER_ROLE Role name for read-only (default: viewer)
FEATURE_ROLES_CLIENT_ID Keycloak client ID for feature roles
ADMIN_CLIENT_IDKeycloak client ID for admin app
DEFAULT_USER_FEATURE_ROLES CSV list of default roles for new users
BACKEND_GRANTABLE_FEATURE_ROLES CSV list of roles admins can grant
EMAIL_API_KEYForwardEmail API key
ALLOW_DEV_AUTH_BYPASS Enable dev auth bypass (dev only)
DSN_SENTRYSentry DSN for error tracking

Running

dart
cd admin_backend_api
dart pub get
dart run bin/server.dart

Next Steps