seed data
This commit is contained in:
268
plans/media-seeding-plan.md
Normal file
268
plans/media-seeding-plan.md
Normal file
@@ -0,0 +1,268 @@
|
||||
# Media Seeding Plan for Team Logos and Driver Avatars
|
||||
|
||||
## Executive Summary
|
||||
|
||||
This plan addresses the robust seeding of media assets (driver avatars and team logos) in the GridPilot development environment. The solution leverages existing static files for avatars and provides a reliable, Docker-compatible approach for team logos using Next.js API routes that serve SVG placeholders.
|
||||
|
||||
## Current State Analysis
|
||||
|
||||
### What Exists
|
||||
1. **Static Avatar Files**: Three default avatars exist in `apps/website/public/images/avatars/`:
|
||||
- `male-default-avatar.jpg`
|
||||
- `female-default-avatar.jpeg`
|
||||
- `neutral-default-avatar.jpeg`
|
||||
|
||||
2. **Next.js Image Configuration**: `apps/website/next.config.mjs` is configured with:
|
||||
- Remote patterns for `localhost:3001` (API)
|
||||
- Remote patterns for `api:3000` (Docker API)
|
||||
- SVG support enabled
|
||||
- Image optimization disabled in development
|
||||
|
||||
3. **Media Controller**: `apps/api/src/domain/media/MediaController.ts` already generates SVG placeholders for:
|
||||
- Team logos (`/api/media/teams/:teamId/logo`)
|
||||
- Driver avatars (`/api/media/drivers/:driverId/avatar`)
|
||||
- League logos, covers, track images, etc.
|
||||
|
||||
4. **Current Seeding Logic**: `SeedRacingData.ts` calls `seedMediaAssets()` which sets URLs in the media repository.
|
||||
|
||||
### Problems Identified
|
||||
1. **Driver Avatars**: Current seeding uses `/api/media/avatar/:driverId` which generates SVG placeholders, not static files
|
||||
2. **Team Logos**: Current seeding uses `/api/media/teams/:teamId/logo` which generates SVG placeholders
|
||||
3. **InMemoryMediaRepository**: Stores URLs but doesn't provide actual file serving
|
||||
4. **No Static File Integration**: The existing static avatars aren't being used in seeding
|
||||
|
||||
## Solution Design
|
||||
|
||||
### 1. Driver Avatars Strategy (Static Files)
|
||||
|
||||
**Goal**: Use existing static avatar files for all seeded drivers.
|
||||
|
||||
**Implementation**:
|
||||
|
||||
#### A. Enhanced Driver Seeding Logic
|
||||
```typescript
|
||||
// In adapters/bootstrap/SeedRacingData.ts - seedMediaAssets() method
|
||||
private async seedMediaAssets(seed: any): Promise<void> {
|
||||
const baseUrl = this.getMediaBaseUrl();
|
||||
|
||||
// Seed driver avatars using static files
|
||||
for (const driver of seed.drivers) {
|
||||
const avatarUrl = this.getDriverAvatarUrl(driver.id);
|
||||
|
||||
const mediaRepo = this.seedDeps.mediaRepository as any;
|
||||
if (mediaRepo.setDriverAvatar) {
|
||||
mediaRepo.setDriverAvatar(driver.id, avatarUrl);
|
||||
}
|
||||
}
|
||||
|
||||
// ... rest of seeding
|
||||
}
|
||||
|
||||
private getDriverAvatarUrl(driverId: string): string {
|
||||
// Use deterministic selection based on driver ID
|
||||
const numericSuffixMatch = driverId.match(/(\d+)$/);
|
||||
let useFemale = false;
|
||||
|
||||
if (numericSuffixMatch) {
|
||||
const numericSuffix = parseInt(numericSuffixMatch[1], 10);
|
||||
useFemale = numericSuffix % 2 === 0;
|
||||
} else {
|
||||
// Fallback hash
|
||||
let hash = 0;
|
||||
for (let i = 0; i < driverId.length; i++) {
|
||||
hash = (hash * 31 + driverId.charCodeAt(i)) | 0;
|
||||
}
|
||||
useFemale = Math.abs(hash) % 2 === 0;
|
||||
}
|
||||
|
||||
// Return static file paths that Next.js can serve
|
||||
if (useFemale) {
|
||||
return '/images/avatars/female-default-avatar.jpeg';
|
||||
} else {
|
||||
return '/images/avatars/male-default-avatar.jpg';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### B. Next.js Static File Serving
|
||||
The existing Next.js configuration already supports serving static files from `public/images/avatars/`. These URLs will work directly from the website container.
|
||||
|
||||
### 2. Team Logos Strategy (SVG Generation)
|
||||
|
||||
**Goal**: Provide reliable, Docker-compatible team logos that work without external dependencies.
|
||||
|
||||
**Implementation**:
|
||||
|
||||
#### A. Enhanced Team Seeding Logic
|
||||
```typescript
|
||||
// In adapters/bootstrap/SeedRacingData.ts - seedMediaAssets() method
|
||||
// Seed team logos
|
||||
for (const team of seed.teams) {
|
||||
const logoUrl = `${baseUrl}/api/media/teams/${team.id}/logo`;
|
||||
|
||||
const mediaRepo = this.seedDeps.mediaRepository as any;
|
||||
if (mediaRepo.setTeamLogo) {
|
||||
mediaRepo.setTeamLogo(team.id, logoUrl);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### B. API Route Enhancement
|
||||
The existing `MediaController.ts` already provides `/api/media/teams/:teamId/logo` which generates SVG placeholders. This is perfect for Docker development because:
|
||||
- No external network dependencies
|
||||
- Deterministic generation based on team ID
|
||||
- Works in Docker containers
|
||||
- Served via the API container (port 3001)
|
||||
|
||||
#### C. Next.js Rewrites Configuration
|
||||
The existing `next.config.mjs` already has rewrites that route `/api/*` to the API container:
|
||||
```javascript
|
||||
async rewrites() {
|
||||
const baseUrl = 'http://api:3000';
|
||||
return [
|
||||
{
|
||||
source: '/api/:path*',
|
||||
destination: `${baseUrl}/:path*`,
|
||||
},
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
This means:
|
||||
- Website requests `/api/media/teams/team-1/logo` → Next.js rewrites to `http://api:3000/api/media/teams/team-1/logo`
|
||||
- API serves SVG placeholder
|
||||
- Next.js Image component can optimize/cache it
|
||||
|
||||
### 3. Architecture Flow
|
||||
|
||||
```
|
||||
Seeding Phase:
|
||||
1. SeedRacingData.execute() creates drivers/teams
|
||||
2. seedMediaAssets() calculates URLs
|
||||
3. InMemoryMediaRepository stores: driverId → avatarUrl, teamId → logoUrl
|
||||
4. URLs are stored in database entities
|
||||
|
||||
Runtime Phase (Website):
|
||||
1. Component requests driver avatar: `/images/avatars/male-default-avatar.jpg`
|
||||
2. Next.js serves static file directly from public directory
|
||||
|
||||
Runtime Phase (Team Logo):
|
||||
1. Component requests team logo: `/api/media/teams/team-1/logo`
|
||||
2. Next.js rewrite: → `http://api:3000/api/media/teams/team-1/logo`
|
||||
3. API generates SVG and returns
|
||||
4. Next.js Image component optimizes/caches
|
||||
```
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
### Step 1: Update SeedRacingData.ts
|
||||
Modify the `seedMediaAssets()` method to use static files for drivers and existing API routes for teams.
|
||||
|
||||
### Step 2: Update InMemoryMediaRepository
|
||||
Ensure it has methods for storing/retrieving media URLs:
|
||||
```typescript
|
||||
setDriverAvatar(driverId: string, url: string): void;
|
||||
setTeamLogo(teamId: string, url: string): void;
|
||||
getDriverAvatar(driverId: string): Promise<string | null>;
|
||||
getTeamLogo(teamId: string): Promise<string | null>;
|
||||
```
|
||||
|
||||
### Step 3: Verify Next.js Configuration
|
||||
Ensure `next.config.mjs` has:
|
||||
- Proper remote patterns for localhost and Docker API
|
||||
- SVG support enabled
|
||||
- Image optimization disabled in dev
|
||||
|
||||
### Step 4: Test the Flow
|
||||
1. Start Docker development environment
|
||||
2. Trigger database seeding
|
||||
3. Verify driver avatars point to static files
|
||||
4. Verify team logos point to API routes
|
||||
5. Test that URLs resolve correctly in website
|
||||
|
||||
## Benefits of This Approach
|
||||
|
||||
### Reliability
|
||||
- **No external dependencies**: No network calls to external services
|
||||
- **Docker-compatible**: Works entirely within Docker network
|
||||
- **Deterministic**: Same IDs always produce same URLs
|
||||
|
||||
### Performance
|
||||
- **Fast**: Static files served directly, SVG generated on-demand
|
||||
- **Cached**: Next.js can cache API responses
|
||||
- **No cold starts**: No external service initialization needed
|
||||
|
||||
### Maintainability
|
||||
- **Clean architecture**: Follows existing patterns
|
||||
- **Testable**: Easy to verify URLs are correct
|
||||
- **Extensible**: Can add more media types easily
|
||||
|
||||
### Developer Experience
|
||||
- **Simple**: No API keys or external services to configure
|
||||
- **Fast**: No waiting for external API responses
|
||||
- **Offline-capable**: Works without internet connection
|
||||
|
||||
## Risk Mitigation
|
||||
|
||||
### Risk: Static files not accessible in Docker
|
||||
**Mitigation**: Files are in `apps/website/public/images/avatars/` which is mounted via volumes in docker-compose.dev.yml
|
||||
|
||||
### Risk: API routes not working in Docker
|
||||
**Mitigation**: Next.js rewrites already route `/api/*` to `http://api:3000` which is the Docker API service
|
||||
|
||||
### Risk: Image optimization fails
|
||||
**Mitigation**: Set `unoptimized: true` in development, which is already configured
|
||||
|
||||
### Risk: URLs don't match between seeding and runtime
|
||||
**Mitigation**: Use consistent URL generation logic in both seeding and display components
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Unit Tests
|
||||
- Verify `getDriverAvatarUrl()` returns correct static file paths
|
||||
- Verify `seedMediaAssets()` calls repository methods correctly
|
||||
|
||||
### Integration Tests
|
||||
- Verify seeding creates correct URLs in database
|
||||
- Verify API routes return SVG for team logos
|
||||
- Verify static files are accessible via Next.js
|
||||
|
||||
### E2E Tests
|
||||
- Load dashboard page
|
||||
- Verify driver avatars display correctly
|
||||
- Verify team logos display correctly
|
||||
- Verify no console errors for missing images
|
||||
|
||||
## Files to Modify
|
||||
|
||||
1. **`adapters/bootstrap/SeedRacingData.ts`**
|
||||
- Update `seedMediaAssets()` method
|
||||
- Add `getDriverAvatarUrl()` helper
|
||||
|
||||
2. **`adapters/racing/persistence/media/InMemoryMediaRepository.ts`**
|
||||
- Ensure methods exist for avatar/logo storage
|
||||
|
||||
3. **`apps/website/next.config.mjs`**
|
||||
- Verify configuration is correct for Docker
|
||||
|
||||
4. **`docker-compose.dev.yml`**
|
||||
- Ensure volumes mount public directory
|
||||
|
||||
## Success Criteria
|
||||
|
||||
✅ Every driver has an avatar URL pointing to static files
|
||||
✅ Every team has a logo URL pointing to API routes
|
||||
✅ URLs work in Docker development environment
|
||||
✅ No external network dependencies required
|
||||
✅ Images display correctly in website UI
|
||||
✅ Seeding is deterministic and reproducible
|
||||
|
||||
## Conclusion
|
||||
|
||||
This plan provides a robust, Docker-compatible solution for media seeding that leverages existing infrastructure:
|
||||
- **Driver avatars**: Static files for reliability and speed
|
||||
- **Team logos**: SVG generation for consistency and no external dependencies
|
||||
- **Architecture**: Follows clean architecture principles
|
||||
- **Docker support**: Works seamlessly in containerized development
|
||||
|
||||
The solution is simple, maintainable, and addresses all the constraints mentioned in the task.
|
||||
Reference in New Issue
Block a user