deletion

package
v0.9.0 Latest Latest
Warning

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

Go to latest
Published: Aug 6, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

Package deletion implements the GoatKit PaaS Entity Deletion system.

Provides soft delete (recycle bin + PII anonymisation), hard delete (purge), restore, tombstone logging, plugin cascade, and auto-purge.

Index

Constants

View Source
const (
	ActionSoftDelete = "soft_delete"
	ActionRestore    = "restore"
	ActionHardDelete = "hard_delete"
)

Deletion actions for tombstone log.

View Source
const (
	EntityTicket        = "ticket"
	EntityArticle       = "article"
	EntityContact       = "contact"
	EntityAgent         = "agent"
	EntityQueue         = "queue"
	EntityOrganisation  = "organisation"
	EntityCustomerGroup = "customer_group"
)

Entity types (matching customfields and other GoatKit entity keys).

View Source
const DefaultAnonymiseValue = "[DELETED]"

DefaultAnonymiseValue is the replacement for anonymised PII fields.

Variables

View Source
var AnonymiseConfig = map[string][]AnonymiseField{
	EntityTicket: {
		{Table: "ticket", Column: "title", Value: DefaultAnonymiseValue},
		{Table: "ticket", Column: "customer_id", Value: DefaultAnonymiseValue},
		{Table: "ticket", Column: "customer_user_id", Value: DefaultAnonymiseValue},
	},
	EntityContact: {
		{Table: "customer_user", Column: "first_name", Value: DefaultAnonymiseValue},
		{Table: "customer_user", Column: "last_name", Value: DefaultAnonymiseValue},
		{Table: "customer_user", Column: "email", Value: DefaultAnonymiseValue},
		{Table: "customer_user", Column: "phone", Value: DefaultAnonymiseValue},
		{Table: "customer_user", Column: "mobile", Value: DefaultAnonymiseValue},
		{Table: "customer_user", Column: "street", Value: DefaultAnonymiseValue},
		{Table: "customer_user", Column: "city", Value: DefaultAnonymiseValue},
		{Table: "customer_user", Column: "zip", Value: DefaultAnonymiseValue},
		{Table: "customer_user", Column: "country", Value: DefaultAnonymiseValue},
	},
	EntityAgent: {
		{Table: "users", Column: "first_name", Value: DefaultAnonymiseValue},
		{Table: "users", Column: "last_name", Value: DefaultAnonymiseValue},
	},
	EntityCustomerGroup: {
		{Table: "customer_company", Column: "name", Value: DefaultAnonymiseValue},
		{Table: "customer_company", Column: "street", Value: DefaultAnonymiseValue},
		{Table: "customer_company", Column: "city", Value: DefaultAnonymiseValue},
		{Table: "customer_company", Column: "zip", Value: DefaultAnonymiseValue},
		{Table: "customer_company", Column: "country", Value: DefaultAnonymiseValue},
	},
}

PII fields to anonymise per entity type.

Functions

func HandleAdminBatchHardDelete

func HandleAdminBatchHardDelete(svc *Service) gin.HandlerFunc

HandleAdminBatchHardDelete handles POST /admin/api/recycle-bin/batch-purge.

func HandleAdminBatchSoftDelete

func HandleAdminBatchSoftDelete(svc *Service) gin.HandlerFunc

HandleAdminBatchSoftDelete handles POST /admin/api/recycle-bin/batch-delete.

func HandleAdminDeletionLog

func HandleAdminDeletionLog(svc *Service) gin.HandlerFunc

HandleAdminDeletionLog handles GET /admin/api/recycle-bin/log/:entity_type/:entity_id.

func HandleAdminHardDelete

func HandleAdminHardDelete(svc *Service) gin.HandlerFunc

HandleAdminHardDelete handles POST /admin/api/recycle-bin/purge.

func HandleAdminRecycleBinList

func HandleAdminRecycleBinList(svc *Service) gin.HandlerFunc

HandleAdminRecycleBinList handles GET /admin/recycle-bin — lists recycle bin entries.

func HandleAdminRestore

func HandleAdminRestore(svc *Service) gin.HandlerFunc

HandleAdminRestore handles POST /admin/api/recycle-bin/restore.

func IsValidAction

func IsValidAction(a string) bool

IsValidAction checks if the given action is valid.

func RecycleBinToJSON

func RecycleBinToJSON(entries []RecycleBinEntry) (json.RawMessage, error)

RecycleBinToJSON converts a slice of entries to JSON bytes.

func RegisterPluginCascade

func RegisterPluginCascade(entityType, pluginName string, soft, hard CascadeHandler)

RegisterPluginCascade records a plugin's cascade handlers for an entity type. Either soft or hard may be nil — only the non-nil handler fires for its corresponding deletion mode. Re-registering the same (entityType, pluginName) pair replaces the prior entry, which is what plugin reloads want.

func SetPreDispatchHook

func SetPreDispatchHook(fn func(ctx context.Context, entityType string))

SetPreDispatchHook registers a hook that the deletion service calls before dispatching cascades for an entityType. Intended for the plugin manager to lazy-load plugins whose cascade closures aren't in the registry yet. Safe to call once at boot.

func UnregisterPluginCascades

func UnregisterPluginCascades(pluginName string)

UnregisterPluginCascades clears every cascade handler registered by pluginName. Called when a plugin is unloaded or replaced so stale closures don't keep dispatching to a gone plugin.

func ValidActions

func ValidActions() []string

ValidActions returns all valid tombstone log actions.

Types

type AnonymiseField

type AnonymiseField struct {
	Table  string // table name
	Column string // column name
	Value  string // replacement value (default: "[DELETED]")
}

AnonymiseField represents a field to anonymise on soft delete.

type CascadeHandler

type CascadeHandler func(ctx context.Context, entityType string, entityID int64) error

CascadeHandler is a function that a plugin registers to handle entity deletion.

type DeletionLog

type DeletionLog struct {
	ID         int64     `json:"id" db:"id"`
	EntityType string    `json:"entity_type" db:"entity_type"`
	EntityID   int64     `json:"entity_id" db:"entity_id"`
	Action     string    `json:"action" db:"action"`
	DeletedBy  int       `json:"deleted_by" db:"deleted_by"`
	DeletedAt  time.Time `json:"deleted_at" db:"deleted_at"`
	OrgID      *int64    `json:"org_id,omitempty" db:"org_id"`
	Reason     *string   `json:"reason,omitempty" db:"reason"`
}

DeletionLog represents a tombstone entry in gk_deletion_log.

type EntityDeleteHandler

type EntityDeleteHandler struct {
	// SoftDelete marks the entity as deleted using its native mechanism.
	// Returns the entity's display name for the recycle bin.
	SoftDelete func(db interface{}, entityID int64, userID int) (entityName string, err error)

	// HardDelete physically removes the entity and all linked data.
	HardDelete func(db interface{}, entityID int64) error

	// Restore reverses a soft delete.
	Restore func(db interface{}, entityID int64, userID int) error

	// Anonymise replaces PII fields with [DELETED].
	Anonymise func(db interface{}, entityID int64) error
}

EntityDeleteHandler defines how a specific entity type is soft/hard deleted.

type RecycleBinEntry

type RecycleBinEntry struct {
	ID         int64      `json:"id" db:"id"`
	EntityType string     `json:"entity_type" db:"entity_type"`
	EntityID   int64      `json:"entity_id" db:"entity_id"`
	EntityName *string    `json:"entity_name,omitempty" db:"entity_name"`
	DeletedBy  int        `json:"deleted_by" db:"deleted_by"`
	DeletedAt  time.Time  `json:"deleted_at" db:"deleted_at"`
	ExpiresAt  *time.Time `json:"expires_at,omitempty" db:"expires_at"`
	OrgID      *int64     `json:"org_id,omitempty" db:"org_id"`
}

RecycleBinEntry represents a soft-deleted entity in the recycle bin.

func (*RecycleBinEntry) ToJSON

func (e *RecycleBinEntry) ToJSON() map[string]any

ToJSON converts a RecycleBinEntry to a JSON-friendly map.

type Repository

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

Repository provides CRUD for the recycle bin and deletion log.

func NewRepository

func NewRepository() (*Repository, error)

NewRepository creates a repository using the global DB.

func NewRepositoryWithDB

func NewRepositoryWithDB(db *sql.DB) *Repository

NewRepositoryWithDB creates a repository with an explicit DB connection.

func (*Repository) AddToRecycleBin

func (r *Repository) AddToRecycleBin(entry *RecycleBinEntry) (int64, error)

AddToRecycleBin adds an entry to the recycle bin.

func (*Repository) AnonymiseEntity

func (r *Repository) AnonymiseEntity(entityType string, entityID int64) error

AnonymiseEntity replaces PII fields with [DELETED] for a given entity.

func (*Repository) GetDeletionLog

func (r *Repository) GetDeletionLog(entityType string, entityID int64) ([]DeletionLog, error)

GetDeletionLog retrieves deletion history for an entity.

func (*Repository) GetRecycleBinEntry

func (r *Repository) GetRecycleBinEntry(entityType string, entityID int64) (*RecycleBinEntry, error)

GetRecycleBinEntry retrieves a specific recycle bin entry.

func (*Repository) ListExpired

func (r *Repository) ListExpired() ([]RecycleBinEntry, error)

ListExpired returns recycle bin entries that have passed their expiry date.

func (*Repository) ListRecycleBin

func (r *Repository) ListRecycleBin(entityType string, orgID int64) ([]RecycleBinEntry, error)

ListRecycleBin lists entries in the recycle bin, optionally filtered by entity type.

func (*Repository) LogDeletion

func (r *Repository) LogDeletion(entry *DeletionLog) error

LogDeletion writes an immutable tombstone entry.

func (*Repository) RemoveFromRecycleBin

func (r *Repository) RemoveFromRecycleBin(entityType string, entityID int64) error

RemoveFromRecycleBin removes an entry from the recycle bin (after restore or hard delete).

type Service

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

Service orchestrates entity deletion: soft delete, restore, hard delete, anonymisation, cascade, and tombstone logging. Cascade handlers live in the package-level registry (see RegisterPluginCascade) — Service no longer holds instance-local handlers because NewService() is called per-request and any per-instance registrations would be lost before dispatch.

func NewService

func NewService() (*Service, error)

NewService creates a new deletion service.

func NewServiceWithDB

func NewServiceWithDB(db *sql.DB) *Service

NewServiceWithDB creates a deletion service with an explicit DB.

func (*Service) HardDelete

func (s *Service) HardDelete(ctx context.Context, entityType string, entityID int64, userID int, reason string) error

HardDelete permanently removes an entity and all linked data.

func (*Service) PurgeExpired

func (s *Service) PurgeExpired(ctx context.Context) (int, error)

PurgeExpired hard-deletes all expired recycle bin entries. Called by scheduled job.

func (*Service) RecycleBinList

func (s *Service) RecycleBinList(ctx context.Context, entityType string) ([]RecycleBinEntry, error)

RecycleBinList returns entries from the recycle bin.

func (*Service) Restore

func (s *Service) Restore(ctx context.Context, entityType string, entityID int64, userID int) error

Restore restores a soft-deleted entity from the recycle bin.

func (*Service) ScopeHardDelete

func (s *Service) ScopeHardDelete(ctx context.Context, entityType string, entityIDs []int64, userID int, reason string) (int, error)

ScopeHardDelete permanently removes all entities of a given type by IDs. Requires entity.hard_delete permission (checked by caller).

func (*Service) ScopeSoftDelete

func (s *Service) ScopeSoftDelete(ctx context.Context, entityType string, entityIDs []int64, userID int, reason string) (int, error)

ScopeSoftDelete soft-deletes all entities of a given type within an org scope. Used for project/exercise teardown.

func (*Service) SetRetention

func (s *Service) SetRetention(entityType string, days int)

SetRetention sets the retention period for an entity type.

func (*Service) SoftDelete

func (s *Service) SoftDelete(ctx context.Context, entityType string, entityID int64, userID int, reason string) error

SoftDelete soft-deletes an entity: marks as deleted, anonymises PII, adds to recycle bin, logs.

Jump to

Keyboard shortcuts

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