Feature breakdown · built with CraftHQ
Audit log
Whole-team time at this build's pace
2 people incl. the product owner, requirements to merge
Estimate at this build's pace, not a measurement of this feature
Every sensitive action, a reveal, an export, a sign-off, is recorded and can be reviewed.
How long a feature this size usually takes
Whole-team time — this build vs a typical team
~14 FP · FP × 6.8 to 9.4 h (ISBSG 2023)
Estimate at this build's pace, not a measurement of this feature
Both figures are whole-team time over the whole lifecycle, so they compare like for like. Ours is this build's pace — about 0.8 hours per function point across the whole build (two people, including the product owner, with requirements and review time). The industry range is an ISBSG project-level figure applied to one feature, so it is indicative.
Workflow
How it moved through the workflow
Select a stage. The build shipped, so every stage is complete; a person approved the merge.
Request
Every sensitive action, a reveal, an export, a sign-off, should leave an append-only record that oversight can read later.
Questions
One design decision was recorded before building.
Approved
The product owner signs off the breakdown by moving the story into the approved state, and the build runs against that reference.
Definition of ready
Building
CraftHQ's build agents write the code and the tests together, run as a loop; a failing check halts the work until it passes.
Checks
Three checks run on every pull request: one on the product owner's machine as CraftHQ builds, one on the engineer's machine before review, and a code-quality scan in CI. Merging is gated by the CI check passing and a person's approval, enforced by branch protection.
Review
An engineer reviews the pull request and merges it.
Merged
The pull request is merged to main after a person approves it. Nothing merges without that approval.
Definition of done
Breakdown
The feature breakdown
Business first, then the engineering view. Tab through it.
Overview
The gap it closes
Without a record of sensitive actions as they happen, there is no reliable way to show who did what later.
Who uses it
Administrators and reviewers read the trail for oversight. Every role's sensitive actions are recorded.
User story
As an administrator, I want an append-only log of sensitive actions so that I can show who did what and when.
Examples
Example 1
A user exports a list. An audit row is written in the same transaction, recording who exported, what, and when.
Example 2
An administrator reveals a masked contact. The reveal is written as its own audit row, recording who revealed it and when, with no separate reason prompt.
Dependencies & risks
Depends on
An append-only, partitioned store, and the data changes and sensitive actions across the product that emit audit rows.
Risk & mitigation
A recorded action could be missed if it did not emit a row. Reduced by writing the audit row in the same transaction as the action, so a committed change cannot commit without its record. The log records data changes and sign-in outcomes.
How it works
Simplified diagrams of the parts involved, the steps of one request, and where it runs.
Architecture
- 1performs a sensitive action
- 2append the row in the same transaction as the action
- 3filter by actor or action
- 4read the trail, scoped by role and tenant
Sequence
- 1perform a sensitive action
- 2build the audit row
- 3append the row in the same transaction as the action
- 4commit the action and the row together
- 5action done, recorded
Infrastructure
- 1action or read the trail (authenticate + tenant check)
- 2append and read audit rows
Acceptance criteria
Each scenario is written as a Gherkin spec. The Engineering tab shows the test that covers each one, or notes where it was verified by review.
@platform @securityFeature: Audit logAs an administratorI want an append-only log of sensitive actionsSo that I can show who did what and whenEvery data change and sensitive action writes an append-only audit row in the same transaction, and a per-role view lets oversight read the trail. The log records sign-in outcomes and data changes.Background:Given the audit log is append-only and partitionedAnd database permissions refuse any update or delete of an audit rowRule: A successful sensitive action and its audit row are written togetherScenario: A sensitive action records an audit rowGiven a user performs a sensitive actionWhen the action is committedThen an audit row is written in the same transactionAnd it records who acted, what they did, and whenRule: The log records data changes and sign-in outcomesScenario: A failed sign-in is recordedGiven a staff account fails a sign-inWhen the outcome is recordedThen an audit row is written for that sign-inScenario: A data change is recordedGiven a user makes a data changeWhen it is committedThen an audit row is written in the same transactionRule: Rows are kept for at least seven years and never editedScenario: An audit row is retained, not rotated awayGiven an audit row is older than a partition boundaryWhen partitioning runs for scaleThen the row is retained for at least seven years and is never editedRule: The log cannot be altered after the factScenario: Updating or deleting an audit row is refusedGiven an audit row has been writtenWhen any account attempts to update or delete itThen the database refuses the changeRule: The audit row is the record for a sensitive reveal or exportScenario: A reveal is recorded without a reason promptGiven a user reveals or exports sensitive dataWhen they take the actionThen an audit row is writtenAnd no separate reason prompt is requiredRule: Oversight reads the trail by role and only within its own organisationScenario: A per-role, per-tenant activity viewGiven an administrator or a reviewer opens the activity viewWhen they filter by actor or actionThen they see the matching audit rows for their own organisationAnd they never see another organisation's actions@edge-casesScenario Outline: Sensitive actions each leave a rowGiven a user performs a "<action>"When the action is committedThen an audit row is writtenExamples:| action || a reveal || an export || a sign-off |
Questions
Questions raised in planning, each with the decision taken.
Is an audit row enough on its own, or should a sensitive reveal also prompt for a reason?
A reason prompt adds friction to every reveal and export; the audit row already records who acted and when.
How we sized it
A function point measures what the software does — its inputs, outputs, lookups and the data it stores — regardless of language or how many lines it took. Each counted item is weighted by complexity: a user input counts 3–6 points, an output or report 4–7, a lookup 3–6, data the feature owns 7–10, and data read from elsewhere 5–7.
- The append-only audit store this feature ownsData the feature owns10
- View the activity log by roleLookup4
- Total14
Not counted here
- Writing an audit row on each action: plumbing, not a user function
Components touched
Append-only audit store
A partitioned store. Rows are only ever added; database permissions refuse any update or delete. Rows are retained for at least seven years; partitioning is for scale, not to delete old rows.
In-transaction emission
A sensitive action or data change writes its audit row in the same transaction, so a committed action is always recorded.
What is recorded
Data changes and sign-in outcomes are recorded: a sign-in, a failed sign-in, a lockout, a reveal, an export, a sign-off, a deactivation and a role change.
Activity view
A per-role, per-tenant view that filters the trail by actor or action, and never shows another organisation's actions.
Data touched
Audit storeappend
Append-only, partitioned rows: who acted, what they did, and when. Retained for at least seven years and never edited.
Audit catalogread
The map of actions that emit audit rows: a sign-in and a failed sign-in, a masked-value reveal, an unmasked export, a review sign-off, a user deactivation and a role change.
Security decisions
- The log is append-only, enforced by database permissions: any update or delete of an audit row is refused, and a test proves it.
- A sensitive action or data change writes its audit row in the same transaction, so a committed action is always recorded.
- The log records data changes and sign-in outcomes: sign-ins, failed sign-ins, lockouts, reveals, exports and sign-offs.
- Rows are retained for at least seven years and are never edited.
- The activity view is scoped by role and by tenant: an administrator or reviewer sees only their own organisation's actions.
Subtasks
- An append-only, partitioned audit store with database permissions refusing update and delete, retained for at least seven years.
- In-transaction emission of audit rows from data changes and sensitive actions.
- Recording of data changes and sign-in outcomes.
- A per-role, per-tenant activity view with filters.
How each scenario is verified
- A successful sensitive action records an audit rowAn integration test checks that a sensitive action writes an audit row in the same transaction.
- Update and delete of an audit row are refusedA test checks that the database permissions refuse any update or delete of an audit row.
- A data change and a staff sign-in outcome are recordedAn integration test checks that a data change and a sign-in for a staff account write an audit row.
- The activity view is scoped by role and tenantA test checks the role-and-tenant-scoped activity view.
Risk tier
Core A person approves every merge. This is a Core-tier change, so it also carries the fullest set of automated tests; a regression here affects the whole product, not one page.
Start here
Want this on your backlog?
Get a free baseline report on one repository, or scope a 3-month pilot measured against what your team’s work costs today.