Early Access Admin Management

The Early Access Admin system provides comprehensive management of early access requests for the ContainerPub platform. This feature allows administrators to control who gains access to the platform during preview/beta phases.

Overview

The early access system consists of:

  • Request Management: Review, approve, or reject early access requests
  • Capacity Control: Set limits on the number of approved users
  • Feature Flag Toggle: Enable/disable early access registration globally
  • Audit Logging: Track all administrative actions on requests
  • Temporary Passwords: Generate and send temporary passwords for approved users

Architecture

Database Tables

early_access_requests

  • Stores all early access requests from potential users
  • Tracks status: pending, approved, rejected, converted, expired
  • Contains user information: email, name, company, use case
  • Links to created user accounts via user_uuid

early_access_audit_logs

  • Records all administrative actions on requests
  • Tracks who performed actions and when
  • Stores metadata for each action (notes, reasons, etc.)

feature_flags

  • Global feature flag: preview_registration_enabled
  • Controls whether new early access requests are accepted
  • Stores capacity limit in value.target_users

Components

Backend Service: admin_backend_api/lib/services/early_access_admin_service.dart

  • Business logic for request management
  • Capacity enforcement
  • Email masking for privacy
  • Audit log creation

Feature Flags Service: admin_backend_api/lib/services/feature_flags_service.dart

  • List, read, and update feature flags
  • Feature overview with registration statistics

Form Schema Service: admin_backend_api/lib/services/early_access_form_schema_admin_service.dart

  • CRUD operations for registration form schemas
  • Schema upsert (create or update)
  • Form data validation against schemas

HTTP Handlers: admin_backend_api/lib/handlers/

  • early_access_request_handler.dart — REST API endpoints for request management
  • early_access_features_handler.dart — Feature flag endpoints
  • early_access_form_schema_handler.dart — Form schema management endpoints
  • Request validation and error handling with Sentry integration

Frontend: frontend/admin_portal/lib/features/early_access/

  • Flutter UI with Forui components
  • Request listing with filters
  • Detail view with action buttons
  • Settings management

Feature Flag System

Flag: preview_registration_enabled

This feature flag controls early access registration globally.

Structure:

json
{
  "name": "preview_registration_enabled",
  "enabled": true,
  "value": {
    "target_users": 100
  }
}

Behavior:

  • enabled: true - Early access registration is open (subject to capacity)
  • enabled: false - Early access registration is closed (no new requests accepted)
  • value.target_users - Maximum number of approved/converted users allowed

Flag Management API

Feature flags have their own management endpoints:

List all flags:

dart
GET /api/admin/early-access-features

Get a specific flag:

dart
GET /api/admin/early-access-features/<name>

Update a flag:

dart
PUT /api/admin/early-access-features/<uuid>
json
{
  "enabled": false,
  "value": { "target_users": 200 }
}

Get feature overview with stats:

dart
GET /api/admin/early-access-features/<featureUuid>/overview

Form Schema Management

The early access system supports configurable registration forms via the form schema management API.

Schema Operations

List schemas:

dart
GET /api/admin/early-access-form-schemas

Get schema by UUID:

dart
GET /api/admin/early-access-form-schemas/<schemaUuid>

Get schemas by feature:

dart
GET /api/admin/early-access-form-schemas/by-feature/<featureUuid>

Create or update schema (upsert):

dart
POST /api/admin/early-access-form-schemas
json
{
  "feature_uuid": "feature-uuid",
  "schema": {
    "fields": [
      {
        "name": "company",
        "type": "text",
        "required": true,
        "label": "Company Name"
      },
      {
        "name": "use_case",
        "type": "textarea",
        "required": true,
        "label": "How will you use ContainerPub?"
      }
    ]
  }
}

Delete schema:

dart
DELETE /api/admin/early-access-form-schemas/<schemaUuid>

Validate form data against schema:

dart
POST /api/admin/early-access-form-schemas/validate
json
{
  "schema_uuid": "schema-uuid",
  "data": {
    "company": "Acme Corp",
    "use_case": "Building cloud functions"
  }
}

Capacity Management

The system enforces capacity limits:

  • Check on Approval: Before approving a request, the system checks if capacity has been reached
  • Count Approved/Converted: Only users with status approved or converted count toward capacity
  • Prevent Over-Approval: If capacity is reached, approval requests fail with an error

Capacity Calculation:

dart
final capacity = featureFlag.value['target_users'];
final approvedCount = COUNT(*) WHERE status IN ('approved', 'converted');
final availableSlots = capacity - approvedCount;
final acceptingRequests = approvedCount < capacity;

API Endpoints

List Requests

GET /api/admin/early-access/requests

Query parameters:

  • page (int, default: 1) - Page number
  • page_size (int, default: 20, max: 100) - Items per page
  • status (string, optional) - Filter by status: pending, approved, rejected, converted, expired
  • search (string, optional) - Search in email, first_name, last_name

Response:

json
{
  "items": [
    {
      "uuid": "req-uuid",
      "email": "jo***@example.com",
      "first_name": "John",
      "last_name": "Doe",
      "company": "Acme Corp",
      "use_case": "Building cloud functions",
      "status": "pending",
      "created_at": "2024-01-15T10:30:00Z"
    }
  ],
  "page": 1,
  "page_size": 20
}

Get Request Details

GET /api/admin/early-access/requests/:requestUuid

Response includes full details with less masking for admin use.

Approve Request

POST /api/admin/early-access/requests/:requestUuid/approve

Request body:

json
{
  "notes": "Approved for beta testing",
  "temporary_password": "optional-custom-password"
}

Capacity Check: Fails if capacity limit reached.

Response:

json
{
  "success": true,
  "message": "Request approved successfully",
  "item": { /* updated request */ }
}

Reject Request

POST /api/admin/early-access/requests/:requestUuid/reject

Request body:

json
{
  "reason": "Does not meet criteria",
  "notes": "Optional additional notes"
}

Response:

json
{
  "success": true,
  "message": "Request rejected successfully",
  "item": { /* updated request */ }
}

Send Temporary Password

POST /api/admin/early-access/requests/:requestUuid/send-temporary-password

Generates a new temporary password for an approved request.

Response:

json
{
  "success": true,
  "temporary_password": "ABC123xyz!@#",
  "email": "jo***@example.com"
}

Get Audit Logs

GET /api/admin/early-access/requests/:requestUuid/audit-logs

Returns all audit logs for a specific request.

Response:

json
{
  "items": [
    {
      "uuid": "log-uuid",
      "action": "approved",
      "actor_uuid": "admin-uuid",
      "actor_email": "ad***@admin.com",
      "metadata": {
        "notes": "Approved for beta testing"
      },
      "created_at": "2024-01-15T11:00:00Z"
    }
  ]
}

Get Settings

GET /api/admin/early-access/settings

Returns current early access settings and statistics.

Response:

json
{
  "settings": {
    "capacity": 100,
    "approved_count": 45,
    "pending_count": 12,
    "available_slots": 55,
    "accepting_requests": true,
    "feature_flag_enabled": true
  }
}

Update Capacity

PUT /api/admin/early-access/settings/capacity

Request body:

json
{
  "capacity": 200
}

Updates the target_users value in the feature flag.

Response:

json
{
  "success": true,
  "capacity": 200,
  "updated_at": "2024-01-15T12:00:00Z"
}

Toggle Feature Flag

PUT /api/admin/early-access/settings/toggle

Request body:

json
{
  "enabled": false
}

Enables or disables early access registration globally.

Response:

json
{
  "success": true,
  "enabled": false,
  "updated_at": "2024-01-15T12:00:00Z"
}

Request Lifecycle

Diagram
┌─────────┐
│ pending │ ─┐
└─────────┘  │
             │ approve
             ├──────────> ┌──────────┐
             │            │ approved │
             │            └──────────┘
             │                 │
             │                 │ user creates account
             │                 v
             │            ┌───────────┐
             │            │ converted │
             │            └───────────┘
             │
             │ reject
             └──────────> ┌──────────┐
                          │ rejected │
                          └──────────┘

Status Descriptions:

  • pending - Awaiting admin review
  • approved - Approved by admin, temporary password sent
  • converted - User successfully created account
  • rejected - Rejected by admin with reason
  • expired - Approval expired (not yet implemented)

Audit Actions

All administrative actions are logged:

  • approved - Request approved
  • rejected - Request rejected
  • resent_password - Temporary password regenerated
  • capacity_changed - Capacity limit updated
  • flag_toggled - Feature flag enabled/disabled

Security & Privacy

Email Masking

All email addresses are masked in responses:

  • john.doe@example.comjo***@example.com
  • Shows first 2 characters (or 1 if short) + *** + domain

Minimal User Info

Only essential fields are exposed:

  • No internal IDs exposed (only UUIDs)
  • No sensitive metadata in list views
  • Full details only in detail endpoints

Role-Based Access

  • viewer: Can view requests and settings (read-only)
  • full_admin: Can approve, reject, update capacity, toggle flag

Frontend Implementation

Page Structure

EarlyAccessPage (early_access_page.dart)

  • Main page with request list
  • Search and filter controls
  • Settings card showing capacity and stats
  • Pagination controls

EarlyAccessRequestDetailPage (separate route)

  • Full request details
  • Action buttons (approve/reject)
  • Audit log timeline
  • Temporary password management

State Management

Uses Riverpod providers:

  • earlyAccessListProvider - Fetches paginated requests
  • earlyAccessSettingsProvider - Fetches settings/stats
  • earlyAccessManagementProvider - Handles actions (approve/reject/update)
  • Filter providers for search and status

UI Components

Built with Forui:

  • FCard - Request cards and settings card
  • FButton - Action buttons
  • FSelect - Status filter dropdown
  • FTextField - Search input
  • FCircularProgress - Loading indicators

Usage Examples

Approve a Request

bash
curl -X POST http://localhost:8081/api/admin/early-access/requests/req-uuid/approve \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "notes": "Approved for beta testing",
    "temporary_password": "Welcome123!"
  }'

Update Capacity

bash
curl -X PUT http://localhost:8081/api/admin/early-access/settings/capacity \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"capacity": 200}'

Disable Early Access Registration

bash
curl -X PUT http://localhost:8081/api/admin/early-access/settings/toggle \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"enabled": false}'

Search Requests

bash
curl "http://localhost:8081/api/admin/early-access/requests?search=john&status=pending" \
  -H "Authorization: Bearer $TOKEN"

Best Practices

Capacity Planning

  • Set Realistic Limits: Start with a conservative capacity
  • Monitor Closely: Watch approved_count vs capacity
  • Adjust as Needed: Increase capacity based on system performance
  • Communicate: Inform users when capacity is reached

Request Review

  • Review Promptly: Don't leave requests pending too long
  • Provide Reasons: Always include rejection reasons
  • Add Notes: Document why requests were approved/rejected
  • Track Patterns: Use audit logs to identify trends

Feature Flag Management

  • Coordinate Releases: Disable flag during maintenance
  • Test Thoroughly: Verify flag behavior before enabling
  • Monitor Impact: Watch for issues after toggling
  • Document Changes: Log why flag was toggled

Troubleshooting

Capacity Limit Reached

Symptom: Approval requests fail with "Capacity limit reached"

Solution:

  • Check current capacity: GET /api/admin/early-access/settings
  • Increase capacity: PUT /api/admin/early-access/settings/capacity
  • Or reject pending requests to free slots

Feature Flag Not Working

Symptom: Registration still accepts/rejects requests despite flag state

Solution:

  • Verify flag state: GET /api/admin/feature-flags/preview_registration_enabled
  • Check backend logs for errors
  • Ensure database connection is healthy

Audit Logs Missing

Symptom: No audit logs appear for actions

Solution:

  • Check database table: SELECT * FROM early_access_audit_logs
  • Verify admin principal is correctly extracted from token
  • Check error logs for audit log insertion failures

Future Enhancements

  • Email Notifications: Automatic emails on approval/rejection
  • Expiration: Auto-expire approved requests after N days
  • Bulk Actions: Approve/reject multiple requests at once
  • Analytics: Dashboard with request trends and conversion rates
  • Waitlist: Queue system when capacity is reached
  • OTP Confirmation: Require OTP for sensitive admin actions

Next Steps