documents

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Aug 6, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Index

Constants

View Source
const (
	DefaultRetentionReminderHorizonDays           = 30
	DefaultRetentionReminderMaxAttempts           = 3
	DefaultRetentionReminderEscalateAfterAttempts = 3
)
View Source
const (
	EntityTypeInvoice      = "invoice"
	EntityTypeJournalEntry = "journal_entry"
	EntityTypePayment      = "payment"
	EntityTypeBankTxn      = "bank_transaction"
	EntityTypeAsset        = "asset"
	EntityTypeExpense      = "expense"
	EntityTypeQuote        = "quote"
	EntityTypeOrder        = "order"
	EntityTypeYearEndClose = "year_end_close"
	EntityTypeLeaveRecord  = "leave_record"
	EntityTypeTSD          = "tsd_declaration"
	EntityTypeKMD          = "kmd_declaration"

	DocumentTypeSupportingDocument = "supporting_document"
	DocumentTypeReceipt            = "receipt"
	DocumentTypeReconciliation     = "reconciliation_evidence"
	DocumentTypeContract           = "contract"
	DocumentTypeAssetRecord        = "asset_record"
	DocumentTypeTaxSupport         = "tax_support"
	DocumentTypeClosePack          = "close_pack"
	DocumentTypeOther              = "other"

	ReviewStatusPending  = "PENDING"
	ReviewStatusReviewed = "REVIEWED"
	ReviewStatusApproved = "APPROVED"
	ReviewStatusRejected = "REJECTED"

	LifecycleStatusActive     = "ACTIVE"
	LifecycleStatusSuperseded = "SUPERSEDED"
	LifecycleStatusArchived   = "ARCHIVED"
	LifecycleStatusDisposed   = "DISPOSED"

	RetentionReminderExpired          = "expired_retention"
	RetentionReminderDueSoon          = "retention_due_soon"
	RetentionReminderMissingRetention = "missing_retention"
	RetentionReminderPendingReview    = "pending_review"
	RetentionReminderRejected         = "rejected_document"

	MaxDocumentSizeBytes = 10 << 20
	MaxRetentionYears    = 100
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Document

type Document struct {
	ID              string     `json:"id"`
	TenantID        string     `json:"tenant_id"`
	EntityType      string     `json:"entity_type"`
	EntityID        string     `json:"entity_id"`
	DocumentType    string     `json:"document_type"`
	FileName        string     `json:"file_name"`
	ContentType     string     `json:"content_type"`
	FileSize        int64      `json:"file_size"`
	StorageKey      string     `json:"-"`
	Notes           string     `json:"notes,omitempty"`
	RetentionUntil  *time.Time `json:"retention_until,omitempty"`
	ReviewStatus    string     `json:"review_status"`
	ReviewNote      string     `json:"review_note,omitempty"`
	ReviewedBy      *string    `json:"reviewed_by,omitempty"`
	ReviewedAt      *time.Time `json:"reviewed_at,omitempty"`
	LifecycleStatus string     `json:"lifecycle_status"`
	LifecycleNote   string     `json:"lifecycle_note,omitempty"`
	SupersededBy    *string    `json:"superseded_by_document_id,omitempty"`
	LifecycleBy     *string    `json:"lifecycle_actioned_by,omitempty"`
	LifecycleAt     *time.Time `json:"lifecycle_actioned_at,omitempty"`
	LegalHold       bool       `json:"legal_hold"`
	LegalHoldNote   string     `json:"legal_hold_note,omitempty"`
	LegalHoldBy     *string    `json:"legal_hold_actioned_by,omitempty"`
	LegalHoldAt     *time.Time `json:"legal_hold_actioned_at,omitempty"`
	UploadedBy      string     `json:"uploaded_by"`
	CreatedAt       time.Time  `json:"created_at"`
}

type DocumentLegalHoldRequest

type DocumentLegalHoldRequest struct {
	LegalHold bool   `json:"legal_hold"`
	Note      string `json:"note"`
}

type DocumentLifecycleRequest

type DocumentLifecycleRequest struct {
	LifecycleStatus      string `json:"lifecycle_status"`
	LifecycleNote        string `json:"lifecycle_note,omitempty"`
	SupersededByDocument string `json:"superseded_by_document_id,omitempty"`
}

type DocumentPurgeCandidate

type DocumentPurgeCandidate struct {
	DocumentID      string     `json:"document_id"`
	EntityType      string     `json:"entity_type"`
	EntityID        string     `json:"entity_id"`
	DocumentType    string     `json:"document_type"`
	FileName        string     `json:"file_name"`
	RetentionUntil  *time.Time `json:"retention_until,omitempty"`
	LifecycleStatus string     `json:"lifecycle_status"`
	LegalHold       bool       `json:"legal_hold"`
	Eligible        bool       `json:"eligible"`
	SkipReason      string     `json:"skip_reason,omitempty"`
	Purged          bool       `json:"purged"`
}

type DocumentPurgeRequest

type DocumentPurgeRequest struct {
	AsOfDate time.Time `json:"-"`
	DryRun   bool      `json:"dry_run"`
	Limit    int       `json:"limit,omitempty"`
}

type DocumentPurgeResult

type DocumentPurgeResult struct {
	AsOfDate       string                   `json:"as_of_date"`
	DryRun         bool                     `json:"dry_run"`
	Limit          int                      `json:"limit"`
	CandidateCount int                      `json:"candidate_count"`
	EligibleCount  int                      `json:"eligible_count"`
	PurgedCount    int                      `json:"purged_count"`
	SkippedCount   int                      `json:"skipped_count"`
	Candidates     []DocumentPurgeCandidate `json:"candidates"`
}

type DocumentRemediationAction

type DocumentRemediationAction struct {
	Code               string `json:"code"`
	Severity           string `json:"severity"`
	Scope              string `json:"scope"`
	OwnerRole          string `json:"owner_role"`
	WorkspaceQueue     string `json:"workspace_queue,omitempty"`
	AssignmentKey      string `json:"assignment_key,omitempty"`
	Priority           string `json:"priority,omitempty"`
	DueInDays          int    `json:"due_in_days,omitempty"`
	Message            string `json:"message"`
	Action             string `json:"action"`
	EntityType         string `json:"entity_type,omitempty"`
	EntityID           string `json:"entity_id,omitempty"`
	DocumentID         string `json:"document_id,omitempty"`
	DocumentType       string `json:"document_type,omitempty"`
	FileName           string `json:"file_name,omitempty"`
	DueDate            string `json:"due_date,omitempty"`
	DaysUntilRetention *int   `json:"days_until_retention,omitempty"`
	UIPath             string `json:"ui_path,omitempty"`
	CLICommand         string `json:"cli_command,omitempty"`
}

func BuildEvidencePolicyRemediationActions

func BuildEvidencePolicyRemediationActions(result *EvidencePolicyResult, docs ...Document) []DocumentRemediationAction

BuildEvidencePolicyRemediationActions turns evidence-policy violations into accountant follow-up actions.

func BuildRetentionReviewRemediationActions

func BuildRetentionReviewRemediationActions(review *RetentionReview) []DocumentRemediationAction

BuildRetentionReviewRemediationActions turns retention reminder rows into accountant follow-up actions.

type EvidencePolicyRequest

type EvidencePolicyRequest struct {
	EntityType string               `json:"entity_type"`
	EntityIDs  []string             `json:"entity_ids"`
	Rules      []EvidencePolicyRule `json:"rules"`
}

type EvidencePolicyResult

type EvidencePolicyResult struct {
	EntityType                 string                      `json:"entity_type"`
	EntityID                   string                      `json:"entity_id"`
	Compliant                  bool                        `json:"compliant"`
	TotalCount                 int                         `json:"total_count"`
	PendingReviewCount         int                         `json:"pending_review_count"`
	ReviewedCount              int                         `json:"reviewed_count"`
	ApprovedCount              int                         `json:"approved_count"`
	RejectedCount              int                         `json:"rejected_count"`
	MissingEvidence            bool                        `json:"missing_evidence"`
	DocumentTypeCounts         map[string]int              `json:"document_type_counts"`
	ApprovedDocumentTypeCounts map[string]int              `json:"approved_document_type_counts"`
	RuleResults                []EvidencePolicyRuleResult  `json:"rule_results"`
	Violations                 []EvidencePolicyRuleResult  `json:"violations"`
	RemediationActions         []DocumentRemediationAction `json:"remediation_actions,omitempty"`
}

type EvidencePolicyRule

type EvidencePolicyRule struct {
	DocumentTypes   []string `json:"document_types,omitempty"`
	MinCount        int      `json:"min_count"`
	RequireApproved bool     `json:"require_approved"`
}

type EvidencePolicyRuleResult

type EvidencePolicyRuleResult struct {
	RuleIndex             int      `json:"rule_index"`
	DocumentTypes         []string `json:"document_types,omitempty"`
	RequiredCount         int      `json:"required_count"`
	MatchingCount         int      `json:"matching_count"`
	ApprovedMatchingCount int      `json:"approved_matching_count"`
	AcceptedCount         int      `json:"accepted_count"`
	RequireApproved       bool     `json:"require_approved"`
	Compliant             bool     `json:"compliant"`
	Message               string   `json:"message,omitempty"`
}

type GORMRepository

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

func NewGORMRepository

func NewGORMRepository(db *gorm.DB) *GORMRepository

func NewRepository

func NewRepository(db *pgxpool.Pool) *GORMRepository

func (*GORMRepository) CreateDocument

func (r *GORMRepository) CreateDocument(ctx context.Context, schemaName string, doc *Document) error

func (*GORMRepository) DeleteDocument

func (r *GORMRepository) DeleteDocument(ctx context.Context, schemaName, tenantID, documentID string) error

func (*GORMRepository) DocumentHasSupersededDependents

func (r *GORMRepository) DocumentHasSupersededDependents(ctx context.Context, schemaName, tenantID, documentID string) (bool, error)

func (*GORMRepository) EntityExists

func (r *GORMRepository) EntityExists(ctx context.Context, schemaName, tenantID, entityType, entityID string) (bool, error)

func (*GORMRepository) GetDocumentByID

func (r *GORMRepository) GetDocumentByID(ctx context.Context, schemaName, tenantID, documentID string) (*Document, error)

func (*GORMRepository) ListDocuments

func (r *GORMRepository) ListDocuments(ctx context.Context, schemaName, tenantID, entityType, entityID string) ([]Document, error)

func (*GORMRepository) ListRetentionReviewDocuments

func (r *GORMRepository) ListRetentionReviewDocuments(ctx context.Context, schemaName, tenantID string, cutoff time.Time, includeMissing bool) ([]Document, error)

func (*GORMRepository) ListReviewQueueDocuments

func (r *GORMRepository) ListReviewQueueDocuments(ctx context.Context, schemaName, tenantID string, filter ReviewQueueFilter) ([]Document, error)

func (*GORMRepository) ListReviewSummaries

func (r *GORMRepository) ListReviewSummaries(ctx context.Context, schemaName, tenantID, entityType string, entityIDs []string) (map[string]ReviewSummary, error)

func (*GORMRepository) ReviewDocument

func (r *GORMRepository) ReviewDocument(ctx context.Context, schemaName, tenantID, documentID, reviewStatus, reviewNote, reviewedBy string, reviewedAt time.Time) error

func (*GORMRepository) UpdateDocumentLegalHold

func (r *GORMRepository) UpdateDocumentLegalHold(ctx context.Context, schemaName, tenantID, documentID string, legalHold bool, note, actionedBy string, actionedAt time.Time) error

func (*GORMRepository) UpdateDocumentLifecycle

func (r *GORMRepository) UpdateDocumentLifecycle(ctx context.Context, schemaName, tenantID, documentID, lifecycleStatus, lifecycleNote, lifecycleBy string, lifecycleAt time.Time, supersededBy *string) error

func (*GORMRepository) UpdateDocumentRetention

func (r *GORMRepository) UpdateDocumentRetention(ctx context.Context, schemaName, tenantID, documentID string, retentionUntil *time.Time) error

type LocalStore

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

func NewLocalStore

func NewLocalStore(rootDir string) (*LocalStore, error)

func (*LocalStore) Delete

func (s *LocalStore) Delete(_ context.Context, key string) error

func (*LocalStore) Open

func (s *LocalStore) Open(_ context.Context, key string) (io.ReadCloser, error)

func (*LocalStore) Save

func (s *LocalStore) Save(_ context.Context, key string, content io.Reader) error

type Repository

type Repository interface {
	EntityExists(ctx context.Context, schemaName, tenantID, entityType, entityID string) (bool, error)
	CreateDocument(ctx context.Context, schemaName string, doc *Document) error
	ListDocuments(ctx context.Context, schemaName, tenantID, entityType, entityID string) ([]Document, error)
	ListReviewQueueDocuments(ctx context.Context, schemaName, tenantID string, filter ReviewQueueFilter) ([]Document, error)
	ListRetentionReviewDocuments(ctx context.Context, schemaName, tenantID string, cutoff time.Time, includeMissing bool) ([]Document, error)
	ListReviewSummaries(ctx context.Context, schemaName, tenantID, entityType string, entityIDs []string) (map[string]ReviewSummary, error)
	GetDocumentByID(ctx context.Context, schemaName, tenantID, documentID string) (*Document, error)
	DocumentHasSupersededDependents(ctx context.Context, schemaName, tenantID, documentID string) (bool, error)
	UpdateDocumentRetention(ctx context.Context, schemaName, tenantID, documentID string, retentionUntil *time.Time) error
	UpdateDocumentLifecycle(ctx context.Context, schemaName, tenantID, documentID, lifecycleStatus, lifecycleNote, lifecycleBy string, lifecycleAt time.Time, supersededBy *string) error
	UpdateDocumentLegalHold(ctx context.Context, schemaName, tenantID, documentID string, legalHold bool, note, actionedBy string, actionedAt time.Time) error
	ReviewDocument(ctx context.Context, schemaName, tenantID, documentID, reviewStatus, reviewNote, reviewedBy string, reviewedAt time.Time) error
	DeleteDocument(ctx context.Context, schemaName, tenantID, documentID string) error
}

type RetentionReminderAction

type RetentionReminderAction struct {
	DocumentID         string     `json:"document_id"`
	EntityType         string     `json:"entity_type"`
	EntityID           string     `json:"entity_id"`
	DocumentType       string     `json:"document_type"`
	FileName           string     `json:"file_name"`
	Action             string     `json:"action"`
	Message            string     `json:"message"`
	DaysUntilRetention *int       `json:"days_until_retention,omitempty"`
	RetentionUntil     *time.Time `json:"retention_until,omitempty"`
}

type RetentionReminderDeliveryResult

type RetentionReminderDeliveryResult struct {
	TenantID         string `json:"tenant_id"`
	RecipientEmail   string `json:"recipient_email,omitempty"`
	AsOfDate         string `json:"as_of_date"`
	CutoffDate       string `json:"cutoff_date"`
	ActionsFound     int    `json:"actions_found"`
	DeliveryAttempts int    `json:"delivery_attempts"`
	EmailSent        bool   `json:"email_sent"`
	Skipped          bool   `json:"skipped"`
	SkipReason       string `json:"skip_reason,omitempty"`
	Failed           bool   `json:"failed"`
	ErrorMessage     string `json:"error_message,omitempty"`
	Escalated        bool   `json:"escalated"`
	EscalationReason string `json:"escalation_reason,omitempty"`
	EmailLogID       string `json:"email_log_id,omitempty"`
}

RetentionReminderDeliveryResult summarizes one scheduled retention reminder run for a tenant.

type RetentionReminderEmailService

type RetentionReminderEmailService interface {
	GetTemplate(ctx context.Context, schemaName, tenantID string, templateType email.TemplateType) (*email.EmailTemplate, error)
	RenderTemplate(tmpl *email.EmailTemplate, data *email.TemplateData) (subject, bodyHTML, bodyText string, err error)
	SendEmail(ctx context.Context, schemaName, tenantID, emailType, recipient, recipientName, subject, bodyHTML, bodyText string, attachments []email.Attachment, relatedID string) (*email.EmailSentResponse, error)
}

RetentionReminderEmailService captures the email operations needed by scheduled retention reminders.

type RetentionReminderPolicy

type RetentionReminderPolicy struct {
	MaxAttempts           int
	EscalateAfterAttempts int
}

RetentionReminderPolicy controls scheduled retention reminder delivery retries and escalation.

type RetentionReminderService

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

RetentionReminderService sends a digest of document retention follow-up actions.

func NewRetentionReminderService

func NewRetentionReminderService(documentService *Service, emailService RetentionReminderEmailService) *RetentionReminderService

func NewRetentionReminderServiceWithPolicy

func NewRetentionReminderServiceWithPolicy(documentService *Service, emailService RetentionReminderEmailService, policy RetentionReminderPolicy) *RetentionReminderService

func (*RetentionReminderService) ProcessRetentionRemindersForTenant

func (s *RetentionReminderService) ProcessRetentionRemindersForTenant(ctx context.Context, tenantID, schemaName, companyName, recipientEmail string, asOf time.Time, horizonDays int, includeMissing bool) (RetentionReminderDeliveryResult, error)

type RetentionReview

type RetentionReview struct {
	AsOfDate              string                      `json:"as_of_date"`
	CutoffDate            string                      `json:"cutoff_date"`
	TotalCount            int                         `json:"total_count"`
	ExpiredCount          int                         `json:"expired_count"`
	DueSoonCount          int                         `json:"due_soon_count"`
	MissingRetentionCount int                         `json:"missing_retention_count"`
	PendingReviewCount    int                         `json:"pending_review_count"`
	RejectedCount         int                         `json:"rejected_count"`
	ReminderActions       []RetentionReminderAction   `json:"reminder_actions"`
	RemediationActions    []DocumentRemediationAction `json:"remediation_actions,omitempty"`
	Documents             []Document                  `json:"documents"`
}

type ReviewDocumentRequest

type ReviewDocumentRequest struct {
	ReviewStatus string `json:"review_status"`
	ReviewNote   string `json:"review_note,omitempty"`
}

type ReviewQueue

type ReviewQueue struct {
	EntityType         string     `json:"entity_type,omitempty"`
	DocumentType       string     `json:"document_type,omitempty"`
	ReviewStatus       string     `json:"review_status"`
	Limit              int        `json:"limit"`
	TotalCount         int        `json:"total_count"`
	PendingReviewCount int        `json:"pending_review_count"`
	ReviewedCount      int        `json:"reviewed_count"`
	ApprovedCount      int        `json:"approved_count"`
	RejectedCount      int        `json:"rejected_count"`
	Documents          []Document `json:"documents"`
}

type ReviewQueueFilter

type ReviewQueueFilter struct {
	EntityType   string `json:"entity_type,omitempty"`
	DocumentType string `json:"document_type,omitempty"`
	ReviewStatus string `json:"review_status,omitempty"`
	Limit        int    `json:"limit,omitempty"`
}

type ReviewSummary

type ReviewSummary struct {
	EntityType         string `json:"entity_type"`
	EntityID           string `json:"entity_id"`
	TotalCount         int    `json:"total_count"`
	PendingReviewCount int    `json:"pending_review_count"`
	ReviewedCount      int    `json:"reviewed_count"`
	ApprovedCount      int    `json:"approved_count"`
	RejectedCount      int    `json:"rejected_count"`
	MissingEvidence    bool   `json:"missing_evidence"`
	HasPendingReview   bool   `json:"has_pending_review"`
	HasRejected        bool   `json:"has_rejected"`
}

type Service

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

func NewService

func NewService(repo Repository, store Store) *Service

func (*Service) DeleteDocument

func (s *Service) DeleteDocument(ctx context.Context, schemaName, tenantID, documentID string) error

func (*Service) EvaluateEvidencePolicy

func (s *Service) EvaluateEvidencePolicy(ctx context.Context, schemaName, tenantID string, req *EvidencePolicyRequest) ([]EvidencePolicyResult, error)

func (*Service) GetRetentionReview

func (s *Service) GetRetentionReview(ctx context.Context, schemaName, tenantID string, asOfDate time.Time, horizonDays int, includeMissing bool) (*RetentionReview, error)

func (*Service) GetReviewQueue

func (s *Service) GetReviewQueue(ctx context.Context, schemaName, tenantID string, filter ReviewQueueFilter) (*ReviewQueue, error)

func (*Service) ListDocuments

func (s *Service) ListDocuments(ctx context.Context, schemaName, tenantID, entityType, entityID string) ([]Document, error)

func (*Service) ListReviewSummaries

func (s *Service) ListReviewSummaries(ctx context.Context, schemaName, tenantID, entityType string, entityIDs []string) ([]ReviewSummary, error)

func (*Service) MarkDocumentReviewed

func (s *Service) MarkDocumentReviewed(ctx context.Context, schemaName, tenantID, documentID, reviewedBy string) (*Document, error)

func (*Service) OpenDocument

func (s *Service) OpenDocument(ctx context.Context, schemaName, tenantID, documentID string) (*Document, io.ReadCloser, error)

func (*Service) PurgeExpiredDocuments

func (s *Service) PurgeExpiredDocuments(ctx context.Context, schemaName, tenantID string, req DocumentPurgeRequest) (*DocumentPurgeResult, error)

func (*Service) ReviewDocument

func (s *Service) ReviewDocument(ctx context.Context, schemaName, tenantID, documentID, reviewedBy string, req *ReviewDocumentRequest) (*Document, error)

func (*Service) UpdateDocumentLegalHold

func (s *Service) UpdateDocumentLegalHold(ctx context.Context, schemaName, tenantID, documentID, actionedBy string, req *DocumentLegalHoldRequest) (*Document, error)

func (*Service) UpdateDocumentLifecycle

func (s *Service) UpdateDocumentLifecycle(ctx context.Context, schemaName, tenantID, documentID, actionedBy string, req *DocumentLifecycleRequest) (*Document, error)

func (*Service) UpdateDocumentRetention

func (s *Service) UpdateDocumentRetention(ctx context.Context, schemaName, tenantID, documentID string, retentionUntil *time.Time) (*Document, error)

func (*Service) UploadDocument

func (s *Service) UploadDocument(ctx context.Context, schemaName, tenantID string, req *UploadDocumentRequest, content io.Reader) (*Document, error)

type Store

type Store interface {
	Save(ctx context.Context, key string, content io.Reader) error
	Open(ctx context.Context, key string) (io.ReadCloser, error)
	Delete(ctx context.Context, key string) error
}

type UploadDocumentRequest

type UploadDocumentRequest struct {
	EntityType         string
	EntityID           string
	DocumentType       string
	FileName           string
	ContentType        string
	FileSize           int64
	Notes              string
	RetentionUntil     *time.Time
	RetentionYears     int
	ReplacesDocumentID string
	ReplacementNote    string
	UploadedBy         string
}

Jump to

Keyboard shortcuts

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