fix(subscriptions): atomic UsageRecord metering to prevent quota bypass
- Add @@unique([subscriptionId, metric, periodStart, periodEnd]) constraint to UsageRecord model with corresponding migration - Replace racy findFirst+update/create pattern with Prisma upsert using INSERT ON CONFLICT DO UPDATE SET count = count + delta - Fix CheckQuotaHandler to use period-scoped findUnique instead of unscoped findFirst, preventing stale cross-period reads - Update tests to reflect atomic upsert pattern Closes GOO-4 Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "UsageRecord_subscriptionId_metric_periodStart_periodEnd_key" ON "UsageRecord"("subscriptionId", "metric", "periodStart", "periodEnd");
|
||||
@@ -0,0 +1,7 @@
|
||||
-- AlterEnum
|
||||
-- Add ROOM_RENTAL, CONDOTEL, and SERVICED_APARTMENT to the PropertyType enum.
|
||||
-- These new values support phòng trọ (room rentals), condotels, and serviced apartment listings.
|
||||
|
||||
ALTER TYPE "PropertyType" ADD VALUE 'ROOM_RENTAL';
|
||||
ALTER TYPE "PropertyType" ADD VALUE 'CONDOTEL';
|
||||
ALTER TYPE "PropertyType" ADD VALUE 'SERVICED_APARTMENT';
|
||||
@@ -265,6 +265,9 @@ enum PropertyType {
|
||||
LAND
|
||||
OFFICE
|
||||
SHOPHOUSE
|
||||
ROOM_RENTAL
|
||||
CONDOTEL
|
||||
SERVICED_APARTMENT
|
||||
}
|
||||
|
||||
enum TransactionType {
|
||||
@@ -757,6 +760,7 @@ model UsageRecord {
|
||||
periodStart DateTime
|
||||
periodEnd DateTime
|
||||
|
||||
@@unique([subscriptionId, metric, periodStart, periodEnd])
|
||||
@@index([subscriptionId, metric])
|
||||
}
|
||||
|
||||
@@ -1064,10 +1068,10 @@ model IndustrialPark {
|
||||
remainingAreaHa Float
|
||||
tenantCount Int @default(0)
|
||||
establishedYear Int?
|
||||
landRentUsdM2Year Float?
|
||||
rbfRentUsdM2Month Float?
|
||||
rbwRentUsdM2Month Float?
|
||||
managementFeeUsd Float?
|
||||
landRentUsdM2Year Decimal? @db.Decimal(18, 4)
|
||||
rbfRentUsdM2Month Decimal? @db.Decimal(18, 4)
|
||||
rbwRentUsdM2Month Decimal? @db.Decimal(18, 4)
|
||||
managementFeeUsd Decimal? @db.Decimal(18, 4)
|
||||
infrastructure Json? // { electricity, water, wastewater, telecom, roads, fire }
|
||||
connectivity Json? // { nearestPort, airport, highway, railway, seaport }
|
||||
incentives Json? // { taxHoliday, importDuty, landRentReduction, specialZone }
|
||||
@@ -1121,10 +1125,10 @@ model IndustrialListing {
|
||||
hasMezzanine Boolean @default(false)
|
||||
hasOfficeArea Boolean @default(false)
|
||||
officeAreaM2 Float?
|
||||
priceUsdM2 Float?
|
||||
priceUsdM2 Decimal? @db.Decimal(18, 4)
|
||||
pricingUnit String? // "usd/m2/month", "usd/m2/year"
|
||||
totalLeasePrice Float?
|
||||
managementFee Float?
|
||||
totalLeasePrice Decimal? @db.Decimal(18, 4)
|
||||
managementFee Decimal? @db.Decimal(18, 4)
|
||||
depositMonths Int?
|
||||
minLeaseYears Int?
|
||||
maxLeaseYears Int?
|
||||
|
||||
Reference in New Issue
Block a user