diff --git a/SVSim.Bootstrap/Data/seeds/daily-login-bonus.json b/SVSim.Bootstrap/Data/seeds/daily-login-bonus.json
deleted file mode 100644
index e31694c2..00000000
--- a/SVSim.Bootstrap/Data/seeds/daily-login-bonus.json
+++ /dev/null
@@ -1,14 +0,0 @@
-[
- {
- "id": 1,
- "bonus_data": []
- },
- {
- "id": 3,
- "bonus_data": []
- },
- {
- "id": 4,
- "bonus_data": []
- }
-]
diff --git a/SVSim.Bootstrap/Importers/DailyLoginBonusImporter.cs b/SVSim.Bootstrap/Importers/DailyLoginBonusImporter.cs
deleted file mode 100644
index 1c158f1f..00000000
--- a/SVSim.Bootstrap/Importers/DailyLoginBonusImporter.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using System.Text.Json;
-using Microsoft.EntityFrameworkCore;
-using SVSim.Bootstrap.Models.Seed;
-using SVSim.Database;
-using SVSim.Database.Models;
-
-namespace SVSim.Bootstrap.Importers;
-
-///
-/// Idempotent upsert of daily-login-bonus campaign rows from seeds/daily-login-bonus.json.
-/// bonus_data array preserved verbatim — prod observed empty arrays outside active events.
-///
-public class DailyLoginBonusImporter
-{
- public async Task ImportAsync(SVSimDbContext context, string seedDir)
- {
- var seed = SeedLoader.LoadList(Path.Combine(seedDir, "daily-login-bonus.json"));
- if (seed.Count == 0) return 0;
-
- var existing = await context.DailyLoginBonuses.ToDictionaryAsync(e => e.Id);
- int created = 0, updated = 0;
- foreach (var s in seed)
- {
- if (s.Id == 0) continue;
- var entry = existing.TryGetValue(s.Id, out var ex) ? ex : new DailyLoginBonusEntry { Id = s.Id };
- entry.BonusData = s.BonusData.ValueKind == JsonValueKind.Undefined
- ? "[]"
- : JsonSerializer.Serialize(s.BonusData);
- if (ex is null) { context.DailyLoginBonuses.Add(entry); existing[s.Id] = entry; created++; }
- else updated++;
- }
-
- await context.SaveChangesAsync();
- Console.WriteLine($"[DailyLoginBonusImporter] +{created}/~{updated}");
- return created + updated;
- }
-}
diff --git a/SVSim.Bootstrap/Models/Seed/DailyLoginBonusSeed.cs b/SVSim.Bootstrap/Models/Seed/DailyLoginBonusSeed.cs
deleted file mode 100644
index e64ed76d..00000000
--- a/SVSim.Bootstrap/Models/Seed/DailyLoginBonusSeed.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System.Text.Json;
-using System.Text.Json.Serialization;
-
-namespace SVSim.Bootstrap.Models.Seed;
-
-/// Mirrors seeds/daily-login-bonus.json. bonus_data preserved verbatim.
-public sealed class DailyLoginBonusSeed
-{
- [JsonPropertyName("id")] public int Id { get; set; }
- [JsonPropertyName("bonus_data")] public JsonElement BonusData { get; set; }
-}
diff --git a/SVSim.Bootstrap/Program.cs b/SVSim.Bootstrap/Program.cs
index 629c91e4..5baccc63 100644
--- a/SVSim.Bootstrap/Program.cs
+++ b/SVSim.Bootstrap/Program.cs
@@ -94,7 +94,6 @@ public static class Program
await new MissionCatalogImporter().ImportAsync(context, opts.SeedDir);
await new AchievementCatalogImporter().ImportAsync(context, opts.SeedDir);
await new BattlePassMonthlyMissionImporter().ImportAsync(context, opts.SeedDir);
- await new DailyLoginBonusImporter().ImportAsync(context, opts.SeedDir);
await new PreReleaseInfoImporter().ImportAsync(context, opts.SeedDir);
await new CardListsImporter().ImportAsync(context, opts.SeedDir);
await new RotationFlagUpdater().UpdateAsync(context);
diff --git a/SVSim.Database/Models/DailyLoginBonusEntry.cs b/SVSim.Database/Models/DailyLoginBonusEntry.cs
deleted file mode 100644
index 22dab428..00000000
--- a/SVSim.Database/Models/DailyLoginBonusEntry.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System.ComponentModel.DataAnnotations.Schema;
-using SVSim.Database.Common;
-
-namespace SVSim.Database.Models;
-
-///
-/// Daily login bonus campaign from /load/index data.daily_login_bonus (dict keyed by bonus_id,
-/// values are arrays of bonus days). Prod observed keys {1, 3, 4} with empty arrays — recapture
-/// target during active login bonus events.
-///
-public class DailyLoginBonusEntry : BaseEntity
-{
- public int BonusId { get => Id; set => Id = value; }
-
- [Column(TypeName = "jsonb")]
- public string BonusData { get; set; } = "[]";
-}
diff --git a/SVSim.Database/Repositories/Globals/GlobalsRepository.cs b/SVSim.Database/Repositories/Globals/GlobalsRepository.cs
index 38082e2b..2f3c1375 100644
--- a/SVSim.Database/Repositories/Globals/GlobalsRepository.cs
+++ b/SVSim.Database/Repositories/Globals/GlobalsRepository.cs
@@ -59,9 +59,6 @@ public class GlobalsRepository : IGlobalsRepository
public Task> GetBattlePassLevels() =>
_dbContext.BattlePassLevels.AsNoTracking().ToListAsync();
- public Task> GetDailyLoginBonus() =>
- _dbContext.DailyLoginBonuses.AsNoTracking().ToListAsync();
-
public Task> GetBanners() =>
_dbContext.Banners.AsNoTracking().OrderBy(b => b.Id).ToListAsync();
diff --git a/SVSim.Database/Repositories/Globals/IGlobalsRepository.cs b/SVSim.Database/Repositories/Globals/IGlobalsRepository.cs
index 503fb56b..fe14fda7 100644
--- a/SVSim.Database/Repositories/Globals/IGlobalsRepository.cs
+++ b/SVSim.Database/Repositories/Globals/IGlobalsRepository.cs
@@ -19,7 +19,6 @@ public interface IGlobalsRepository
Task> GetUnlimitedRestrictions();
Task> GetLoadingExclusionCards();
Task> GetBattlePassLevels();
- Task> GetDailyLoginBonus();
Task> GetBanners();
Task> GetActiveHomeDialogsAsync(DateTime nowUtc);
Task GetCurrentSealedSeason();
diff --git a/SVSim.Database/SVSimDbContext.cs b/SVSim.Database/SVSimDbContext.cs
index a6bb4472..eb23443e 100644
--- a/SVSim.Database/SVSimDbContext.cs
+++ b/SVSim.Database/SVSimDbContext.cs
@@ -60,7 +60,6 @@ public class SVSimDbContext : DbContext
public DbSet ViewerMissions => Set();
public DbSet ViewerAchievements => Set();
public DbSet ViewerEventCounters => Set();
- public DbSet DailyLoginBonuses => Set();
public DbSet Banners => Set();
public DbSet HomeDialogEntries => Set();
public DbSet SealedSeasons => Set();
diff --git a/SVSim.EmulatedEntrypoint/Controllers/LoadController.cs b/SVSim.EmulatedEntrypoint/Controllers/LoadController.cs
index 9f1a198c..1701efba 100644
--- a/SVSim.EmulatedEntrypoint/Controllers/LoadController.cs
+++ b/SVSim.EmulatedEntrypoint/Controllers/LoadController.cs
@@ -229,10 +229,8 @@ public class LoadController : SVSimController
MaintenanceCards = (await _globalsRepository.GetMaintenanceCards())
.Select(e => e.Id).ToList(),
RedEtherOverrides = new List(),
- // Optional per spec (load-index.md:247). Skeleton-seeded rows in DailyLoginBonuses table
- // capture prod's empty-period shape ({"1":[], "3":[], "4":[]}); the spec-shaped DTO
- // ({normal?, total?, campaign?[]}) carries nothing meaningful until an active campaign
- // is captured.
+ // Optional per spec (load-index.md:247). Populated by ILoginBonusService (Task 6)
+ // when the viewer has an active bonus period.
DailyLoginBonus = null,
UserRankedMatches = new List(),
UserRankInfo = RankFormats.Select(f => new UserRankInfo
diff --git a/SVSim.EmulatedEntrypoint/Models/Dtos/Responses/IndexResponse.cs b/SVSim.EmulatedEntrypoint/Models/Dtos/Responses/IndexResponse.cs
index e7db9c4e..29eb205b 100644
--- a/SVSim.EmulatedEntrypoint/Models/Dtos/Responses/IndexResponse.cs
+++ b/SVSim.EmulatedEntrypoint/Models/Dtos/Responses/IndexResponse.cs
@@ -150,9 +150,7 @@ public class IndexResponse
///
/// Spec: optional. Shape is {normal?, total?, campaign?[]} per common/types.ts.md DailyLoginBonus.
- /// Until we have an active login-bonus campaign to surface in spec shape, omit. The skeleton
- /// rows in DailyLoginBonuses table (prod sent {"1":[], "3":[], "4":[]}) preserve the capture
- /// for archive but don't make it into the wire response.
+ /// Populated by ILoginBonusService when the viewer has an active bonus period; null otherwise.
///
[JsonPropertyName("daily_login_bonus")]
[Key("daily_login_bonus")]
diff --git a/SVSim.UnitTests/Importers/LoadIndexImporterTests.cs b/SVSim.UnitTests/Importers/LoadIndexImporterTests.cs
index f54387fc..f1fb9cb0 100644
--- a/SVSim.UnitTests/Importers/LoadIndexImporterTests.cs
+++ b/SVSim.UnitTests/Importers/LoadIndexImporterTests.cs
@@ -8,7 +8,7 @@ namespace SVSim.UnitTests.Importers;
///
/// Happy-path coverage for the load-index importer classes introduced in Stage 9B
-/// (RotationConfig, MyRotation, AvatarAbility, ArenaSeason, DailyLoginBonus,
+/// (RotationConfig, MyRotation, AvatarAbility, ArenaSeason,
/// PreReleaseInfo). Each test instantiates the importer in isolation and verifies it inserts
/// rows from the corresponding seed file under Data/seeds/.
/// Idempotency, edge cases, and per-importer detail tests live in dedicated *ImporterTests files (e.g. BattlePassImporterTests).
@@ -73,19 +73,6 @@ public class LoadIndexImporterTests
Assert.That(row!.FormatInfo, Is.Not.EqualTo("{}"), "format_info blob must be populated from seed");
}
- [Test]
- public async Task DailyLoginBonusImporter_writes_bonus_rows()
- {
- using var factory = new SVSimTestFactory();
- using var scope = factory.Services.CreateScope();
- var db = scope.ServiceProvider.GetRequiredService();
-
- await new DailyLoginBonusImporter().ImportAsync(db, SeedDir);
-
- Assert.That(await db.DailyLoginBonuses.CountAsync(), Is.GreaterThan(0),
- "daily-login-bonus.json must produce rows");
- }
-
[Test]
public async Task PreReleaseInfoImporter_writes_singleton()
{
diff --git a/SVSim.UnitTests/Infrastructure/SVSimTestFactory.cs b/SVSim.UnitTests/Infrastructure/SVSimTestFactory.cs
index c7efe03a..60285309 100644
--- a/SVSim.UnitTests/Infrastructure/SVSimTestFactory.cs
+++ b/SVSim.UnitTests/Infrastructure/SVSimTestFactory.cs
@@ -266,7 +266,6 @@ internal class SVSimTestFactory : WebApplicationFactory
await new BattlePassImporter().ImportAsync(ctx, seedDir);
await new BattlePassSeasonImporter().ImportAsync(ctx, seedDir);
await new BattlePassRewardImporter().ImportAsync(ctx, seedDir);
- await new DailyLoginBonusImporter().ImportAsync(ctx, seedDir);
await new PreReleaseInfoImporter().ImportAsync(ctx, seedDir);
await new CardListsImporter().ImportAsync(ctx, seedDir);
await new RotationFlagUpdater().UpdateAsync(ctx);
diff --git a/SVSim.UnitTests/Repositories/GlobalsRepositoryTests.cs b/SVSim.UnitTests/Repositories/GlobalsRepositoryTests.cs
index 388e97d0..a59f05db 100644
--- a/SVSim.UnitTests/Repositories/GlobalsRepositoryTests.cs
+++ b/SVSim.UnitTests/Repositories/GlobalsRepositoryTests.cs
@@ -80,16 +80,6 @@ public class GlobalsRepositoryTests
Assert.That(levels.Count, Is.EqualTo(100));
}
- [Test]
- public async Task GetDailyLoginBonus_returns_three_skeleton_entries()
- {
- var (factory, repo) = await SetupAsync();
- using var _ = factory;
- var bonuses = await repo.GetDailyLoginBonus();
- Assert.That(bonuses.Count, Is.EqualTo(3),
- "Prod capture has keys {1, 3, 4} with empty arrays — skeleton presence still seeded.");
- }
-
[Test]
public async Task GetPreReleaseInfo_returns_singleton()
{