diff --git a/databuild/dashboard/TYPE_SAFETY.md b/databuild/dashboard/TYPE_SAFETY.md new file mode 100644 index 0000000..be503d4 --- /dev/null +++ b/databuild/dashboard/TYPE_SAFETY.md @@ -0,0 +1,127 @@ +# Dashboard Type Safety Architecture + +## Overview + +This document describes the type safety architecture implemented in the DataBuild dashboard to prevent runtime errors from backend API changes. + +## Problem Statement + +The dashboard previously experienced runtime crashes when backend API changes were deployed: +- `status.toLowerCase()` failed when status changed from string to object +- `partition.str` access failed when partition structure changed +- TypeScript compilation passed but runtime errors occurred + +## Solution Architecture + +### 1. Dashboard Data Contracts + +We define stable TypeScript interfaces in `types.ts` that represent the data shapes the UI components expect: + +```typescript +export interface DashboardBuild { + build_request_id: string; + status: string; // Always a human-readable string + requested_partitions: string[]; // Always flat string array + // ... other fields +} +``` + +### 2. Transformation Layer + +The `services.ts` file contains transformation functions that convert OpenAPI-generated types to dashboard types: + +```typescript +function transformBuildSummary(apiResponse: BuildSummary): DashboardBuild { + return { + build_request_id: apiResponse.build_request_id, + status: apiResponse.status_name, // Extract string from API + requested_partitions: apiResponse.requested_partitions.map(p => p.str), // Flatten objects + // ... transform other fields + }; +} +``` + +### 3. Component Isolation + +All UI components use only dashboard types, never raw API types: + +```typescript +// GOOD: Using dashboard types +const build: DashboardBuild = await DashboardService.getBuildDetail(id); +m('div', build.status.toLowerCase()); // Safe - status is always string + +// BAD: Using API types directly +const build: BuildSummary = await apiClient.getBuild(id); +m('div', build.status.toLowerCase()); // Unsafe - status might be object +``` + +## Benefits + +1. **Compile-time Safety**: TypeScript catches type mismatches during development +2. **Runtime Protection**: Transformation functions handle API changes gracefully +3. **Clear Boundaries**: UI code is isolated from API implementation details +4. **Easier Updates**: API changes require updates only in transformation functions + +## Testing Strategy + +### Unit Tests +- `transformation-tests.ts`: Verify transformation functions produce correct dashboard types + +### Strict TypeScript Configuration +- `exactOptionalPropertyTypes`: Ensures optional properties are handled explicitly +- `strictNullChecks`: Prevents null/undefined errors +- `noImplicitAny`: Requires explicit typing + +## Maintenance Guidelines + +### When Backend API Changes + +1. Update the OpenAPI spec and regenerate client +2. TypeScript compilation will fail in transformation functions if types changed +3. Update only the transformation functions to handle new API shape +4. Run tests to verify UI components still work correctly + +### Adding New Features + +1. Define dashboard types in `types.ts` +2. Create transformation functions in `services.ts` +3. Use only dashboard types in components +4. Add tests for the transformation logic + +## Example: Handling API Evolution + +If the backend changes `status` from string to object: + +```typescript +// Old API +{ status_name: "COMPLETED" } + +// New API +{ status: { code: 4, name: "COMPLETED" } } + +// Transformation handles both +function transformBuildSummary(apiResponse: any): DashboardBuild { + return { + status: apiResponse.status_name || apiResponse.status?.name || 'UNKNOWN', + // ... other fields + }; +} +``` + +The UI components continue working without changes because they always receive the expected `string` type. + +## Monitoring + +To maintain type safety over time: + +1. **Build-time Checks**: TypeScript compilation catches type errors +2. **Test Suite**: Transformation tests run on every build +3. **Code Reviews**: Ensure new code follows the pattern +4. **Documentation**: Keep this document updated with patterns + +## Related Files + +- `types.ts` - Dashboard type definitions +- `services.ts` - API transformation functions +- `transformation-tests.ts` - Unit tests for transformations +- `tsconfig_app.json` - Strict TypeScript configuration \ No newline at end of file