feat: T4 wave 10 – bottling quality, phenology and honey chain UI, Telegram link/receive and ops
- Bottling quality: water content above the legal limit (strict >) answers 409 CONFIRMATION_REQUIRED bound to the measured value; prefill for jar size, best-before (shelfLifeMonths, month-end clamping) and water content; impossible dates give 400; water-content checks in src/common/quality. - Frontend phenology: "Entwicklung melden" sheet, IndexedDB v4 queue, season header on the apiary page, confirmed revoke for all apiaries. - Frontend honey chain: "Vorschlag aus …" hints with explicit take-over, prefill status note, movement ledger with withdraw/correct dialogs. - Telegram: link tokens (hashed, single use), private-chat receiver with lease and offset CAS, bounded poison-update skip, Retry-After, pending deliveries skipped on disconnect; system API for deliveries and retry; worker-only secret wiring and manifest policy tests. - ARCHITECTURE.md §7, §9, §10, §11.11–11.13, Annahmen 51–55. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
16cc557462
commit
fab7f7e12f
91 files changed
+8463
-104
No files matched your search
@@ -137,7 +137,7 @@ describe('CleanupJob', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('cleanup deletes terminal NotificationDelivery rows after 30 days (FAILED after 90) and TelegramLinkToken rows expired for 30 days', async () => {
|
||||
it('cleanup deletes terminal NotificationDelivery rows after 30 days (FAILED after 90) and TelegramLinkToken rows used or expired for 24 hours', async () => {
|
||||
await job.run();
|
||||
|
||||
const failed = statementOn('NotificationDelivery', 'FAILED');
|
||||
@@ -153,7 +153,10 @@ describe('CleanupJob', () => {
|
||||
expect(delivered?.values).toEqual([WEBHOOK_DELIVERY_RETENTION_DAYS]);
|
||||
expect(delivered?.sql).toContain('"createdAt" < now()');
|
||||
const tokens = statementOn('TelegramLinkToken');
|
||||
expect(tokens.sql).toContain('"expiresAt" < now() - interval \'30 days\'');
|
||||
expect(tokens.sql).toContain('"expiresAt" < now() - interval \'24 hours\'');
|
||||
expect(tokens.sql).toContain(
|
||||
'"consumedAt" < now() - interval \'24 hours\'',
|
||||
);
|
||||
expect(tokens.values).toEqual([]);
|
||||
});
|
||||
|
||||
|
||||
@@ -84,10 +84,12 @@ export class CleanupJob implements Job {
|
||||
`Removed ${notificationDeliveriesPending} Telegram deliveries that stayed pending for over ${PENDING_DELIVERY_MAX_AGE_DAYS} days`,
|
||||
);
|
||||
}
|
||||
// A link token lives 10 minutes; used or not, it is of no use after that.
|
||||
// A link token lives 10 minutes and works once: a day after it was used
|
||||
// or expired it is of no use (and the hash is not worth keeping).
|
||||
const telegramLinkTokens = await this.prisma.$executeRaw`
|
||||
DELETE FROM "TelegramLinkToken"
|
||||
WHERE "expiresAt" < now() - interval '30 days'`;
|
||||
WHERE "expiresAt" < now() - interval '24 hours'
|
||||
OR "consumedAt" < now() - interval '24 hours'`;
|
||||
// After abortStale: no run this old can still be RUNNING.
|
||||
const jobRunsDeleted = await this.prisma.$executeRaw`
|
||||
DELETE FROM "JobRun"
|
||||
|
||||
Reference in new issue
Block a user