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:
@@ -15,12 +15,16 @@ export class TabsService {
|
||||
},
|
||||
});
|
||||
|
||||
const snapshots = await this.prisma.openTabSnapshot.findMany({
|
||||
where: {
|
||||
OR: ownerships.map((o) => ({ deviceId: o.deviceId, tabId: o.tabId })),
|
||||
},
|
||||
});
|
||||
const snapshotByKey = new Map(snapshots.map((s) => [`${s.deviceId}:${s.tabId}`, s]));
|
||||
|
||||
const tabs = [];
|
||||
for (const ownership of ownerships) {
|
||||
const snapshot = await this.prisma.openTabSnapshot.findFirst({
|
||||
where: { tabId: ownership.tabId, deviceId: ownership.deviceId },
|
||||
orderBy: { reportedAt: 'desc' },
|
||||
});
|
||||
const snapshot = snapshotByKey.get(`${ownership.deviceId}:${ownership.tabId}`);
|
||||
|
||||
if (snapshot) {
|
||||
tabs.push({
|
||||
|
||||
Reference in New Issue
Block a user