dgtlss/capsule
Capsule is a Laravel package for organizing your application into self-contained modules. It provides a clean structure for routes, migrations, views, and classes, making large codebases easier to navigate, reuse, and maintain.
Architecture fit Capsule is a Laravel-native backup and disaster-recovery package: it drives backups of database and filesystem state through Laravel's filesystem abstraction and a scheduled/CLI surface, with encryption and restore tooling attached. v3.0.0 moves it from "convenient scheduled dump" toward "defensible production DR component," but only if we treat key custody and restore rehearsal as first-class engineering deliverables rather than package configuration. Architecturally this belongs to the platform/infrastructure domain (SRE-adjacent ownership), not to individual feature teams — a backup nobody can restore is an org problem, not a library problem.
Integration feasibility
The blocking constraints are environmental, not code-level: PHP 8.2 (Laravel 12) or 8.3 (Laravel 13), plus zip, sodium, zlib extensions, pdo_sqlite for SQLite backup/validation, sqlite3 for SQLite restore, and an AES-capable libzip build for the legacy ZIP path. Feasibility therefore reduces to a question about our base images and CI runners: if we own the Dockerfiles, this is a small, well-understood change; if we run on a managed platform with a fixed extension set, this may be a hard blocker.
The genuinely valuable capability here is capsule-decrypt. Recovery no longer depends on a working Laravel application or backup catalog, which decouples DR from deploy state and from application health. That is the strongest architectural improvement in the release and the basis on which a TPM can justify adoption.
Technical risk
.capsule.enc is a package-specific format requiring "a compatible Capsule installation" plus the password. The standalone decryptor reduces app coupling but does not eliminate tool coupling — we must retain a working decryptor binary, version-pinned, for as long as any archive in retention exists.Key questions
sodium, sqlite3, and an AES-capable libzip into every environment that might perform a restore — including the incident-response environment?capsule-decrypt live, and how is its version pinned against archive format versions we still retain?Stack fit
Conditional and decidable. Strong fit if we own our container images and are on Laravel 12+/PHP 8.2+. Poor fit if we are pinned to Laravel 10/11, PHP 8.1, or a managed runtime where we cannot control extensions or the libzip build. The conditional is a two-hour check of base images and CI matrices, not a research project — do it before any design work.
Migration path Stage it, and exploit the fact that existing backups need no conversion:
--list and --dry-run before any real destination mutation, and diff the resulting layout against expectations from the prior version.--no-local --encrypt on one low-risk service with a documented password stored outside the application.Compatibility Pin the package version and, separately and explicitly, pin the decryptor version against the archive format versions we retain. During the transition we will be running two toolchains concurrently: v3.x for new archives and the prior release (or an older decryptor) for archives still inside retention. That concurrent-support burden is the main compatibility cost and should be scheduled, not discovered.
Sequencing
Prerequisites strictly precede adoption: framework/PHP upgrade → image extension work (including AES-capable libzip) → secret storage for the backup password → staging capacity → restore rehearsal harness → runbook. Do not let the package upgrade and the framework upgrade land in the same change window; they have independent failure signatures and would be indistinguishable during triage.
Maintenance
Low change frequency, high consequence. Steady-state maintenance is dominated by environment drift — base-image rebuilds that silently drop an extension, libzip rebuilt without AES, PHP minor upgrades — rather than by the package itself. Archive format is now tied to tool version, so package upgrades require a compatibility decision, not a routine composer update. Budget one recurring owner, not a rotating volunteer.
Support Two distinct runbooks with very different exercise frequency: backup is routine and should be silent (alert only on failure or on unexpected full-base creation); restore is rare and must be rehearsed on a schedule. Decryption is a separate competency with a separate artifact — the docs explicitly require keeping the password and recovery dependencies available separately from the application. That is an operational control we must actually implement (escrow, access logging, break-glass procedure), not merely agree with in a design review.
Scaling Streaming materially reduces peak local disk versus staging a complete local archive, which is the right shape for growing datasets. But peak temp usage from SQLite snapshots and filesystem adapters still governs capacity, and a forced fresh full base temporarily roughly doubles storage for that dataset. Encryption adds CPU on the sodium path; measure it against the largest real dataset rather than assuming it is negligible. Incremental chains also grow unbounded unless retention is defined.
Failure modes
sqlite3, AES-capable libzip) → discovered during an incident, which is the worst possible time.Ramp-up Developer learning curve is genuinely low — this is configuration plus a scheduled command. The real effort is procedural: DR runbook authoring, rehearsal cadence, password custody and escrow, and an explicit decision on how long we retain both legacy archives and their toolchain. Rough shape for planning: image/extension work is small (days), runbook and first rehearsal are moderate (one to two weeks including a real restore into a scratch environment), and organizational agreement on key custody is the long pole and should be started first because it gates everything else.
How can I help you explore Laravel packages today?