Status: FULLY COMPLETED
Date: December 9, 2025
Impact: All 12 Channel records now have unique channelId values
Phase 4 required making channelId a mandatory field in the Channel model and throughout the stats pipeline. However, existing production data had all 12 Channel records with missing/null channelId values, causing Prisma deserialization failures during app startup.
This document tracks the resolution of that data consistency issue.
Error Encountered:
Error converting field 'channelId' of expected non-nullable type 'String',
found incompatible value of 'null'
Root Cause:
channelId a required fieldchannelId setchannelId optional in schema: String? instead of StringChannelCacheBuilder to skip null recordsGenerated unique channelId values for all 12 channels:
| Channel Name | Generated channelId | Method |
|---|---|---|
| channel name | channel-name | Slugified name |
| 123 | 123 | Numeric slug |
| 4 | 4 | Numeric slug |
| 5 | 5 | Numeric slug |
| 6 | 6 | Numeric slug |
| 7 | 7 | Numeric slug |
| 8 | 8 | Numeric slug |
| 9 | 9 | Numeric slug |
| 10 | 10 | Numeric slug |
| 11 | 11 | Numeric slug |
| asd321 | asd321 | Direct slug |
| 123 (duplicate) | 123-692960 | Slug with ID suffix |
Migration Strategy:
123-692960Result: ✅ All 12 records updated successfully
channelId from optional to required: channelId String @uniqueChannelCacheBuilderprisma/mongo/schema/channel.prisma
// BEFORE
channelId String? @unique
// AFTER
channelId String @unique
libs/core/src/cache/channel/channel-cache.builder.ts
// BEFORE - With filter for null channelId
const channels = await this.mongoPrisma.channel.findMany({
where: { channelId: { not: null } },
orderBy: [{ name: 'asc' }],
});
// AFTER - No filter needed, all channels have channelId
const channels = await this.mongoPrisma.channel.findMany({
orderBy: [{ name: 'asc' }],
});
Prisma Clients Regenerated
node_modules/@prisma/mongo/client ✅node_modules/@prisma/mysql/client ✅node_modules/@prisma/mongo-stats/client ✅Total records: 12
With channelId: 12 (100%)
Without channelId: 0 (0%)
[Nest] ChannelCacheBuilder] Built 12 channels
[Nest] VideoListCacheBuilder] Built video pools and home sections for 12 channels
[Nest] Bootstrap] 🚀 box-app-api listening on http://0.0.0.0:3301
✅ TypeScript: 0 errors
✅ Prisma Generation: All clients generated successfully
✅ App startup: No cache warming errors
| Component | Status | Details |
|---|---|---|
| Channel Schema | ✅ Required | channelId String @unique |
| Channel Data | ✅ Complete | All 12 records populated |
| App Startup | ✅ Success | All cache warming completes |
| Cache Loading | ✅ Full | All 12 channels cached |
| TypeScript | ✅ Clean | 0 compilation errors |
| RabbitMQ | ✅ Ready | Stats pipeline operational |
The following Phase 4 changes are now FULLY ENFORCED:
channelId required in mongo Channel modelchannelId required in all mongo-stats models (User, UserLoginHistory, AdsClickHistory, etc.)machine required in all mongo-stats modelschannelId and machinechannelId and machinechannelId and machineuser-login.service.ts validates required fieldsstats-events.consumer.ts validates required fieldschannel.service.ts includes channelId in all operationsNew Channels: When creating new channels, channelId must be provided
channelId during channel creationData Validation: Consider adding pre-insert validation
API Contract: Update Channel creation/update endpoints
Monitoring: Track stats event failures due to missing channelId
If reverting to optional channelId is needed:
channelId String?However, this is NOT RECOMMENDED as it defeats the purpose of Phase 4 enforcement.
✅ All Phase 4 requirements met ✅ Data migration completed successfully ✅ Production data validated and populated ✅ App startup verified with all 12 channels cached ✅ No outstanding blockers
Next Steps: Phase 4 enforcement is complete. Stats pipeline is now operating with mandatory channelId and machine fields across all events and models.