Files
wekan/server/lib/syncNotificationRetention.js
Lauri Ojansivu 5a7b74bd1d Compact delivered Sync webhook plans, with their URLs and tokens, after 90 days.
Maintainer decision of 2026-09-30: receipts are compacted after 90 days to
a permanent minimal id and outcome. A stored webhook plan keeps each
target's URL, its X-Wekan-Token credential and the request body; a response
row keeps the receiver's reply and a comment plan the comment text - all
forever, and the plan had no completion evidence of its own.

The notification plan retention becomes a shared kit (syncPlanRetention.js)
and webhooks use it: once every target's delivery is confirmed, a completion
receipt with its time is written. After SYNC_RECEIPT_METADATA_DAYS (90) the
sweep first removes the plan's response and comment-plan rows - read only
while a delivery receipt is missing - then compacts the plan in place. A late
replay of the compact form returns as delivered; delivery and comment
receipts, already minimal, stay.

A MongoDB test covers what is removed and what an undelivered plan keeps,
replay of the compact form and its refusals; the full-app webhook test
compacts a really delivered plan, checks the URL and token are gone, and
replays it without touching the comment. 565 server tests pass.

Thanks to xet7 !
2026-09-30 11:39:05 +03:00

21 lines
1.3 KiB
JavaScript

'use strict';
// Retention for stored Sync notification plans (maintainer decision of
// 2026-09-30): after SYNC_RECEIPT_METADATA_DAYS (90) a delivered plan is
// compacted to a permanent minimal id and outcome.
//
// A plan keeps each recipient's rendered email subject and HTML. It had no
// completion evidence of its own - delivery is confirmed by the tray receipt
// and the email outbox - so a plan could never be told finished. A receipt
// { _id: planId, version: 1, activityHash, checksum, completedAt }
// is now written once delivery is confirmed; the first one stored wins, with
// its timestamp. A plan whose receipt is older than the policy is replaced IN
// PLACE by { _id, activityHash, checksum, compactReceiptVersion: 1 } - the same
// _id, so a late replay can never rebuild and resend it. A replay that finds
// the compact form returns as delivered; within the policy a replay still
// re-checks every recipient, as it always did.
const kit = require('./syncPlanRetention').createPlanRetentionKit('sync-notification');
module.exports = { isCompactNotificationPlan: kit.isCompactPlan, recordNotificationCompletion: kit.recordPlanCompletion,
readCompactedNotification: kit.readCompactedPlan, compactNotificationBatch: kit.compactPlanBatch,
createSyncNotificationRetention: kit.createPlanRetention };