# Admin Feature Documentation

Complete reference for the admin role management, authorization, and cross-tenant oversight capabilities in MotoVaultPro.

## Overview

The admin feature provides role-based access control for system administrators to manage:
- Admin user accounts (create, revoke, reinstate)
- Vehicle catalog data (makes, models, years, trims, engines)
- Gas stations and user favorites
- Complete audit trail of all admin actions

## Architecture

### Backend Feature Capsule

Location: `backend/src/features/admin/`

Structure:
```
admin/
├── api/
│   ├── admin.controller.ts    - HTTP handlers for admin management
│   ├── admin.routes.ts        - Route registration
│   ├── admin.validation.ts    - Input validation schemas
│   ├── catalog.controller.ts  - Vehicle catalog handlers
│   └── stations.controller.ts - Station oversight handlers
├── domain/
│   ├── admin.types.ts         - TypeScript type definitions
│   ├── admin.service.ts       - Admin user management logic
│   ├── vehicle-catalog.service.ts - Catalog CRUD logic
│   └── station-oversight.service.ts - Station management logic
├── data/
│   └── admin.repository.ts    - Database access layer
├── migrations/
│   ├── 001_create_admin_users.sql         - Admin tables and seed
│   └── 002_create_platform_change_log.sql - Catalog audit log
└── tests/
    ├── unit/                  - Service and guard tests
    ├── integration/           - Full API endpoint tests
    └── fixtures/              - Test data
```

### Core Plugins

- **auth.plugin.ts**: Enhanced with `request.userContext` containing `userId`, `email`, `isAdmin`, `adminRecord`
- **admin-guard.plugin.ts**: `fastify.requireAdmin` preHandler that checks `admin_users` table and enforces 403 on non-admins

### Frontend Feature

Location: `frontend/src/features/admin/`

Structure:
```
admin/
├── types/admin.types.ts         - TypeScript types (mirroring backend)
├── api/admin.api.ts             - API client functions
├── hooks/
│   ├── useAdminAccess.ts        - Verify admin status
│   ├── useAdmins.ts             - Admin user management
│   ├── useCatalog.ts            - Vehicle catalog
│   └── useStationOverview.ts    - Station management
├── pages/
│   ├── AdminUsersPage.tsx       - Desktop user management
│   ├── AdminCatalogPage.tsx     - Desktop catalog management
│   └── AdminStationsPage.tsx    - Desktop station management
├── mobile/
│   ├── AdminUsersMobileScreen.tsx    - Mobile user management
│   ├── AdminCatalogMobileScreen.tsx  - Mobile catalog management
│   └── AdminStationsMobileScreen.tsx - Mobile station management
└── __tests__/                   - Component and hook tests
```

## Database Schema

### admin_users table

```sql
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
);
```

**Indexes:**
- `auth0_sub` (PRIMARY KEY) - OAuth ID from Auth0
- `email` - For admin lookups by email
- `created_at` - For audit trails
- `revoked_at` - For active admin queries

### admin_audit_logs table

```sql
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
);
```

**Actions logged:**
- CREATE - New admin or resource created
- UPDATE - Resource updated
- DELETE - Resource deleted
- REVOKE - Admin access revoked
- REINSTATE - Admin access restored
- VIEW - Data accessed (for sensitive operations)

### platform_change_log table

```sql
CREATE TABLE platform_change_log (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  change_type VARCHAR(50) NOT NULL,
  resource_type VARCHAR(100) NOT NULL,
  resource_id VARCHAR(255),
  old_value JSONB,
  new_value JSONB,
  changed_by VARCHAR(255) NOT NULL,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
```

**Resource types:**
- makes, models, years, trims, engines
- stations
- users

## API Reference

### Phase 2: Admin Management

#### List all admins
```
GET /api/admin/admins
Authorization: Bearer <JWT>
Guard: fastify.requireAdmin

Response (200):
{
  "total": 2,
  "admins": [
    {
      "auth0Sub": "auth0|admin1",
      "email": "admin@motovaultpro.com",
      "role": "admin",
      "createdAt": "2024-01-01T00:00:00Z",
      "createdBy": "system",
      "revokedAt": null,
      "updatedAt": "2024-01-01T00:00:00Z"
    }
  ]
}
```

#### Create admin
```
POST /api/admin/admins
Authorization: Bearer <JWT>
Guard: fastify.requireAdmin
Content-Type: application/json

Request:
{
  "email": "newadmin@example.com",
  "role": "admin"
}

Response (201):
{
  "auth0Sub": "auth0|newadmin",
  "email": "newadmin@example.com",
  "role": "admin",
  "createdAt": "2024-01-15T10:30:00Z",
  "createdBy": "auth0|existing",
  "revokedAt": null,
  "updatedAt": "2024-01-15T10:30:00Z"
}

Audit log entry:
{
  "actor_admin_id": "auth0|existing",
  "target_admin_id": "auth0|newadmin",
  "action": "CREATE",
  "resource_type": "admin_user",
  "resource_id": "newadmin@example.com",
  "context": { "email": "newadmin@example.com", "role": "admin" }
}
```

#### Revoke admin
```
PATCH /api/admin/admins/:auth0Sub/revoke
Authorization: Bearer <JWT>
Guard: fastify.requireAdmin

Response (200):
{
  "auth0Sub": "auth0|toadmin",
  "email": "admin@motovaultpro.com",
  "role": "admin",
  "createdAt": "2024-01-01T00:00:00Z",
  "createdBy": "system",
  "revokedAt": "2024-01-15T10:35:00Z",
  "updatedAt": "2024-01-15T10:35:00Z"
}

Errors:
- 400 Bad Request - Last active admin (cannot revoke)
- 403 Forbidden - Not an admin
- 404 Not Found - Admin not found
```

#### Reinstate admin
```
PATCH /api/admin/admins/:auth0Sub/reinstate
Authorization: Bearer <JWT>
Guard: fastify.requireAdmin

Response (200):
{
  "auth0Sub": "auth0|toadmin",
  "email": "admin@motovaultpro.com",
  "role": "admin",
  "createdAt": "2024-01-01T00:00:00Z",
  "createdBy": "system",
  "revokedAt": null,
  "updatedAt": "2024-01-15T10:40:00Z"
}
```

#### Audit logs
```
GET /api/admin/audit-logs?limit=100&offset=0
Authorization: Bearer <JWT>
Guard: fastify.requireAdmin

Response (200):
{
  "total": 150,
  "logs": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "actor_admin_id": "auth0|admin1",
      "target_admin_id": "auth0|admin2",
      "action": "CREATE",
      "resource_type": "admin_user",
      "resource_id": "admin2@motovaultpro.com",
      "context": { "email": "admin2@motovaultpro.com", "role": "admin" },
      "created_at": "2024-01-15T10:30:00Z"
    }
  ]
}
```

### Phase 3: Catalog CRUD

All catalog endpoints follow RESTful patterns:

```
GET    /api/admin/catalog/{resource}           - List all
GET    /api/admin/catalog/{parent}/{parentId}/{resource} - List by parent
POST   /api/admin/catalog/{resource}           - Create
PUT    /api/admin/catalog/{resource}/:id       - Update
DELETE /api/admin/catalog/{resource}/:id       - Delete
```

**Resources:** makes, models, years, trims, engines

**Example: Get all makes**
```
GET /api/admin/catalog/makes
Guard: fastify.requireAdmin

Response (200):
{
  "total": 42,
  "makes": [
    { "id": "1", "name": "Toyota", "createdAt": "...", "updatedAt": "..." },
    { "id": "2", "name": "Honda", "createdAt": "...", "updatedAt": "..." }
  ]
}
```

**Cache invalidation:** All mutations invalidate `platform:*` Redis keys

**Audit trail:** All mutations recorded in `platform_change_log` with old and new values

### Phase 4: Station Oversight

#### List all stations
```
GET /api/admin/stations?limit=100&offset=0&search=query
Guard: fastify.requireAdmin

Response (200):
{
  "total": 1250,
  "stations": [
    {
      "id": "station-1",
      "placeId": "ChIJxxx",
      "name": "Shell Station Downtown",
      "address": "123 Main St",
      "latitude": 40.7128,
      "longitude": -74.0060,
      "createdAt": "...",
      "deletedAt": null
    }
  ]
}
```

#### Create station
```
POST /api/admin/stations
Guard: fastify.requireAdmin
Content-Type: application/json

Request:
{
  "placeId": "ChIJxxx",
  "name": "New Station",
  "address": "456 Oak Ave",
  "latitude": 40.7580,
  "longitude": -73.9855
}

Response (201): Station object with all fields

Cache invalidation:
- mvp:stations:* - All station caches
- mvp:stations:search:* - Search result caches
```

#### Delete station (soft or hard)
```
DELETE /api/admin/stations/:stationId?force=false
Guard: fastify.requireAdmin

Query parameters:
- force=false (default) - Soft delete (set deleted_at)
- force=true - Hard delete (permanent removal)

Response (204 No Content)
```

#### User station management
```
GET /api/admin/users/:userId/stations
Guard: fastify.requireAdmin

Response (200):
{
  "userId": "auth0|user123",
  "stations": [...]
}
```

## Authorization Rules

### Admin Guard

The `fastify.requireAdmin` preHandler enforces:

1. **JWT validation** - User must be authenticated
2. **Admin check** - User must exist in `admin_users` table
3. **Active status** - User's `revoked_at` must be NULL
4. **Error response** - Returns 403 Forbidden with message "Admin access required"

### Last Admin Protection

The system maintains at least one active admin:
- Cannot revoke the last active admin (returns 400 Bad Request)
- Prevents system lockout
- Enforced in `AdminService.revokeAdmin()`

### Audit Trail

All admin actions logged:
- Actor admin ID (who performed action)
- Target admin ID (who was affected, if applicable)
- Action type (CREATE, UPDATE, DELETE, REVOKE, REINSTATE)
- Resource type and ID
- Context (relevant data, like old/new values)
- Timestamp

## Security Considerations

### Input Validation

All inputs validated using Zod schemas:
- Email format and uniqueness
- Role enum validation
- Required field presence
- Type checking

### Parameterized Queries

All database operations use parameterized queries:
```typescript
// Good - Parameterized
const result = await pool.query(
  'SELECT * FROM admin_users WHERE email = $1',
  [email]
);

// Bad - SQL concatenation (never done)
const result = await pool.query(
  `SELECT * FROM admin_users WHERE email = '${email}'`
);
```

### Transaction Support

Catalog mutations wrapped in transactions:
```sql
BEGIN;
-- INSERT/UPDATE/DELETE operations
COMMIT;  -- or ROLLBACK on error
```

### Cache Invalidation

Prevents stale data:
- All catalog mutations invalidate `platform:*` keys
- All station mutations invalidate `mvp:stations:*` keys
- User station mutations invalidate `mvp:stations:saved:{userId}`

## Deployment

### Prerequisites

1. **Database migrations** - Run all migrations before deploying
2. **Initial admin** - First admin seeded automatically in migration
3. **Auth0 configuration** - Admin user must exist in Auth0

### Deployment Steps

```bash
# 1. Build containers
make rebuild

# 2. Run migrations (automatically on startup)
docker compose exec mvp-backend npm run migrate

# 3. Verify admin user created
docker compose exec mvp-backend npm run verify-admin

# 4. Check backend health
curl https://motovaultpro.com/api/health

# 5. Verify frontend build
curl https://motovaultpro.com
```

### Rollback

If issues occur:

```bash
# Revoke problematic admin
docker compose exec mvp-backend npm run admin:revoke admin@motovaultpro.com

# Reinstate previous admin
docker compose exec mvp-backend npm run admin:reinstate <auth0_sub>

# Downgrade admin feature (keep data)
docker compose down
git checkout previous-version
make rebuild
make start
```

## Testing

### Backend Unit Tests

Location: `backend/src/features/admin/tests/unit/`

```bash
npm test -- features/admin/tests/unit
```

Tests:
- Admin guard authorization logic
- Admin service business rules
- Repository error handling
- Last admin protection

### Backend Integration Tests

Location: `backend/src/features/admin/tests/integration/`

```bash
npm test -- features/admin/tests/integration
```

Tests:
- Full API endpoints
- Database persistence
- Audit logging
- Admin guard in request context
- CRUD operations
- Cache invalidation
- Permission enforcement

### Frontend Tests

Location: `frontend/src/features/admin/__tests__/`

```bash
docker compose exec mvp-frontend npm test
```

Tests:
- useAdminAccess hook (loading, admin, non-admin, error states)
- Admin page rendering
- Admin route guards
- Navigation

### E2E Testing

1. **Desktop workflow**
   - Navigate to `/garage/settings`
   - Verify "Admin Console" card visible (if admin)
   - Click "User Management"
   - Verify admin list loads
   - Try to create new admin (if permitted)

2. **Mobile workflow**
   - Open app on mobile viewport (375px)
   - Navigate to settings
   - Verify admin section visible (if admin)
   - Tap "Users" button
   - Verify admin list loads

## Monitoring & Troubleshooting

### Common Issues

**Issue: "Admin access required" (403 Forbidden)**
- Verify user in `admin_users` table
- Check `revoked_at` is NULL
- Verify JWT token valid
- Check Auth0 configuration

**Issue: Stale catalog data**
- Verify Redis is running
- Check cache invalidation logs
- Manually flush: `redis-cli DEL 'mvp:platform:*'`

**Issue: Audit log not recording**
- Check `admin_audit_logs` table exists
- Verify migrations ran
- Check database connection

### Logs

View admin-related logs:

```bash
# Backend logs
make logs | grep -i admin

# Check specific action
docker compose exec mvp-backend psql -U postgres -d motovaultpro \
  -c "SELECT * FROM admin_audit_logs WHERE action = 'CREATE' ORDER BY created_at DESC LIMIT 10;"

# Check revoked admins
docker compose exec mvp-backend psql -U postgres -d motovaultpro \
  -c "SELECT email, revoked_at FROM admin_users WHERE revoked_at IS NOT NULL;"
```

## Next Steps

### Planned Enhancements

1. **Role-based permissions** - Extend from binary admin to granular roles (admin, catalog_editor, station_manager)
2. **2FA for admins** - Enhanced security with two-factor authentication
3. **Admin impersonation** - Test user issues as admin without changing password
4. **Bulk operations** - Import/export catalog data
5. **Advanced analytics** - Admin activity dashboards

## References

- Backend feature: `backend/src/features/admin/README.md`
- Frontend feature: `frontend/src/features/admin/` (see individual files)
- Architecture: `docs/PLATFORM-SERVICES.md`
- Testing: `docs/TESTING.md`
