letmesplain

Server-side progress — what is stored about your users

By default, Splain records nothing on your server about who completed what — completion lives only in each user's browser. A host can turn on server-side progress to make completion durable and cross-device (and, with the pro report, visible to an admin). This page says exactly what that stores, because the whole point is that you can tell your users — and your lawyer — the truth without hedging.

Turning it on

// config/splain.php
'progress' => [
    'enabled' => env('SPLAIN_PROGRESS', false),   // ← default false; off stores nothing new
    'retention_days' => null,                     // null = you own retention
    'reporting' => ['per_person' => false],       // aggregate-only by default
],

Off (the default), Splain behaves exactly as before: completion is client-only and no new rows are written. Nothing here activates until you set enabled to true.

What is stored (the entire footprint)

One row per (user, guide-version) the user completes, holding only:

field what it is
user_type, user_id a pointer to your own user record (its class + id). Not a copy — Splain stores no name/email. The report shows only this pointer (e.g. App\Models\User #42); if you want a human name, you resolve it against your own user table.
guide_slug, guide_version which guide, which version
completed_at when they reached the guide's final step (or null for a backfilled row, where the real date is unknown)
source playback (recorded live) or import (migrated from the browser)

What is deliberately not stored

No name, email, IP, user-agent, session id, page URLs, step timings, or click trail — and no created_at/updated_at: Splain does not record when a user synced, only the completion fact itself. The honest framing is: "we keep the single minimal behavioral fact — that a user reached a guide's terminal step, and when" — not "we keep no behavior." A per-guide completed_at is minimal personal data; we say so.

Anonymous users

If there's no identifiable user, nothing is written — no row, no synthetic id. Logged-out visitors stay entirely on localStorage.

Erasure and retention (you are the controller)

Splain is a processor here — you decide policy:

php artisan splain:progress:forget "App\Models\User" 42   # erase one user's records
php artisan splain:progress:prune                         # delete rows past retention_days

prune only removes dated completions (source: playback). A backfilled row (source: import) carries no completion date — the real date is unknown — so it is exempt from age-based pruning by design; erase those with splain:progress:forget.

prune with no retention_days set is a deliberate no-op — Splain never deletes on a schedule you didn't choose.

The admin report (pro) and employee monitoring

The pro completion report shows onboarding progress. Because per-person completion visible to managers is regulated employee monitoring in some jurisdictions, reporting.per_person defaults to false (aggregate counts only); turn on per-person visibility deliberately, with whatever disclosure your jurisdiction requires. Treat that wording as a lawyer-review item, like the publish attestation.

Nothing leaves your perimeter

Recording is a local database write. Progress data never leaves your app.


Rendered from splain@b6ea439. The documentation is rendered from the package repository — the same files that ship with Splain — so the site can't drift from the code.