LogoContainerPub

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:

{
  "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:

GET /api/admin/early-access-features

Get a specific flag:

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

Update a flag:

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

Get feature overview with stats:

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:

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

Get schema by UUID:

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

Get schemas by feature:

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

Create or update schema (upsert):

POST /api/admin/early-access-form-schemas
{
  "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:

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

Validate form data against schema:

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

Capacity Management#

The system enforces capacity limits:

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

Capacity Calculation:

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:

{
  "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:

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

Capacity Check: Fails if capacity limit reached.

Response:

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

Reject Request#

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

Request body:

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

Response:

{
  "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:

{
  "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:

{
  "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:

{
  "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:

{
  "capacity": 200
}

Updates the target_users value in the feature flag.

Response:

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

Toggle Feature Flag#

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

Request body:

{
  "enabled": false
}

Enables or disables early access registration globally.

Response:

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

Request Lifecycle#

┌─────────┐
│ 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#

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#

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#

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#

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

Best Practices#

Capacity Planning#

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

Request Review#

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

Feature Flag Management#

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

Troubleshooting#

Capacity Limit Reached#

Symptom: Approval requests fail with "Capacity limit reached"

Solution:

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

Feature Flag Not Working#

Symptom: Registration still accepts/rejects requests despite flag state

Solution:

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

Audit Logs Missing#

Symptom: No audit logs appear for actions

Solution:

  1. Check database table: SELECT * FROM early_access_audit_logs
  2. Verify admin principal is correctly extracted from token
  3. 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#