feat: reminders, Excel customer import and security hardening
Features - Payment reminders via Resend (candidates, send, history, test email) - Bulk import of the customer list from Excel/CSV in the dashboard - Dashboard i18n (en/nl) with language selector Security - Enforce venue isolation on all /venues/:venueId routes - Require admin for planned-tab changes and pairing codes - Rate-limit login and device registration; opt-in TRUST_PROXY - Require JWT_SECRET in production; stop leaking internal errors - Escape customer names in reminder emails Sync and commands - Remove tabs the terminal no longer reports; validate nested sync payload - Return all pending commands on every sync (fixes missed-command race) - First command ack wins; atomic registration code claim - Reject commands for revoked devices, stale versions or duplicates - Remind only unpaid balances, with a 7-day cooldown Dashboard - Share a single token refresh across concurrent 401s (random logouts) - Keep the session alive for the refresh token lifetime Deployment - Replace `db push --accept-data-loss` with migrations (baselines legacy DBs) - Set NODE_ENV=production; pass Resend and TRUST_PROXY env in prod compose
This commit is contained in:
@@ -20,6 +20,7 @@ model Venue {
|
||||
auditLogs AuditLog[]
|
||||
regCodes RegistrationCode[]
|
||||
plannedTabs PlannedTab[]
|
||||
tabReminders TabReminder[]
|
||||
}
|
||||
|
||||
model Device {
|
||||
@@ -148,6 +149,7 @@ model PlannedTab {
|
||||
id String @id @default(uuid())
|
||||
venueId String
|
||||
customerName String
|
||||
email String?
|
||||
position Int @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@ -155,4 +157,20 @@ model PlannedTab {
|
||||
|
||||
@@unique([venueId, customerName])
|
||||
@@index([venueId])
|
||||
}
|
||||
|
||||
model TabReminder {
|
||||
id String @id @default(uuid())
|
||||
venueId String
|
||||
tabId String
|
||||
customerName String
|
||||
email String
|
||||
amountInCents Int
|
||||
sentAt DateTime @default(now())
|
||||
status String @default("sent")
|
||||
|
||||
venue Venue @relation(fields: [venueId], references: [id])
|
||||
|
||||
@@index([venueId, sentAt])
|
||||
@@index([venueId, tabId])
|
||||
}
|
||||
Reference in New Issue
Block a user