retention

package
v1.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 10, 2026 License: Apache-2.0 Imports: 10 Imported by: 0

Documentation

Overview

Package retention is the data-lifecycle layer (roadmap E2): a generalized legal hold over any entity (not just documents) and a Data Subject Request ledger (export/erasure) with a statutory-override reason. Per-record-class disposition over product tables is orchestrated by the scheduler with product-supplied callbacks; these are the concrete, framework-owned primitives a compliance product would otherwise hand-roll. All operations run in the caller's tenant transaction (RLS-scoped).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type DSR

type DSR struct {
	// contains filtered or unexported fields
}

DSR is the Data Subject Request ledger (export / erasure). It tracks the request lifecycle and the statutory-override reason when an erasure is refused because a retention obligation (or a legal hold) forbids it. The actual data export/erasure is performed by product-registered callbacks per record class; this ledger is the auditable request record.

func NewDSR

func NewDSR(idgen model.IDGen) *DSR

NewDSR builds the DSR ledger service.

func (*DSR) Complete

func (d *DSR) Complete(ctx context.Context, db database.TenantDB, id uuid.UUID) error

Complete marks a pending request fulfilled (after the product has performed the export/erasure). KindConflict if the request is not pending.

func (*DSR) Get

func (d *DSR) Get(ctx context.Context, db database.TenantDB, id uuid.UUID) (Request, error)

Get reads a DSR request.

func (*DSR) Open

func (d *DSR) Open(ctx context.Context, db database.TenantDB, subjectRef string, kind Kind) (uuid.UUID, error)

Open records a new DSR for a subject. subjectRef is the product's subject identifier. Runs in the caller's tenant transaction.

func (*DSR) Reject

func (d *DSR) Reject(ctx context.Context, db database.TenantDB, id uuid.UUID, overrideReason string) error

Reject marks a pending request refused, recording the statutory-override reason (e.g. "retained under §X for 7 years"). KindConflict if not pending.

type DisposeFunc

type DisposeFunc func(ctx context.Context, db database.TenantDB, before time.Time) (int, error)

DisposeFunc disposes the class's records whose retention lapsed on/before `before` — deleting or anonymizing them — and returns how many. It must itself skip records under legal hold (consult Holds.IsHeld). Runs in the caller's tenant transaction.

type Engine

type Engine struct {
	// contains filtered or unexported fields
}

Engine orchestrates disposition and DSR fulfilment over the registered classes.

func NewEngine

func NewEngine(reg *Registry, dsr *DSR) *Engine

NewEngine wires the engine over a record-class registry and the DSR ledger.

func (*Engine) RunErasure

func (e *Engine) RunErasure(ctx context.Context, db database.TenantDB, requestID uuid.UUID) (int, error)

RunErasure fulfils a pending erasure DSR: it invokes each class's Erase for the subject and marks the request completed, returning the total records affected. A legal hold that forbids erasure must be enforced by the product's Erase callback (skip held records) or by rejecting the DSR first with a reason.

func (*Engine) RunExport

func (e *Engine) RunExport(ctx context.Context, db database.TenantDB, requestID uuid.UUID) (map[string]any, error)

RunExport fulfils a pending export DSR: it invokes each class's Export for the subject, aggregates the results by class key, marks the request completed, and returns the payload. All work is in the caller's tenant tx, so a failure leaves the request pending and rolls back partial exports.

func (*Engine) SweepDisposition

func (e *Engine) SweepDisposition(ctx context.Context, db database.TenantDB, at time.Time) (int, error)

SweepDisposition runs each class's Dispose for records whose retention lapsed by `at`, in the caller's tenant transaction, returning the total disposed. Classes without a Dispose callback are skipped. Intended to be driven periodically by the scheduler.

type EraseFunc

type EraseFunc func(ctx context.Context, db database.TenantDB, subjectRef string) (int, error)

EraseFunc erases (or anonymizes) the class's data for a DSR subject and returns how many records were affected. Runs in the caller's tenant transaction.

type ExportFunc

type ExportFunc func(ctx context.Context, db database.TenantDB, subjectRef string) (map[string]any, error)

ExportFunc returns the class's data for a DSR subject (for a data-portability export). Runs in the caller's tenant transaction.

type Hold

type Hold struct {
	ID         uuid.UUID
	EntityType string
	EntityID   uuid.UUID
	Reason     string
}

Hold is an active legal hold.

type Holds

type Holds struct {
	// contains filtered or unexported fields
}

Holds manages generalized legal holds. A hold on (entityType, entityID) blocks disposition of that entity until released — retention sweeps consult IsHeld.

func NewHolds

func NewHolds(idgen model.IDGen) *Holds

NewHolds builds the legal-hold service.

func (*Holds) IsHeld

func (h *Holds) IsHeld(ctx context.Context, db database.TenantDB, entityType string, entityID uuid.UUID) (bool, error)

IsHeld reports whether the entity has an active legal hold.

func (*Holds) List

func (h *Holds) List(ctx context.Context, db database.TenantDB) ([]Hold, error)

List returns the tenant's active legal holds.

func (*Holds) Place

func (h *Holds) Place(ctx context.Context, db database.TenantDB, entityType string, entityID uuid.UUID, reason string) (uuid.UUID, error)

Place puts an entity under legal hold. Reason is required. A second active hold on the same entity is a KindConflict (there is at most one active hold).

func (*Holds) Release

func (h *Holds) Release(ctx context.Context, db database.TenantDB, id uuid.UUID) error

Release lifts an active hold by id. KindNotFound if it is not an active hold.

type Kind

type Kind string

Kind is the DSR type.

const (
	KindExport  Kind = "export"
	KindErasure Kind = "erasure"
)

type RecordClass

type RecordClass struct {
	Key       string
	Retention time.Duration // documentary; the Dispose callback enforces it
	Dispose   DisposeFunc
	Export    ExportFunc
	Erase     EraseFunc
}

RecordClass declares one class of product data and how to dispose/export/erase it. Any callback may be nil (a class with no Export contributes nothing to an export, etc.).

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry is the boot-time catalog of record classes.

func NewRegistry

func NewRegistry() *Registry

NewRegistry builds an empty registry.

func (*Registry) Err

func (r *Registry) Err() error

Err returns the first registration error, if any.

func (*Registry) Register

func (r *Registry) Register(c RecordClass)

Register adds a record class. Keys must be non-empty and unique; the first error is retained and surfaced by Err (checked at boot).

type Request

type Request struct {
	ID             uuid.UUID
	SubjectRef     string
	Kind           Kind
	Status         string // pending | completed | rejected
	OverrideReason string
}

Request is a DSR ledger row.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL