Major Enhancement: NestJS Migration + CASL Authorization + Error Handling
Some checks failed
CI/CD Pipeline / Backend Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Tests (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (push) Has been cancelled
CI/CD Pipeline / Security Scan (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled

Complete rewrite from Express to NestJS with enterprise-grade features:

## Backend Improvements
- Migrated from Express to NestJS 11.0.1 with TypeScript
- Implemented Prisma ORM 7.3.0 for type-safe database access
- Added CASL authorization system replacing role-based guards
- Created global exception filters with structured logging
- Implemented Auth0 JWT authentication with Passport.js
- Added vehicle management with conflict detection
- Enhanced event scheduling with driver/vehicle assignment
- Comprehensive error handling and logging

## Frontend Improvements
- Upgraded to React 19.2.0 with Vite 7.2.4
- Implemented CASL-based permission system
- Added AbilityContext for declarative permissions
- Created ErrorHandler utility for consistent error messages
- Enhanced API client with request/response logging
- Added War Room (Command Center) dashboard
- Created VIP Schedule view with complete itineraries
- Implemented Vehicle Management UI
- Added mock data generators for testing (288 events across 20 VIPs)

## New Features
- Vehicle fleet management (types, capacity, status tracking)
- Complete 3-day Jamboree schedule generation
- Individual VIP schedule pages with PDF export (planned)
- Real-time War Room dashboard with auto-refresh
- Permission-based navigation filtering
- First user auto-approval as administrator

## Documentation
- Created CASL_AUTHORIZATION.md (comprehensive guide)
- Created ERROR_HANDLING.md (error handling patterns)
- Updated CLAUDE.md with new architecture
- Added migration guides and best practices

## Technical Debt Resolved
- Removed custom authentication in favor of Auth0
- Replaced role checks with CASL abilities
- Standardized error responses across API
- Implemented proper TypeScript typing
- Added comprehensive logging

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-31 08:50:25 +01:00
parent 8ace1ab2c1
commit 868f7efc23
351 changed files with 44997 additions and 6276 deletions

View File

@@ -1,56 +0,0 @@
import { useState, useEffect, useCallback } from 'react';
// Simple hook for API calls that handles loading, error, and data states
export function useApi<T>(
apiCall: () => Promise<T>,
dependencies: any[] = []
) {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const fetchData = useCallback(async () => {
try {
setLoading(true);
setError(null);
const result = await apiCall();
setData(result);
} catch (err) {
setError(err instanceof Error ? err.message : 'An error occurred');
setData(null);
} finally {
setLoading(false);
}
}, dependencies);
useEffect(() => {
fetchData();
}, [fetchData]);
return { data, loading, error, refetch: fetchData };
}
// Hook for mutations (POST, PUT, DELETE)
export function useMutation<TData = any, TVariables = any>(
mutationFn: (variables: TVariables) => Promise<TData>
) {
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const mutate = useCallback(async (variables: TVariables) => {
try {
setLoading(true);
setError(null);
const result = await mutationFn(variables);
return result;
} catch (err) {
const errorMessage = err instanceof Error ? err.message : 'An error occurred';
setError(errorMessage);
throw err;
} finally {
setLoading(false);
}
}, [mutationFn]);
return { mutate, loading, error };
}

View File

@@ -1,74 +0,0 @@
import { useState, useCallback } from 'react';
export interface ApiError {
message: string;
code?: string;
details?: unknown;
}
export const useError = () => {
const [error, setError] = useState<ApiError | null>(null);
const [isError, setIsError] = useState(false);
const clearError = useCallback(() => {
setError(null);
setIsError(false);
}, []);
const handleError = useCallback((error: unknown) => {
console.error('API Error:', error);
let apiError: ApiError;
if (error instanceof Error) {
// Check if it's our custom ApiError
if ('status' in error && 'code' in error) {
apiError = {
message: error.message,
code: (error as any).code,
details: (error as any).details
};
} else {
// Regular Error
apiError = {
message: error.message,
code: 'ERROR'
};
}
} else if (typeof error === 'object' && error !== null) {
// Check for axios-like error structure
const err = error as any;
if (err.response?.data?.error) {
apiError = {
message: err.response.data.error.message || err.response.data.error,
code: err.response.data.error.code,
details: err.response.data.error.details
};
} else {
apiError = {
message: 'An unexpected error occurred',
code: 'UNKNOWN_ERROR',
details: error
};
}
} else {
// Unknown error type
apiError = {
message: 'An unexpected error occurred',
code: 'UNKNOWN_ERROR'
};
}
setError(apiError);
setIsError(true);
return apiError;
}, []);
return {
error,
isError,
clearError,
handleError
};
};