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
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:
@@ -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 };
|
||||
}
|
||||
@@ -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
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user