LogoContainerPub

Admin Backend Overview

Architecture and components of the admin_backend_api server

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#

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:

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

Project Structure#

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_adminRead + WriteFull administrative access
viewerRead onlyCan 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
tiersService tier definitions (name, description, metadata)
user_tiersJunction: user_uuid → tier_id assignments
organizationsOrganization definitions (name, owner)
organization_membersJunction: 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#

  1. Handler-Service Separation — Handlers parse requests and format responses. Business logic lives in services.
  2. Soft-Delete — Users are never physically removed. disableUser() sets status = 'blocked', deleteUser() sets status = 'deleted'.
  3. Email Masking — Emails in list responses are masked (e.g., jo***@example.com). Names show only initials (JD***).
  4. Temporary Passwords — Generated with Random.secure(), hashed via BCrypt, and emailed to users.
  5. Audit Logging — The early access system records all admin actions with actor, action, and metadata.
  6. 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_ROLERole name for read-only (default: viewer)
FEATURE_ROLES_CLIENT_IDKeycloak client ID for feature roles
ADMIN_CLIENT_IDKeycloak client ID for admin app
DEFAULT_USER_FEATURE_ROLESCSV list of default roles for new users
BACKEND_GRANTABLE_FEATURE_ROLESCSV list of roles admins can grant
EMAIL_API_KEYForwardEmail API key
ALLOW_DEV_AUTH_BYPASSEnable dev auth bypass (dev only)
DSN_SENTRYSentry DSN for error tracking

Running#

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

Next Steps#