Files
motovaultpro/backend/src/features/admin
Eric Gullickson 4fc5b391e1
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 4m34s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 37s
Deploy to Staging / Verify Staging (pull_request) Successful in 6s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 6s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
feat: Add admin vehicle management and profile vehicles display (refs #11)
- Add GET /api/admin/stats endpoint for Total Vehicles widget
- Add GET /api/admin/users/:auth0Sub/vehicles endpoint for user vehicle list
- Update AdminUsersPage with Total Vehicles stat and expandable vehicle rows
- Add My Vehicles section to SettingsPage (desktop) and MobileSettingsScreen
- Update AdminUsersMobileScreen with stats header and vehicle expansion
- Add defense-in-depth admin checks and error handling
- Update admin README documentation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 13:18:38 -06:00
..
2025-12-21 19:56:52 -06:00
2025-12-22 21:34:05 -06:00

Admin Feature

Self-contained feature capsule for MotoVaultPro admin role and access control management.

Architecture

admin/
├── api/
│   ├── admin.controller.ts    # HTTP request handlers
│   └── admin.routes.ts        # Route registration
├── domain/
│   ├── admin.types.ts         # TypeScript interfaces
│   └── admin.service.ts       # Business logic
├── data/
│   └── admin.repository.ts    # Database access (parameterized queries)
├── migrations/
│   └── 001_create_admin_users.sql  # Database schema
└── tests/
    ├── unit/                  # Service/guard tests
    └── integration/           # API endpoint tests

Database Schema

admin_users table

CREATE TABLE admin_users (
  auth0_sub VARCHAR(255) PRIMARY KEY,
  email VARCHAR(255) NOT NULL UNIQUE,
  role VARCHAR(50) NOT NULL DEFAULT 'admin',
  created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
  created_by VARCHAR(255) NOT NULL,
  revoked_at TIMESTAMP WITH TIME ZONE,
  updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);

admin_audit_logs table

CREATE TABLE admin_audit_logs (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  actor_admin_id VARCHAR(255) NOT NULL,
  target_admin_id VARCHAR(255),
  action VARCHAR(100) NOT NULL,
  resource_type VARCHAR(100),
  resource_id VARCHAR(255),
  context JSONB,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);

Usage

Phase 1: Access Control Foundations

Provides:

  • AdminRepository - Database access with parameterized queries
  • AdminService - Business logic for admin operations
  • admin-guard plugin - Authorization enforcement (decorator on Fastify)
  • request.userContext - Enhanced with isAdmin, adminRecord

Admin Dashboard Stats

Provides admin dashboard statistics:

  • GET /api/admin/stats - Get total users and vehicles counts

Response:

{
  "totalUsers": 150,
  "totalVehicles": 287
}

User Management APIs

Provides:

  • GET /api/admin/users - List all users with pagination/filters
  • GET /api/admin/users/:auth0Sub - Get single user details
  • GET /api/admin/users/:auth0Sub/vehicles - Get user's vehicles (admin view)
  • PATCH /api/admin/users/:auth0Sub/tier - Update subscription tier
  • PATCH /api/admin/users/:auth0Sub/deactivate - Deactivate user
  • PATCH /api/admin/users/:auth0Sub/reactivate - Reactivate user
  • PATCH /api/admin/users/:auth0Sub/profile - Update user profile
  • PATCH /api/admin/users/:auth0Sub/promote - Promote to admin
  • DELETE /api/admin/users/:auth0Sub - Hard delete user (GDPR)

User Vehicles Endpoint:

GET /api/admin/users/:auth0Sub/vehicles

Returns minimal vehicle data for privacy (Year/Make/Model only):

{
  "vehicles": [
    { "year": 2022, "make": "Toyota", "model": "Camry" },
    { "year": 2020, "make": "Honda", "model": "Civic" }
  ]
}

Admin Management APIs

Provides:

  • GET /api/admin/admins - List all admins
  • POST /api/admin/admins - Add admin
  • PATCH /api/admin/admins/:auth0Sub/revoke - Revoke admin
  • PATCH /api/admin/admins/:auth0Sub/reinstate - Reinstate admin
  • GET /api/admin/audit-logs - View audit trail

Phase 3: Platform Catalog CRUD (COMPLETED)

Provides complete CRUD operations for platform vehicle catalog data:

Makes:

  • GET /api/admin/catalog/makes - List all makes
  • POST /api/admin/catalog/makes - Create new make
  • PUT /api/admin/catalog/makes/:makeId - Update make
  • DELETE /api/admin/catalog/makes/:makeId - Delete make

Models:

  • GET /api/admin/catalog/makes/:makeId/models - List models for a make
  • POST /api/admin/catalog/models - Create new model
  • PUT /api/admin/catalog/models/:modelId - Update model
  • DELETE /api/admin/catalog/models/:modelId - Delete model

Years:

  • GET /api/admin/catalog/models/:modelId/years - List years for a model
  • POST /api/admin/catalog/years - Create new year
  • PUT /api/admin/catalog/years/:yearId - Update year
  • DELETE /api/admin/catalog/years/:yearId - Delete year

Trims:

  • GET /api/admin/catalog/years/:yearId/trims - List trims for a year
  • POST /api/admin/catalog/trims - Create new trim
  • PUT /api/admin/catalog/trims/:trimId - Update trim
  • DELETE /api/admin/catalog/trims/:trimId - Delete trim

Engines:

  • GET /api/admin/catalog/trims/:trimId/engines - List engines for a trim
  • POST /api/admin/catalog/engines - Create new engine
  • PUT /api/admin/catalog/engines/:engineId - Update engine
  • DELETE /api/admin/catalog/engines/:engineId - Delete engine

Change Logs:

  • GET /api/admin/catalog/change-logs?limit=100&offset=0 - Retrieve platform catalog change history

Features:

  • All mutations wrapped in database transactions
  • Automatic cache invalidation (platform:* keys)
  • Complete audit trail in platform_change_log table
  • Referential integrity validation (prevents orphan deletions)
  • requireAdmin guard on all endpoints

Phase 4: Station Oversight

Provides:

  • GET /api/admin/stations - List all stations globally with pagination and search
  • POST /api/admin/stations - Create new station
  • PUT /api/admin/stations/:stationId - Update station details
  • DELETE /api/admin/stations/:stationId - Delete station (soft delete by default, ?force=true for hard delete)
  • GET /api/admin/users/:userId/stations - List user's saved stations
  • DELETE /api/admin/users/:userId/stations/:stationId - Remove user's saved station (soft delete by default, ?force=true for hard delete)

All station mutations invalidate related Redis caches and log audit trails.

Extending the Feature

Adding a new admin endpoint

  1. Add handler method to AdminController
  2. Register route in admin.routes.ts with app.requireAdmin guard
  3. Add service method if business logic needed
  4. Add repository method for database operations

Example:

// In admin.routes.ts
fastify.get('/admin/users', {
  preHandler: [fastify.requireAdmin]
}, adminController.getUsers.bind(adminController));

// In AdminController
async getUsers(request: FastifyRequest, reply: FastifyReply) {
  const actorId = request.userContext?.userId;
  const users = await this.adminService.getAllUsers();
  return reply.code(200).send(users);
}

// Audit logging
await this.adminService.logAuditAction(actorId, 'VIEW', null, 'users');

Security Considerations

  1. Admin Guard: All admin endpoints require preHandler: [fastify.requireAdmin]
  2. Parameterized Queries: All database operations use parameterized queries (no SQL concatenation)
  3. Audit Logging: All sensitive actions logged with actor, target, action, and context
  4. Last Admin Protection: Cannot revoke the last active admin
  5. Soft Deletes: Admins are soft-deleted (revoked_at), never hard-deleted

Testing

Unit tests (no database)

npm test -- features/admin/tests/unit

Tests:

  • Admin guard authorization logic
  • Admin service business rules
  • Repository error handling

Integration tests (with database)

npm test -- features/admin/tests/integration

Tests:

  • Full API endpoints
  • Database persistence
  • Audit logging
  • Admin guard in request context

Migrations

Run migrations during container startup:

docker compose exec mvp-backend npm run migrate

Initial seed: First admin user is seeded in migration with:

  • auth0_sub: system|bootstrap
  • email: admin@motovaultpro.com
  • role: admin