# Task 11: Seed Data Service Implementation Evidence

## Files Created

### 1. backend/src/WorkClub.Infrastructure/Seed/SeedDataService.cs
- **Purpose**: Provides idempotent seeding of development database
- **Key Features**:
  - Deterministic GUID generation from entity names (MD5-based)
  - Idempotent checks: Only seeds if no data exists
  - IServiceScopeFactory injection for creating scoped DbContext
  - Async SeedAsync() method for non-blocking seed operations

### 2. backend/src/WorkClub.Api/Program.cs (Modified)
- **Added Import**: `using WorkClub.Infrastructure.Seed;`
- **Service Registration**: `builder.Services.AddScoped<SeedDataService>();`
- **Development Startup**: Added seed execution in development environment only
  ```csharp
  if (app.Environment.IsDevelopment())
  {
      using var scope = app.Services.CreateScope();
      var seedService = scope.ServiceProvider.GetRequiredService<SeedDataService>();
      await seedService.SeedAsync();
  }
  ```

## Seed Data Structure

### Clubs (2 total)
1. **Sunrise Tennis Club** (Tennis)
   - Tenant ID: Deterministic GUID from "Sunrise Tennis Club"
   - Used by 3 members: admin@test.com, manager@test.com, member1@test.com, member2@test.com, viewer@test.com

2. **Valley Cycling Club** (Cycling)
   - Tenant ID: Deterministic GUID from "Valley Cycling Club"
   - Used by 2 members: admin@test.com, member1@test.com

### Members (7 total records, 5 unique users)
- **admin@test.com**: Admin in Tennis Club, Member in Cycling Club
- **manager@test.com**: Manager in Tennis Club
- **member1@test.com**: Member in Tennis Club, Member in Cycling Club
- **member2@test.com**: Member in Tennis Club
- **viewer@test.com**: Viewer in Tennis Club

### Work Items (8 total)
**Tennis Club (5 items)**
- Court renovation (Open, unassigned)
- Equipment order (Assigned, to manager)
- Tournament planning (InProgress, to member1)
- Member handbook review (Review, to member2)
- Website update (Done, to manager)

**Cycling Club (3 items)**
- Route mapping (Open, unassigned)
- Safety training (Assigned, to member1)
- Group ride coordination (InProgress, to admin)

### Shifts (5 total)
**Tennis Club (3 shifts)**
- Court Maintenance - Yesterday (past, capacity 2)
- Court Maintenance - Today (today, capacity 3)
- Tournament Setup - Next Week (future, capacity 5)

**Cycling Club (2 shifts)**
- Group Ride - Today (today, capacity 10)
- Maintenance Workshop - Next Week (future, capacity 4)

### Shift Signups (3-4 total)
- Tennis Court Maintenance (Yesterday): 2 signups
- Cycling Group Ride (Today): 1 signup

## Idempotency Implementation

Each entity type is seeded with idempotent checks:
```csharp
if (!context.Clubs.Any())
{
    context.Clubs.AddRange(...);
    await context.SaveChangesAsync();
}
```

This ensures:
- First run: All data inserted
- Subsequent runs: No duplicates (check passes on subsequent runs)
- Safe for multiple restarts during development

## Development-Only Guard

Seed execution is protected:
```csharp
if (app.Environment.IsDevelopment())
{
    // Seed only runs in Development environment
}
```

This ensures:
- Production environment: No seed execution
- Staging/Testing: Controlled separately via environment variables

## Deterministic GUID Generation

Used MD5 hash to create consistent tenant IDs:
```csharp
private static string GenerateDeterministicGuid(string input)
{
    var hash = MD5.HashData(Encoding.UTF8.GetBytes(input));
    return new Guid(hash.Take(16).ToArray()).ToString();
}
```

Benefits:
- Same GUID generated for same club name (consistency across restarts)
- Predictable: Matches expected UUIDs in test users
- No external dependencies needed

## Usage During Development

1. Backend starts in Development environment
2. Program.cs development middleware runs
3. SeedDataService is resolved from DI container
4. SeedAsync() is called asynchronously
5. First run: All seed data inserted
6. Subsequent runs: Checks pass, no duplicates

## Notes

- Seed runs synchronously in middleware (blocking startup until complete)
- SeedDataService uses IServiceScopeFactory to create fresh DbContext
- All entities have CreatedAt/UpdatedAt timestamps set to UTC now
- ExternalUserId values are placeholder user IDs (can be updated when connected to Keycloak)
- Shift times use DateTimeOffset to handle timezone properly
