Data Retention & Tenant Deletion
This page documents how a tenant's data can be exported (GDPR data portability) and erased (right to be forgotten), and what survives a deletion.
Export (data portability)
A company owner — or a developer acting on a child tenant via the
X-Acting-Company header — can download a complete machine-readable dump:
- Auth: JWT bearer. Scoped to the effective company (own company, a child a developer owns, or — for a superuser — any company).
- Rate limit: 1 request/hour (severe, by design).
- Format: a streamed
application/zipcontaining one JSON array per model plus amanifest.json(company id/name, export timestamp, per-model row counts). Nothing is staged on disk.
Models included
products, locations, suppliers, customers, movements, batches,
physical_products, qr_codes, event_logs, reservations,
purchase_orders, sales_orders, transfer_orders, return_orders,
work_orders.
Foreign keys are exported as raw ids, so the object graph can be re-stitched on import. The UI exposes this as Impostazioni → Esporta dati azienda.
Deletion (right to be forgotten)
Tenant deletion is an operator command, not a self-service endpoint:
# Dry run — prints per-model row counts, deletes nothing:
python manage.py delete_company <company-uuid>
# Actually delete (cascade):
python manage.py delete_company <company-uuid> --confirm
- Without
--confirmthe command prints a report only and exits without changing anything. - A developer company that still owns child tenants is refused — delete the children first, so tenants are never silently orphaned or cascade-deleted.
- Deletion runs inside a transaction. A
COMPANY_DELETEDrow is written tocore.AuditLogbefore the delete; because that row's company FK isSET_NULL, the audit trail survives the cascade.
What is deleted
Everything that hangs off the company by FK, via Django on_delete=CASCADE:
the company row, its users, API keys, products and all product-scoped data
(movements, batches, physical products, event logs), locations, suppliers,
customers, QR codes, reservations, and every order type (purchase, sales,
transfer, return, work).
What remains
Nothing tenant-identifying. The only residue is the audit log entry of the deletion itself, with the company FK nulled — it records that a company was deleted and the row counts, but no longer points at a (now non-existent) company. This is intentional: it is the operator's durable evidence that the erasure happened.
Timing
Deletion is immediate and irreversible. There is no soft-delete or grace
window for the hard delete_company path. (To temporarily block access without
erasing data, suspend the company instead via the platform console — that flips
is_active and is fully reversible.)