milenmk/laravel-gdpr-exporter
Laravel package for GDPR-compliant personal data exports, letting you gather and export a user's stored data in a structured format to satisfy data access and portability requests.
Architecture fit. milenmk/laravel-gdpr-exporter fills a narrow but legally mandated slot: assembling a subject-access / data-portability response (GDPR Art. 15 and Art. 20) from Eloquent-backed personal data and packaging it as a downloadable artifact. The functionality is not novel — any team can write a controller that dumps a user's rows — so the leverage is in standardizing the plumbing: config-driven model and column discovery, serialization, archive creation, and delivery notification. As a TPM the correct framing is that this package supplies roughly 20% of a DSAR capability. The remaining 80% is the data map, the legal review, and the operational runbook, none of which ship in the dependency. Fit is good for a conventional Laravel monolith where a data subject's records live in first-party Eloquent models on a single connection and the app already has queue workers, a private storage disk, and transactional mail. Fit is poor for the architectures that increasingly dominate real DSAR scope — multi-tenant databases, data spread across services, documents in object storage, event streams, and third-party processors. There the package is one contributor among many and you still hand-build the aggregation layer. Decide the gate early: "one app, one database" (adopt) versus "distributed estate" (adopt as a component, budget for orchestration).
Integration feasibility. Install cost is low; configuration cost is medium; correctness cost is high. The binding constraint is never composer require — it is producing and maintaining an authoritative inventory of which columns constitute personal data. That inventory is a legal artifact as much as a technical one and needs DPO sign-off, which puts a multi-week dependency on work engineering will misjudge as an afternoon. Treat the config file as the API surface: it declares which models are exported, which columns and relations are pulled, and what is deliberately excluded. Version it in the repo so the exact scope of any historical export is auditable and defensible.
Technical risk. Four concerns dominate. First, the 1.4.0 release body is only an auto-generated compare link — no feature summary, migration notes, or security reference. The minor bump from 1.3.2 is consistent with additive, non-breaking change under semver, but semver is a convention the maintainer self-certifies, not a guarantee, and it does not tell you whether new config keys exist (requiring a config republish), whether the archive format shifted (breaking downstream consumers), or what CI now covers. Treat "no breaking changes" as unverified until the diff and composer.json constraints are read directly. Second, this is a single-maintainer package with minimal adoption signal (2 stars) sitting on a legally consequential code path; a silently dropped model produces an incomplete statutory response, which is a compliance incident rather than a bug ticket. Bus factor is one, and there is no visible security disclosure policy. Third, PHP and Laravel support windows are not stated in the release notes and must be confirmed against the application's own upgrade horizon — a package that caps below your next Laravel major becomes a migration blocker with a legal dependency attached. Fourth, the package produces a file but cannot guarantee compliance: lawful basis, identity verification of the requester, and the response clock remain the application's responsibility, and no one should be allowed to believe otherwise.
Key questions. What exactly changed between 1.3.2 and 1.4.0, and does it touch configuration keys or output format? Does the exporter query in chunks, or load a full subject's dataset into memory? How are queries scoped — is there a test proving one subject's export cannot contain another's rows? What is the CI matrix and test coverage, and is there a vulnerability disclosure route? Does it handle soft-deleted records, relations, polymorphic associations, encrypted casts, and non-column data (uploads, JSON blobs), or only straightforward attributes? Which storage disk does it default to, and does it enforce encryption at rest and a TTL? Is there an extension interface for custom exporters, or would anything non-standard require a fork?
Stack fit. Suitable for Laravel applications with Eloquent as the system of record, an async queue driver, a durable private storage disk, and working transactional mail. It assumes the application can enumerate its own personal data; where that assumption fails — data in object storage, processor-held data, event-sourced history — the package's leverage drops sharply and the shortfall has to be covered by a documented manual step in the DSAR process.
Migration path. Introduce on a branch, publish and commit the config, and build the data map incrementally rather than attempting a complete inventory in one pass — start with the user table and the two or three highest-risk related tables, then expand under review. Before trusting output in production, generate an export for a seeded synthetic account and reconcile it line by line against a manually assembled export for one real, consented internal account. That reconciliation is the only credible evidence the map is complete, and it should become a repeatable test rather than a one-off exercise. Keep the export path single-sourced: every request — console, support tool, or API — should flow through the same declaration so any two artifacts for the same subject are identical.
Compatibility. Read the package's composer.json PHP and Laravel constraints against the application's pinned versions and its own framework upgrade plan. Read the 1.3.2→1.4.0 diff specifically for changes to the published config file and the archive structure. Pin an exact version in composer.lock; for a legally consequential dependency, deliberate upgrades beat automatic ones. Diff the published config against vendor/.../config/ on every minor bump, because a new upstream key will silently default rather than appear.
Sequencing. (1) DPO and legal agree the scope of what a DSAR response must contain. (2) Engineering reads the 1.4.0 diff and records what changed. (3) Install 1.4.0 pinned in staging — do not combine package adoption and a minor upgrade in a single deploy, so a failure has one candidate cause. (4) Build and review the data map with legal. (5) Build the delivery and retention path around the package: queued job, signed expiring link, private encrypted disk, TTL deletion, audit log of who exported what and the artifact hash. (6) Write the internal DSAR runbook and name an owner. (7) Ship to production behind a flag and run a live drill against a real account before any external request depends on it. (8) Only then connect it to a support- or legal-facing request intake.
Maintenance. The dependency surface is small, but you permanently own two drifting artifacts: the config and the data map. Both decay silently as the schema evolves — a phone_number column added six months from now simply will not appear in exports, and nothing fails. Mitigate with a schema-introspection test in CI that asserts every column tagged as personal data is mapped, plus a recurring review cadence tied to schema migrations. Budget this as ongoing cost, not a one-time setup, and assign it to a named owner rather than "the team."
Support. DSAR requests originate from legal and customer support, not engineering, and carry statutory deadlines. The package provides a mechanism, not a process. Without a documented runbook, a named owner, a tracked request queue with deadline visibility, and defined escalation paths for "export is empty" and "export is late," the capability exists on paper and fails in practice. Identity verification of the requester must be an explicit, logged step before any export is generated — an export triggered by the wrong party is a data breach, not a support ticket.
Scaling. Export cost is proportional to one subject's data volume, usually modest, but the tail is dangerous: a long-tenured or high-activity account can mean hundreds of thousands of rows across many tables. Queue the work rather than inlining it in an HTTP request so max_execution_time and memory limits do not truncate the response. Verify chunked queries; measure peak memory on a deliberately large account. Cap concurrent exports per subject and globally, and consider routing reads to a replica so a large export cannot degrade production. Storage grows monotonically unless retention is enforced — 24–72 hours is typical and should be automated, not left to an operator.
Failure modes. Rank by severity, not likelihood. Most severe: cross-subject leakage from a scoping bug, which converts a compliance obligation into a reportable breach — this needs a dedicated test, not a code review. Next: under-export, the most common production failure, caused by an unmapped relation, a $hidden attribute, or a select that never loads a column; silent, and only discovered when a data subject complains. Then: over-export and insecure delivery — an artifact on a public disk, an unencrypted archive, a non-expiring link. Then: job failure or queue backlog pushing a response past the statutory deadline with no alerting. Then: config drift after an upgrade, where published config silently diverges from the package's expectations. Finally: maintainer abandonment, which leaves you owning a fork on a regulated path — worth a contingency note in the runbook given the bus factor.
Ramp-up. Engineering effort is front-loaded and small in absolute terms: a day to install, inspect the command surface and source, and produce a first export; one to three weeks to build and legally review a credible data map and delivery/retention path for a mid-sized schema; ongoing fractional effort thereafter. The expensive ramp-up is organizational, not technical: teaching support and legal how to open, track, and close a request; getting DPO sign-off on the scope document; and rehearsing one end-to-end drill so the first real request is not the first real run. Frame the adoption decision as buying a well-scoped serialization component and budgeting the surrounding DSAR process explicitly — teams that treat the package as the whole solution ship a capability that looks complete and fails its first audit.
How can I help you explore Laravel packages today?