refactor(tutorial-presents): promote static catalogue to seed-driven TutorialPresentEntries table

The five tutorial gifts every fresh viewer is given at signup used to live as a
static C# array in SVSim.Database/SeedData/TutorialPresents.cs — outside the
seed-JSON pipeline used by all 40+ other globals tables. Editing a gift required
a code change + rebuild instead of a JSON edit + bootstrap re-run.

Now authored in SVSim.Bootstrap/Data/seeds/tutorial-presents.json and loaded into
a new TutorialPresentEntries table via TutorialPresentsImporter (clear-and-rewrite,
mirroring HomeDialogs). ViewerRepository.RegisterAnonymousViewer reads the table
at signup and projects each row into a ViewerPresent with Source="tutorial".

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-06-09 09:53:10 -04:00
parent 7118b92522
commit 998402ebc3
12 changed files with 4434 additions and 39 deletions

View File

@@ -278,6 +278,8 @@ internal sealed class SVSimTestFactory : WebApplicationFactory<Program>
await mypage.ImportSpecialDeckFormatsAsync(ctx, seedDir);
await mypage.ImportHomeDialogsAsync(ctx, seedDir);
await new TutorialPresentsImporter().ImportAsync(ctx, seedDir);
await new DefaultDeckImporter().ImportAsync(ctx, seedDir);
await new PackImporter().ImportAsync(ctx, seedDir);
// PackDrawTableImporter is NOT called here — production draw tables reference real
@@ -563,17 +565,31 @@ internal sealed class SVSimTestFactory : WebApplicationFactory<Program>
}
/// <summary>
/// Seed the five tutorial ViewerPresent rows for a test viewer. RegisterViewer (admin/social
/// path) does NOT auto-seed; only the production /tool/signup -> RegisterAnonymousViewer flow
/// does. Tests opt in by calling this helper after SeedViewerAsync when they want a tutorial-
/// shaped inbox state.
/// Seed the tutorial ViewerPresent rows for a test viewer by projecting from the
/// TutorialPresentEntries catalogue. RegisterViewer (admin/social path) does NOT auto-seed;
/// only the production /tool/signup -> RegisterAnonymousViewer flow does. Tests opt in by
/// calling this helper after SeedViewerAsync when they want a tutorial-shaped inbox state.
/// If the catalogue is empty (most tests skip SeedGlobalsAsync), this method imports
/// tutorial-presents.json on demand so the helper works regardless of test setup ordering.
/// </summary>
public async Task SeedTutorialPresentsAsync(long viewerId)
{
using var scope = Services.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<SVSimDbContext>();
if (!await db.TutorialPresentEntries.AnyAsync())
{
string seedDir = Path.Combine(AppContext.BaseDirectory, "Data", "seeds");
await new TutorialPresentsImporter().ImportAsync(db, seedDir);
}
var catalogue = await db.TutorialPresentEntries
.AsNoTracking()
.OrderBy(p => p.PresentId)
.ToListAsync();
var createdAt = DateTime.UtcNow;
foreach (var spec in SVSim.Database.SeedData.TutorialPresents.All)
foreach (var spec in catalogue)
{
db.ViewerPresents.Add(new ViewerPresent
{