9.3 KiB
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
-
Static Avatar Files: Three default avatars exist in
apps/website/public/images/avatars/:male-default-avatar.jpgfemale-default-avatar.jpegneutral-default-avatar.jpeg
-
Next.js Image Configuration:
apps/website/next.config.mjsis configured with:- Remote patterns for
localhost:3001(API) - Remote patterns for
api:3000(Docker API) - SVG support enabled
- Image optimization disabled in development
- Remote patterns for
-
Media Controller:
apps/api/src/domain/media/MediaController.tsalready generates SVG placeholders for:- Team logos (
/api/media/teams/:teamId/logo) - Driver avatars (
/api/media/drivers/:driverId/avatar) - League logos, covers, track images, etc.
- Team logos (
-
Current Seeding Logic:
SeedRacingData.tscallsseedMediaAssets()which sets URLs in the media repository.
Problems Identified
- Driver Avatars: Current seeding uses
/api/media/avatar/:driverIdwhich generates SVG placeholders, not static files - Team Logos: Current seeding uses
/api/media/teams/:teamId/logowhich generates SVG placeholders - InMemoryMediaRepository: Stores URLs but doesn't provide actual file serving
- 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
// 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
// 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:
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 tohttp://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:
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
- Start Docker development environment
- Trigger database seeding
- Verify driver avatars point to static files
- Verify team logos point to API routes
- 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
-
adapters/bootstrap/SeedRacingData.ts- Update
seedMediaAssets()method - Add
getDriverAvatarUrl()helper
- Update
-
adapters/racing/persistence/media/InMemoryMediaRepository.ts- Ensure methods exist for avatar/logo storage
-
apps/website/next.config.mjs- Verify configuration is correct for Docker
-
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.