PHPackages                             ginkelsoft/laravel-data-breach-registry - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Security](/categories/security)
4. /
5. ginkelsoft/laravel-data-breach-registry

ActiveLibrary[Security](/categories/security)

ginkelsoft/laravel-data-breach-registry
=======================================

A Laravel package that implements the GDPR art. 33/34 personal-data breach register with a hash-chained event log, 72-hour deadline helpers, and CLI for daily monitoring.

v1.0.0(1mo ago)001MITPHPPHP ^8.2CI passing

Since May 28Pushed 1mo agoCompare

[ Source](https://github.com/ginkelsoft-development/laravel-data-breach-registry)[ Packagist](https://packagist.org/packages/ginkelsoft/laravel-data-breach-registry)[ RSS](/packages/ginkelsoft-laravel-data-breach-registry/feed)WikiDiscussions development Synced 1w ago

READMEChangelog (1)Dependencies (10)Versions (3)Used By (1)

Ginkelsoft Laravel Data Breach Registry
=======================================

[](#ginkelsoft-laravel-data-breach-registry)

[![Tests](https://github.com/ginkelsoft-development/laravel-data-breach-registry/actions/workflows/tests.yml/badge.svg?branch=development)](https://github.com/ginkelsoft-development/laravel-data-breach-registry/actions/workflows/tests.yml)[![License](https://camo.githubusercontent.com/6c711032aff1ca0eb6b211aa6cb3649ce7fd64a7714e1181d4bb457f9680e7cf/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d677265656e2e7376673f7374796c653d666c61742d737175617265)](LICENSE)[![Laravel](https://camo.githubusercontent.com/255077649ac4ed79e446c4d860d1c53c9764b8ff855456caeb401faf7d250205/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d31302d2d31332d627269676874677265656e3f7374796c653d666c61742d737175617265266c6f676f3d6c61726176656c)](https://laravel.com)[![PHP](https://camo.githubusercontent.com/482d9c7691869be159b0bd042060a220a12a89396d63fa223c22b74affaf42c4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e322532302d2d253230382e352d626c75653f7374796c653d666c61742d737175617265266c6f676f3d706870)](https://php.net)[![PHPStan](https://camo.githubusercontent.com/fa63e0381a93ba9755a46ec197198ef973137dca1643836d06b3d6263c9aa7c8/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d6c6576656c2532306d61782d627269676874677265656e3f7374796c653d666c61742d737175617265)](phpstan.neon.dist)

Overview
--------

[](#overview)

Implements the **GDPR art. 33** (notification to supervisory authority within 72 hours) and **art. 34** (notification to affected subjects when the risk is high) personal-data breach register for a Laravel application.

Two tables work together. `breach_register` holds the current state of each breach — open, contained, resolved, reported to whom and when. `breach_event_log` is the append-only, hash-chained audit trail of every state transition, built on the shared `HashChain` from `ginkelsoft/laravel-compliance-core`. The register answers "where do we stand?"; the event log answers "how did we get here?", and is the part an auditor will scrutinize.

This is the **breach registry** member of the GinkelSoft compliance family.

The family
----------

[](#the-family)

PackageGDPR Article(s)Role[`laravel-compliance-core`](https://github.com/ginkelsoft-development/laravel-compliance-core)art. 5(2)Shared primitives[`laravel-data-retention`](https://github.com/ginkelsoft-development/laravel-data-retention)art. 5(1)(e)Storage limitation[`laravel-data-right-to-be-forgotten`](https://github.com/ginkelsoft-development/laravel-data-right-to-be-forgotten)art. 17Subject-driven erasure[`laravel-data-subject-access`](https://github.com/ginkelsoft-development/laravel-data-subject-access)art. 15 + 20Subject access[`laravel-data-consent`](https://github.com/ginkelsoft-development/laravel-data-consent)art. 6(1)(a) + 7Consent registry**`laravel-data-breach-registry`****art. 33 + 34****Breach register — this package**[`laravel-compliance-hub`](https://github.com/ginkelsoft-development/laravel-compliance-hub)art. 5(2)UmbrellaHow it works
------------

[](#how-it-works)

### Register a breach

[](#register-a-breach)

```
use Ginkelsoft\DataBreachRegistry\Actions\BreachRegistry;
use Illuminate\Support\Carbon;

$registry = new BreachRegistry;

$breach = $registry->register(
    reference: 'BREACH-2026-001',
    discoveredAt: Carbon::parse('2026-05-27 09:15'),
    description: 'Misdirected client export sent to wrong recipient.',
    severity: 'high',
    occurredAt: Carbon::parse('2026-05-27 08:50'),
    dataCategories: ['name', 'email', 'order_history'],
    subjectsAffected: 42,
    cause: 'Operator selected the wrong recipient group.',
    actor: 'ops@example.com',
);
```

The 72-hour deadline for notifying the supervisory authority (AP in NL) runs from `discoveredAt`. The model exposes `authorityNotificationDeadline()` and `isAuthorityNotificationOverdue()`for direct use in dashboards.

### Update, contain, resolve

[](#update-contain-resolve)

```
$registry->update('BREACH-2026-001', [
    'mitigation' => 'Recipient confirmed deletion. Tokens revoked.',
    'severity'   => 'medium',
], actor: 'ops@example.com');

$registry->reportToAuthority('BREACH-2026-001', notificationReference: 'AP-2026-9999');
$registry->reportToSubjects('BREACH-2026-001', channel: 'email');

$registry->contain('BREACH-2026-001');
$registry->resolve('BREACH-2026-001');
```

Each call atomically updates the register row and appends a hash-chained event. Updates with identical values are no-ops — no event is written when nothing actually changes.

### Find the deadlines that matter

[](#find-the-deadlines-that-matter)

```
use Ginkelsoft\DataBreachRegistry\Support\BreachDeadlines;

$deadlines = new BreachDeadlines(warningWindowHours: 24);

$overdue = $deadlines->overdue();         // 72 hours passed, authority not notified
$approaching = $deadlines->approaching(); // deadline in the next 24 hours
```

### CLI

[](#cli)

```
php artisan retention:breach:register BREACH-2026-001 \
    --description="Misdirected export" \
    --severity=high \
    --discovered="2026-05-27 09:15" \
    --subjects=42 \
    --categories="name,email"

php artisan retention:breach:list
php artisan retention:breach:list --status=open

php artisan retention:breach:show BREACH-2026-001

php artisan retention:breach:deadlines
php artisan retention:breach:deadlines --warning=48
```

`retention:breach:deadlines` exits with a non-zero code when there are overdue breaches — perfect for a scheduled job that pages someone when a 72-hour clock is about to expire. The command names keep the `retention:breach:` prefix for BC with the v1.x monolithic package.

### Verify the event log

[](#verify-the-event-log)

```
use Ginkelsoft\ComplianceCore\Config\LogSecret;
use Ginkelsoft\ComplianceCore\Support\HashChain;
use Illuminate\Support\Facades\DB;

$entries = DB::table('breach_event_log')->orderBy('id')->get()
    ->map(fn ($row) => (array) $row)->all();

$intact = HashChain::verify($entries, LogSecret::value());
```

Or run `php artisan compliance:verify` from the [hub](https://github.com/ginkelsoft-development/laravel-compliance-hub) to verify every chain in the family in one shot.

What the log holds
------------------

[](#what-the-log-holds)

The event log holds only metadata: action names, field diffs, optionally an actor. **It never holds personal data** — that data lives in the source systems the breach concerns, not in the register.

Compliance notes
----------------

[](#compliance-notes)

- **GDPR art. 33** — Notification of a personal-data breach to the supervisory authority within 72 hours of becoming aware of it.
- **GDPR art. 34** — Communication of a personal-data breach to the data subject when the breach is likely to result in a high risk.
- **GDPR art. 5(2)** — Accountability. The event log is the evidence.

This package is **not legal advice**. Whether a breach requires subject notification (art. 34: "high risk") is your DPIA call, not the package's.

Installation
------------

[](#installation)

```
composer require ginkelsoft/laravel-data-breach-registry
php artisan vendor:publish --tag=compliance-config
php artisan vendor:publish --tag=breach-config
php artisan vendor:publish --tag=breach-migrations
php artisan migrate
```

Then add a secret to `.env` (shared with the rest of the family):

```
COMPLIANCE_LOG_SECRET="$(openssl rand -base64 32)"
```

Gotchas
-------

[](#gotchas)

- **No notification is automatic.** This module records that a breach happened and that you notified — it does NOT actually send the email to the AP or to subjects. The notification itself is a business process you own. Use `reportToAuthority` / `reportToSubjects` to mark the moment you completed it.
- **Severity is your judgement.** The package accepts `low`, `medium`, `high`, `critical` as enum-like values, but does not assess them for you. Whether a breach requires subject notification (art. 34: "high risk") is your DPIA call.
- **The register is the canonical record, the event log is the proof.**Direct Eloquent `update()` on `BreachRegisterEntry` is allowed by Laravel but skips the event log; always go through `BreachRegistry` so the audit trail stays complete.

Testing
-------

[](#testing)

```
composer install
vendor/bin/pest
vendor/bin/phpstan analyse --memory-limit=1G
vendor/bin/pint --test
```

Reporting bugs
--------------

[](#reporting-bugs)

Found a bug or unexpected behaviour? We want to hear about it.

**Preferred — open a GitHub issue:**

When opening an issue, please include:

1. **Versions** — PHP, Laravel, and the package version (`composer show ginkelsoft/laravel-data-breach-registry`).
2. **What you did** — the artisan command, code snippet, or steps that triggered the bug.
3. **What you expected** vs **what actually happened** — include full error output or a stack trace if there is one.
4. **A minimal reproduction** if you can — a failing test or a small code sample beats a long description.

**Security-sensitive findings** (anything that could expose personal data, break a hash-chain, or bypass an audit log) — please **do not**open a public issue. E-mail **** directly with "SECURITY" in the subject line and we will respond privately.

**Not on GitHub?** You can also e-mail **** with the same information.

Contact
-------

[](#contact)

For commercial support, integration questions, or anything that doesn't fit a GitHub issue: **** — .

License
-------

[](#license)

MIT License — see [LICENSE](LICENSE). (c) 2026 Ginkelsoft

###  Health Score

38

—

LowBetter than 83% of packages

Maintenance89

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity47

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

57d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/165766253?v=4)[ginkelsoft](/maintainers/ginkelsoft)[@GinkelSoft](https://github.com/GinkelSoft)

---

Top Contributors

[![ginkelsoft-development](https://avatars.githubusercontent.com/u/179240029?v=4)](https://github.com/ginkelsoft-development "ginkelsoft-development (3 commits)")

---

Tags

laravelgdprcomplianceaudit-logavgginkelsoftincident-responsebreach-registrydatalek

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/ginkelsoft-laravel-data-breach-registry/health.svg)

```
[![Health](https://phpackages.com/badges/ginkelsoft-laravel-data-breach-registry/health.svg)](https://phpackages.com/packages/ginkelsoft-laravel-data-breach-registry)
```

###  Alternatives

[laravel/cashier

Laravel Cashier provides an expressive, fluent interface to Stripe's subscription billing services.

2.5k30.2M151](/packages/laravel-cashier)[laravel/pulse

Laravel Pulse is a real-time application performance monitoring tool and dashboard for your Laravel application.

1.7k15.1M136](/packages/laravel-pulse)[laravel/ai

The official AI SDK for Laravel.

1.0k3.2M246](/packages/laravel-ai)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
