WorkCompliance engineering
Regulatory rules as versioned, effective-dated data in a small application
A jurisdiction's statutory deadlines stored as effective-dated data rows instead of code, with a retention schedule and breach runbook written against the same records.
The problem
Many small applications keep records governed by statute: tenancy, employment or benefits rules, for example. The rules set deadlines, notice periods and limits. Some figures change on a schedule. Some apply only when conditions hold.
Hardcoding these numbers fails twice. A changed figure becomes a code release, and history is lost: the system cannot say which rule applied when a deadline started. Conditional rules become branching nobody outside the code can check.
A records application of this kind also needs a retention schedule and breach plan matched to what it stores.
What was built
A small regulated-records application with separate administrator and end-user views. Its compliance core has three parts.
A rule table. Every statutory figure is a row, not a constant. A single resolver, given a rule key, a jurisdiction and an as-of date, returns the row in force on that date. The table was seeded from a written compliance addendum, and each row carries a short note.
| Field | Purpose |
|---|---|
| key | The rule’s name, such as a notice period |
| jurisdiction | Scopes a rule to the place it applies |
| value | Stored as JSON, so a rule can be a number, a flag or a tiered value |
| note | Caveats or a statute reference, such as the event a period runs from |
| effective_from / effective_to | The dates the row applies |
A deadline engine. Each kind of statutory clock is a defined type; built flows register clocks as events occur, and types for later phases can be reserved ahead of use. The engine reads a clock’s duration from the rule table as of the start date, computes the due date at registration, and stores a snapshot of the rule value with the deadline. A scheduled sweep finds upcoming and overdue items, queues each alert once, and audits each run.
Conditions as data. Where a rule applies only under certain conditions, each condition is a field on the records it concerns, and the effective result is derived from those fields, never stored.
Design decisions
- Resolve rules by date, snapshot them at use. A deadline keeps the rule value it was created under. If a figure changes while a clock is running, existing clocks stay as they were, and the record explains each due date.
- No threshold in code. The design-of-record maps each rule to where it is enforced, and every threshold goes through the resolver. A changed figure is a new dated row, not a release.
- Hard gates where the law is a hard line. Scheduling an action with less lead time than the rule requires is refused unless the affected person consented, and that override is audited. Requirements the law makes mandatory are enforced server-side, not left to on-screen wording.
- An append-only audit log. Database triggers reject any update or delete of audit rows. Diffs are redacted to shape and keys, so the log never copies the personal data values it records changes to.
- Retention that is hard to cut short by mistake. Deleting a person’s record hides it but keeps it. A parent record cannot be deleted while any agreement, active or ended, refers to it. Every document carries a retention class for disposal to key off.
- Encrypt what is not queried; collect less. Sensitive free-text notes are encrypted at the application layer under a dedicated key, with a self-describing prefix so older values still read. New fields are added only with a retention class and a reason.
Evidence and limits
- Continuous integration runs type checking, linting and the tests on every change. Tests exercise the real API routes against in-process storage fakes; the design-of-record specifies tests for overlapping and expired rules, audit-log write rejection, sweep idempotency and deadline boundaries.
- In the suite, axe-core asserts zero accessibility violations on key end-user screens. A manual Lighthouse run on a built preview requires 0.95 or better; it sits outside per-change CI, and color contrast is checked only there.
- The retention schedule labels every period as statutory, limitations-driven prudence, tax, or operational. For two record classes the policy records that no statute sets a retention period; for one, a commonly repeated multi-year rule turned out to have no statutory source. Where two periods apply, the longer wins.
- The breach runbook starts the notification clock at discovery, not at containment. It lists each store of personal data with its control, and treats encryption as the statutory safe harbor, which holds only if the key is not exposed with the data, so keys must be stored and rotated apart from it.
- The documents state their own limits. Rule values, retention periods and notice requirements were written to await confirmation by counsel and, for tax records, an accountant. Automated disposal and some rule enforcement were left outside the first phase’s scope.
Where it applies
The pattern is not specific to one domain. Any organization bound by dated external requirements can hold them as inspectable data rather than code.
- Preparing an authorization package. Parameter values, review cadences and notification windows held as effective-dated records, snapshotted where used, show which requirement version applied when a baseline changes mid-period.
- Retention and incident response. A schedule that separates mandated periods from chosen ones, each tied to a disposition and a data store, gives both plans concrete evidence.
- Fractional security leadership. For a smaller organization, the lesson is to keep the rule set, the audit trail and an honest list of what is not yet built where a non-engineer can read them.
Independent work by Wade Blackwell. Each write-up is written from scratch for this site, without client, employer or personal data. Names, hostnames, addresses and configuration detail are left out on purpose.