|
|
@@ -1,6 +1,7 @@
|
|
|
# Phase 4: Enforce Required channelId and machine Fields
|
|
|
|
|
|
## Overview
|
|
|
+
|
|
|
This phase makes `channelId` and `machine` required (non-optional) throughout the entire stats pipeline, enforcing data integrity from the client through to the database layer.
|
|
|
|
|
|
## Changes Made
|
|
|
@@ -8,12 +9,14 @@ This phase makes `channelId` and `machine` required (non-optional) throughout th
|
|
|
### 1. Prisma Models (mongo-stats schema)
|
|
|
|
|
|
**Updated Files:**
|
|
|
+
|
|
|
- `prisma/mongo-stats/schema/user.prisma`
|
|
|
- `prisma/mongo-stats/schema/user-login-history.prisma`
|
|
|
- `prisma/mongo-stats/schema/ads-click-history.prisma`
|
|
|
- `prisma/mongo-stats/schema/events.prisma`
|
|
|
|
|
|
**Changes:**
|
|
|
+
|
|
|
- Removed `?` (optional) marker from `channelId` field in:
|
|
|
- `User` model
|
|
|
- `UserLoginHistory` model
|
|
|
@@ -31,6 +34,7 @@ This phase makes `channelId` and `machine` required (non-optional) throughout th
|
|
|
- `AdImpressionEvents` model
|
|
|
|
|
|
**Indexes Added:**
|
|
|
+
|
|
|
- Added composite index `@@index([channelId, createAt])` to `User` for channel-based queries
|
|
|
- Added composite index `@@index([channelId, createAt])` to `UserLoginHistory` for channel-based reporting
|
|
|
- Added composite index `@@index([channelId, uid, clickAt])` to `AdsClickHistory` for channel+user analytics
|
|
|
@@ -41,32 +45,36 @@ This phase makes `channelId` and `machine` required (non-optional) throughout th
|
|
|
### 2. Event Payload Interfaces
|
|
|
|
|
|
**Updated File:**
|
|
|
+
|
|
|
- `libs/common/src/events/user-login-event.dto.ts`
|
|
|
|
|
|
**Changes:**
|
|
|
+
|
|
|
```typescript
|
|
|
// Before
|
|
|
export interface UserLoginEventPayload {
|
|
|
- channelId?: string; // optional
|
|
|
- machine?: string; // optional
|
|
|
+ channelId?: string; // optional
|
|
|
+ machine?: string; // optional
|
|
|
}
|
|
|
|
|
|
// After
|
|
|
export interface UserLoginEventPayload {
|
|
|
- channelId: string; // required
|
|
|
- machine: string; // required
|
|
|
+ channelId: string; // required
|
|
|
+ machine: string; // required
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### 3. DTOs (API Input Validation)
|
|
|
|
|
|
**Updated Files:**
|
|
|
+
|
|
|
- `apps/box-app-api/src/feature/auth/login.dto.ts`
|
|
|
- `apps/box-app-api/src/feature/ads/dto/ad-click.dto.ts`
|
|
|
- `apps/box-app-api/src/feature/ads/dto/ad-impression.dto.ts`
|
|
|
|
|
|
**Changes:**
|
|
|
-- `LoginDto`:
|
|
|
+
|
|
|
+- `LoginDto`:
|
|
|
- `channelId` changed from `@IsOptional()` to `@IsNotEmpty()` @IsString()`
|
|
|
- `machine` changed from `@IsOptional()` to `@IsNotEmpty() @IsString()`
|
|
|
|
|
|
@@ -81,13 +89,14 @@ export interface UserLoginEventPayload {
|
|
|
### 4. Service Methods
|
|
|
|
|
|
**Updated File:**
|
|
|
+
|
|
|
- `apps/box-stats-api/src/feature/user-login/user-login.service.ts`
|
|
|
|
|
|
**Changes:**
|
|
|
+
|
|
|
- `createUser()` method:
|
|
|
- Removed `?? null` coalescing for `channelId` and `machine`
|
|
|
- Now directly assigns values without null fallback (since they're required)
|
|
|
-
|
|
|
- `recordLogin()` method:
|
|
|
- Removed `?? null` coalescing for `channelId` and `machine`
|
|
|
- Now directly assigns values
|
|
|
@@ -95,9 +104,11 @@ export interface UserLoginEventPayload {
|
|
|
### 5. Stats Event Consumer
|
|
|
|
|
|
**Updated File:**
|
|
|
+
|
|
|
- `apps/box-stats-api/src/feature/stats-events/stats-events.consumer.ts`
|
|
|
|
|
|
**Changes:**
|
|
|
+
|
|
|
- `handleAdClick()`:
|
|
|
- Validation now checks: `!payload.channelId || !payload.machine`
|
|
|
- Removed `?? null` coalescing, now directly assigns values
|
|
|
@@ -114,11 +125,14 @@ export interface UserLoginEventPayload {
|
|
|
### 6. Channel Management Updates
|
|
|
|
|
|
**Updated Files:**
|
|
|
+
|
|
|
- `apps/box-mgnt-api/src/mgnt-backend/feature/channel/channel.dto.ts`
|
|
|
- `apps/box-mgnt-api/src/mgnt-backend/feature/channel/channel.service.ts`
|
|
|
|
|
|
**Changes:**
|
|
|
+
|
|
|
- Added required `channelId` field to `CreateChannelDto`:
|
|
|
+
|
|
|
```typescript
|
|
|
@IsNotEmpty()
|
|
|
@IsString()
|
|
|
@@ -198,19 +212,23 @@ StatsEventsConsumer.handleAdClick()
|
|
|
## Validation Strategy
|
|
|
|
|
|
### Client-Side (Frontend)
|
|
|
+
|
|
|
- `channelId` and `machine` must be provided in all API requests
|
|
|
- Both fields are required and cannot be empty/null
|
|
|
|
|
|
### API Layer (NestJS)
|
|
|
+
|
|
|
- DTOs enforce `@IsNotEmpty()` and `@IsString()` decorators
|
|
|
- ValidationPipe validates before reaching controllers
|
|
|
- Controllers reject requests with missing/invalid values (400 Bad Request)
|
|
|
|
|
|
### Message Queue (RabbitMQ)
|
|
|
+
|
|
|
- Event payloads typed as required fields
|
|
|
- Consumer validation checks for presence before persisting
|
|
|
|
|
|
### Database (MongoDB)
|
|
|
+
|
|
|
- Prisma schema enforces non-optional fields
|
|
|
- Database will reject inserts/updates without `channelId` and `machine`
|
|
|
- Composite indexes optimize channel+user based analytics queries
|
|
|
@@ -218,6 +236,7 @@ StatsEventsConsumer.handleAdClick()
|
|
|
## Migration Path
|
|
|
|
|
|
For existing data with null `channelId` or `machine`:
|
|
|
+
|
|
|
1. No automatic migration - manual data cleanup required
|
|
|
2. All NEW requests MUST provide both fields
|
|
|
3. Recommend setting default values for legacy data during migration window
|
|
|
@@ -226,6 +245,7 @@ For existing data with null `channelId` or `machine`:
|
|
|
## Testing Recommendations
|
|
|
|
|
|
### Unit Tests
|
|
|
+
|
|
|
- ✅ LoginDto validation with required fields
|
|
|
- ✅ AdClickDto validation with required fields
|
|
|
- ✅ AdImpressionDto validation with required fields
|
|
|
@@ -233,12 +253,14 @@ For existing data with null `channelId` or `machine`:
|
|
|
- ✅ StatsEventsConsumer validation of required fields
|
|
|
|
|
|
### Integration Tests
|
|
|
+
|
|
|
- ✅ End-to-end login flow with channelId + machine
|
|
|
- ✅ Ad click tracking with channelId + machine
|
|
|
- ✅ Ad impression tracking with channelId + machine
|
|
|
- ✅ Data persists correctly to MongoDB
|
|
|
|
|
|
### Manual Testing
|
|
|
+
|
|
|
```bash
|
|
|
# Test 1: Login with required fields
|
|
|
curl -X POST http://localhost:3301/api/v1/auth/login \
|
|
|
@@ -274,31 +296,37 @@ curl -X POST http://localhost:3301/api/v1/auth/login \
|
|
|
## Files Modified Summary
|
|
|
|
|
|
### Prisma Schemas (4 files)
|
|
|
+
|
|
|
- `prisma/mongo-stats/schema/user.prisma` ✅
|
|
|
- `prisma/mongo-stats/schema/user-login-history.prisma` ✅
|
|
|
- `prisma/mongo-stats/schema/ads-click-history.prisma` ✅
|
|
|
- `prisma/mongo-stats/schema/events.prisma` ✅
|
|
|
|
|
|
### Event Interfaces (1 file)
|
|
|
+
|
|
|
- `libs/common/src/events/user-login-event.dto.ts` ✅
|
|
|
|
|
|
### DTOs (3 files)
|
|
|
+
|
|
|
- `apps/box-app-api/src/feature/auth/login.dto.ts` ✅
|
|
|
- `apps/box-app-api/src/feature/ads/dto/ad-click.dto.ts` ✅
|
|
|
- `apps/box-app-api/src/feature/ads/dto/ad-impression.dto.ts` ✅
|
|
|
|
|
|
### Services (3 files)
|
|
|
+
|
|
|
- `apps/box-stats-api/src/feature/user-login/user-login.service.ts` ✅
|
|
|
- `apps/box-stats-api/src/feature/stats-events/stats-events.consumer.ts` ✅
|
|
|
- `apps/box-mgnt-api/src/mgnt-backend/feature/channel/channel.service.ts` ✅
|
|
|
|
|
|
### Channel Management (2 files)
|
|
|
+
|
|
|
- `apps/box-mgnt-api/src/mgnt-backend/feature/channel/channel.dto.ts` ✅
|
|
|
|
|
|
## Compilation Status
|
|
|
|
|
|
✅ **Prisma Generation**: All three schemas passed validation
|
|
|
✅ **TypeScript**: Phase 4 critical files compile without errors
|
|
|
+
|
|
|
- Note: Existing errors from Phase 3 (Ads-Channel split) remain in ad-related files but don't impact Phase 4 functionality
|
|
|
|
|
|
## Next Steps
|