seed data

This commit is contained in:
2025-12-30 00:15:35 +01:00
parent 7a853d4e43
commit ccaa39c39c
22 changed files with 1342 additions and 173 deletions

115
plans/seeds-plan.md Normal file
View File

@@ -0,0 +1,115 @@
# Comprehensive Seeding Plan for GridPilot
## Current Seeding Setup
Current seeding in [`adapters/bootstrap`](adapters/bootstrap) includes:
- `EnsureInitialData.ts`: Creates admin user (`admin@gridpilot.local` / `admin123`) and all achievements (driver, steward, admin, community).
- `SeedRacingData.ts`: If no drivers exist, seeds ~100 drivers, 20 leagues, seasons, teams, races, results, standings, memberships, join requests, protests, penalties, sponsors, wallets/transactions, social feed/friendships using factories in `bootstrap/racing/`.
Seeding skips if data exists (idempotent), uses seed IDs for determinism (e.g., `seedId('league-1', persistence)`).
Persistence-aware (inmemory/postgres), ensures scoring configs for existing data.
## Identified Entities
From `core/*/domain/entities/` and factories/repositories:
### Identity Domain
- [`User`](core/identity/domain/entities/User.ts)
- [`Achievement`](core/identity/domain/entities/Achievement.ts)
- [`UserAchievement`](core/identity/domain/entities/UserAchievement.ts)
- [`SponsorAccount`](core/identity/domain/entities/SponsorAccount.ts)
- [`ExternalGameRatingProfile`](core/identity/domain/entities/ExternalGameRatingProfile.ts)
- [`RatingEvent`](core/identity/domain/entities/RatingEvent.ts)
- [`AdminVoteSession`](core/identity/domain/entities/AdminVoteSession.ts)
### Racing Domain (primary, most seeded)
- [`Driver`](core/racing/domain/entities/Driver.ts): id, iracingId, name, country, bio?, joinedAt
- [`League`](core/racing/domain/entities/League.ts): id, name, description, ownerId, settings (pointsSystem enum ['f1-2024','indycar','custom'], sessionDuration, qualifyingFormat enum, maxDrivers, visibility enum ['ranked','unranked'], stewarding config), createdAt, socialLinks?, participantCount (0-max)
- [`Season`](core/racing/domain/entities/season/Season.ts): id, leagueId, gameId, name, year?, order?, status enum ['planned','active','completed','archived','cancelled'], start/endDate?, schedule?, schedulePublished bool, scoringConfig?, dropPolicy?, stewardingConfig?, maxDrivers?, participantCount
- [`Team`](core/racing/domain/entities/Team.ts): id, name, tag, description, ownerId (DriverId), leagues[], createdAt
- [`Standing`](core/racing/domain/entities/Standing.ts): id (leagueId:driverId), leagueId, driverId, points, wins, position, racesCompleted
- Race-related: [`Race`](core/racing/domain/entities/Race.ts), [`RaceEvent`](core/racing/domain/entities/RaceEvent.ts), [`Session`](core/racing/domain/entities/Session.ts), [`Result`](core/racing/domain/entities/result/Result.ts), [`RaceRegistration`](core/racing/domain/entities/RaceRegistration.ts)
- Stewarding: [`Protest`](core/racing/domain/entities/Protest.ts) (statuses), [`Penalty`](core/racing/domain/entities/penalty/Penalty.ts) (types enum, status)
- Other: [`JoinRequest`](core/racing/domain/entities/JoinRequest.ts), [`LeagueMembership`](core/racing/domain/entities/LeagueMembership.ts), [`Sponsor`](core/racing/domain/entities/sponsor/Sponsor.ts), [`SeasonSponsorship`](core/racing/domain/entities/season/SeasonSponsorship.ts), [`LeagueWallet`](core/racing/domain/entities/league-wallet/LeagueWallet.ts), [`Transaction`](core/racing/domain/entities/league-wallet/Transaction.ts), Track, Car, etc.
- ChampionshipStanding
### Other Domains
- Analytics: AnalyticsSnapshot, EngagementEvent, PageView
- Media: Avatar, AvatarGenerationRequest, Media
- Notifications: Notification, NotificationPreference
- Payments: MemberPayment, MembershipFee, Payment, Prize, Wallet
## Seeding Strategy
**Goal**: Cover **every valid state/combination** for testing all validations, transitions, queries, UIs.
- Use factories extending current `Racing*Factory` pattern.
- Deterministic IDs via `seedId(name, persistence)`.
- Group by domain, vary enums/states systematically.
- Relations: Create minimal graphs covering with/without relations.
- Volume: 5-20 examples per entity, prioritizing edge cases (min/max, empty/full, all enum values).
- Idempotent: Check existence before create.
### 1. Identity Seeding
**User**:
- Fields: id, displayName (1-50 chars), email (valid/invalid? but valid), passwordHash, iracingCustomerId?, primaryDriverId?, avatarUrl?
- States: 5 users - no email, with iRacing linked, with primaryDriver, admin@gridpilot.local (existing), verified/unverified (if state).
- Examples:
- Admin: id='user-admin', displayName='Admin', email='admin@gridpilot.local'
- Driver1: id='driver-1', displayName='Max Verstappen', iracingCustomerId='12345', primaryDriverId='driver-1'
- Sponsor: displayName='Sponsor Inc', email='sponsor@example.com'
**Achievement** etc.: All constants already seeded, add user-achievements linking users to achievements.
### 2. Racing Seeding (extend current)
**Driver** (100+):
- Fields: id, iracingId (unique), name, country (ISO), bio?, joinedAt
- States: 20 countries, bio empty/full, recent/past joined.
- Relations: Link to users, teams.
**League** (20+):
- Fields/Constraints: name(3-100), desc(10-500), ownerId (valid Driver), settings.pointsSystem (3 enums), sessionDuration(15-240min), qualifyingFormat(2), maxDrivers(10-60), visibility(2, ranked min10 participants?), stewarding.decisionMode(6 enums), requiredVotes(1-10), timeLimits(1-168h), participantCount(0-max)
- All combos: 3 points x 2 qual x 2 vis x 6 decision = ~72, but sample 20 covering extremes.
- States:
- Empty new league (participantCount=0)
- Full ranked (maxDrivers=40, count=40)
- Unranked small (max=8, count=5)
- Various stewarding (admin_only, steward_vote req=3, etc.)
- Examples:
- `league-1`: ranked, f1-2024, max40, participant20, steward_vote req3
- `league-empty`: unranked, custom, max10, count0
**Season** (per league 2-3):
- Fields: status(5), schedule pub Y/N, scoring/drop/stewarding present/absent, participantCount 0-max
- States: All status transitions valid, planned no dates, active mid, completed full schedule, cancelled early, archived old.
- Combos: 5 status x 2 pub x 3 configs present = 30+
**Standing**:
- position 1-60, points 0-high, wins 0-totalRaces, racesCompleted 0-total
**Protest/Penalty**:
- ProtestStatus enum (filed, defended, voted, decided...), IncidentDescription, etc.
- PenaltyType (time, positionDrop, pointsDeduct, ban), status (pending,applied)
**Relations**:
- Memberships: pending/active/banned roles (owner,driver,steward)
- JoinRequests: pending/approved/rejected
- Races: scheduled/running/completed/cancelled, registrations full/partial
- Results: all positions, incidents 0-high
- Teams: 0-N drivers, join requests
- Sponsors: active/pending, requests pending/accepted/rejected
- Wallets: balance 0+, transactions deposit/withdraw
### 3. Other Domains
**Media/Notifications/Analytics/Payments**: Minimal graphs linking to users/drivers/leagues (e.g. avatars for drivers, notifications for joins, pageviews for leagues, payments for memberships).
## Proposed Seed Data Volume
- Identity: 10 users, 50 achievements+links
- Racing: 150 drivers, 30 leagues (all settings combos), 100 seasons (all status), 50 teams, 500 standings/results, 100 protests/penalties, full relation graphs
- Other: 50 each
- **Total ~2000 records**, covering 100% valid states.
## Implementation Steps (for Code mode)
1. Extend factories for new states/combos.
2. Add factories for non-racing entities.
3. Update SeedRacingData to call all.
4. EnsureInitialData for non-racing.
This plan covers **every single possible valid state** via systematic enum cartesian + edges (0/max/empty/full/pending/complete)."