wip: listings/admin in-flight — bulk update, duplicates, audit log, price constraints
Some checks failed
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 7s
CI / E2E Tests (push) Has been skipped
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 10s
Deploy / Build API Image (push) Failing after 23s
E2E Tests / Playwright E2E (push) Failing after 7s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 3s
Security Scanning / Trivy Scan — API Image (push) Failing after 43s
Security Scanning / Trivy Scan — Web Image (push) Failing after 28s
Security Scanning / Trivy Scan — AI Services Image (push) Failing after 28s
Deploy / Build Web Image (push) Failing after 10s
Deploy / Build AI Services Image (push) Failing after 9s
Security Scanning / Trivy Filesystem Scan (push) Failing after 38s
Deploy / Deploy to Staging (push) Has been skipped
Deploy / Smoke Test Staging (push) Has been skipped
Deploy / Deploy to Production (push) Has been skipped
Deploy / Smoke Test Production (push) Has been skipped
Security Scanning / Security Gate (push) Failing after 1s
Deploy / Rollback Staging (push) Has been skipped
Deploy / Rollback Production (push) Has been skipped
Some checks failed
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 7s
CI / E2E Tests (push) Has been skipped
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 10s
Deploy / Build API Image (push) Failing after 23s
E2E Tests / Playwright E2E (push) Failing after 7s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 3s
Security Scanning / Trivy Scan — API Image (push) Failing after 43s
Security Scanning / Trivy Scan — Web Image (push) Failing after 28s
Security Scanning / Trivy Scan — AI Services Image (push) Failing after 28s
Deploy / Build Web Image (push) Failing after 10s
Deploy / Build AI Services Image (push) Failing after 9s
Security Scanning / Trivy Filesystem Scan (push) Failing after 38s
Deploy / Deploy to Staging (push) Has been skipped
Deploy / Smoke Test Staging (push) Has been skipped
Deploy / Deploy to Production (push) Has been skipped
Deploy / Smoke Test Production (push) Has been skipped
Security Scanning / Security Gate (push) Failing after 1s
Deploy / Rollback Staging (push) Has been skipped
Deploy / Rollback Production (push) Has been skipped
Batch-committing concurrent work-in-progress so it isn't lost: Listings — bulk update + duplicate detection --------------------------------------------- - New command BulkUpdateListings + handler + tests under application/commands/bulk-update-listings/. - New DTO presentation/dto/bulk-update-listings.dto.ts. - Controller wires the bulk endpoint; update DTO extended. - Property duplicate detector hardened: normalized-address pipeline (new migration 20260420020000_add_property_address_normalized), repository + service updates, tests refreshed. - Listing entity gains ownership-transferred event (new event file). - Integration specs for price constraints (20260420000000_add_price_check_constraints) and duplicates. - E2E: e2e/api/listings-duplicates.spec.ts. Admin — moderation audit log ---------------------------- - New Prisma table (migration 20260420010000_add_moderation_audit_log) + Prisma repo + interface + DI wiring. - Listener `moderation-audit.listener.ts` + unit spec. - Query GetModerationAuditLogs + handler + controller `admin-moderation-audit.controller.ts` + DTO. Supporting ---------- - shared/infrastructure/cache.service.ts tweak. - AUDIT_LISTINGS_PROPERTY_MANAGEMENT.md — in-repo audit notes. - Various test + module wiring updates to keep the tree green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -276,6 +276,10 @@ model Property {
|
||||
ward String
|
||||
district String
|
||||
city String
|
||||
/// Lower-cased, unaccented, whitespace-collapsed concatenation of
|
||||
/// address/ward/district/city. Used for duplicate detection (TEC-2932).
|
||||
/// Nullable until the backfill migration covers historic rows.
|
||||
addressNormalized String?
|
||||
location Unsupported("geometry(Point, 4326)")
|
||||
areaM2 Float
|
||||
usableAreaM2 Float?
|
||||
@@ -296,6 +300,7 @@ model Property {
|
||||
furnishing Furnishing?
|
||||
propertyCondition PropertyCondition?
|
||||
balconyDirection Direction?
|
||||
// CHECK ("maintenanceFeeVND" IS NULL OR "maintenanceFeeVND" >= 0)
|
||||
maintenanceFeeVND BigInt?
|
||||
parkingSlots Int?
|
||||
viewType String[] @default([])
|
||||
@@ -317,6 +322,7 @@ model Property {
|
||||
// --- Compound indexes (query optimization) ---
|
||||
@@index([district, propertyType])
|
||||
@@index([district, city, propertyType])
|
||||
@@index([addressNormalized])
|
||||
}
|
||||
|
||||
model PropertyMedia {
|
||||
@@ -343,10 +349,14 @@ model Listing {
|
||||
seller User @relation(fields: [sellerId], references: [id], onDelete: Restrict)
|
||||
transactionType TransactionType
|
||||
status ListingStatus @default(DRAFT)
|
||||
// CHECK ("priceVND" > 0) — see migration 20260420000000_add_price_check_constraints
|
||||
priceVND BigInt
|
||||
// CHECK ("pricePerM2" IS NULL OR "pricePerM2" > 0)
|
||||
pricePerM2 Float?
|
||||
// CHECK ("rentPriceMonthly" IS NULL OR "rentPriceMonthly" > 0)
|
||||
rentPriceMonthly BigInt?
|
||||
commissionPct Float? @default(2.0)
|
||||
// CHECK ("aiPriceEstimate" IS NULL OR "aiPriceEstimate" > 0)
|
||||
aiPriceEstimate BigInt?
|
||||
aiConfidence Float?
|
||||
moderationScore Float?
|
||||
@@ -390,7 +400,9 @@ model PriceHistory {
|
||||
id String @id @default(cuid())
|
||||
listingId String
|
||||
listing Listing @relation(fields: [listingId], references: [id], onDelete: Cascade)
|
||||
// CHECK ("oldPrice" > 0) — see migration 20260420000000_add_price_check_constraints
|
||||
oldPrice BigInt
|
||||
// CHECK ("newPrice" > 0)
|
||||
newPrice BigInt
|
||||
source String @default("manual_update")
|
||||
changedAt DateTime @default(now())
|
||||
@@ -841,6 +853,28 @@ model AdminAuditLog {
|
||||
@@index([action, createdAt(sort: Desc)])
|
||||
}
|
||||
|
||||
// Free-form moderation audit log capturing every approve/reject/edit/flag action
|
||||
// performed by moderators on listings, properties, inquiries and other targets.
|
||||
// Strings (not enums) are used for `targetType` and `action` so that adding new
|
||||
// moderation surfaces does not require an enum migration. Existing AdminAuditLog
|
||||
// stays as-is for the admin-action timeline; this table is the moderator-centric
|
||||
// view used by TEC-2926.
|
||||
model ModerationAuditLog {
|
||||
id String @id @default(uuid())
|
||||
targetType String
|
||||
targetId String
|
||||
action String
|
||||
moderatorId String
|
||||
reason String?
|
||||
metadata Json?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([targetType, targetId])
|
||||
@@index([moderatorId, createdAt(sort: Desc)])
|
||||
@@index([action, createdAt(sort: Desc)])
|
||||
@@index([createdAt])
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// NEIGHBORHOOD & POI
|
||||
// =============================================================================
|
||||
|
||||
Reference in New Issue
Block a user