Skip to content

Backup & retention

dAvePi stores everything it cares about in two places:

  1. MongoDB — every record, every audit row, every idempotency token, every webhook delivery row, every migration record.
  2. File storage — blobs for type: 'File' fields. Local disk, S3, or GCS depending on your config.

Backups need to cover both. Restores need to put both back in sync. This page covers the framework-level invariants (what to back up, what the framework already purges, retention configuration); per-platform deep dives live one click deeper.

Where Mongo livesGuide
Self-hosted Mongo on a VM (e.g. the Docker Compose stack)Self-host backup
MongoDB AtlasAtlas backup
AWS DocumentDBDocumentDB backup
Azure Cosmos DB (Mongo API)Cosmos backup

For uploaded blobs:

And the most important page nobody reads until 3am:

  • Restore drill — a documented rehearsal procedure. Untested backups aren’t backups.

The whole database, with a couple of exceptions:

CollectionBack up?Why
Every schema-driven collectionYesThis is your data.
audit_logYesCompliance + post-incident forensics. The framework doesn’t auto-purge audit rows — once written, they’re permanent until you manually prune.
_migrationsYesLosing this means the migration runner thinks it needs to re-run everything. Catastrophic if migrations aren’t idempotent.
idempotency_keyNo (optional)Auto-purged after IDEMPOTENCY_TTL_SECONDS (default 24h). It’s a retry-correctness mechanism, not history.
webhook_deliveryYesOperational telemetry, but the framework doesn’t auto-purge it — grows linearly with mutations. Include in backups if you keep delivery audit trails; prune periodically to stop unbounded growth.

If you really need a partial restore, grab the full dump and filter on restore.

What the framework purges automatically vs. what you have to manage yourself:

CollectionAuto-purge?Configured via
idempotency_keyYesIDEMPOTENCY_TTL_SECONDS env (default 24h).
Soft-deleted records (per-schema)OptionalsoftDelete: { retentionDays: N } on the schema, or SOFT_DELETE_RETENTION_DAYS env globally.
audit_logNoManual pruning. The framework records audit rows but never deletes them.
webhook_deliveryNoManual pruning. Same posture as audit.

idempotency_key rows have an expiresAt TTL — defaults to 24h, override with IDEMPOTENCY_TTL_SECONDS. Mongo’s TTL monitor sweeps expired rows on its background cycle (~60s). Collection size stays bounded.

Opt in per-schema or globally:

module.exports = {
path: 'contact',
softDelete: { retentionDays: 30 }, // per-schema
fields: [/* ... */],
};

Or via env (applies to every schema that doesn’t specify its own):

Terminal window
SOFT_DELETE_RETENTION_DAYS=30

A periodic sweep hard-deletes any row whose deletedAt is older than the configured retention. The matching file blobs (for type: 'File' fields) are removed too. Useful for GDPR / right-to-be-forgotten windows.

Without softDelete: { retentionDays } (and no global env), tombstoned rows live forever — the soft-delete is the retention.

audit_log grows linearly with mutations and the framework does not auto-purge it. If your audit volume is high or your compliance window is bounded, prune the collection yourself on a cron:

// e.g. weekly: keep 1 year of audit rows
db.audit_log.deleteMany({
createdAt: { $lt: new Date(Date.now() - 365 * 24 * 60 * 60 * 1000) },
});

Adding framework-side audit retention is a tracked enhancement; for now, manual pruning is the path.

Same posture as audit: webhook_delivery records every delivery attempt and the framework doesn’t prune them. Manual cleanup on a cron is the current path.

OperationSnapshot before
Running a migrationTake a Mongo backup. Migrations should be idempotent and have a down, but a snapshot is your safety net.
Bulk delete via the admin SPASame.
db.collection.dropIndexTake a snapshot, then run the migration that re-creates whatever the framework needs.
npx davepi migrate downSnapshot first — down is best-effort, and some operations don’t have a clean inverse.
Tuning softDelete.retentionDays shorterSnapshot first. The next sweep will hard-delete rows that fell out of the new window.

A useful mental model when picking a platform-specific backup strategy:

TargetWhat it means
RPO (recovery point objective)How much data you can afford to lose. If your last good backup is 24h ago, your RPO is 24h.
RTO (recovery time objective)How long it takes to bring the system back. A mongorestore from S3 of a 500GB database isn’t a 10-minute operation.
PlatformTypical RPOTypical RTO (small DB)Cost shape
Self-host with daily mongodump cron24h30-60 minStorage of dumps + your time
Self-host with hourly mongodump cron1h30-60 minSame
Atlas continuous backup<1 min (oplog)5-20 minIncluded in M10+ tiers
DocumentDB automated snapshots5 min (oplog)10-30 minIncluded; longer retention costs extra
Cosmos continuous backup<1 min5-30 minBuilt-in once enabled

The pages above walk through configuring each.