package docgov import ( "context" "sync" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgxpool" ) // GovernanceEngine 受控文档编制/审核/批准与认领治理引擎 type GovernanceEngine struct { pool *pgxpool.Pool sm *StateMachine mu sync.RWMutex memDocs map[string]*DocumentRecord memComms map[string][]*DocumentComment memProps map[string]*ChangeProposal memAudits map[string][]*AuditLog onApprovedHook func(ctx context.Context, doc *DocumentRecord) onApprovedHooks []func(ctx context.Context, doc *DocumentRecord) onPendingDigest PendingSupplementNotify onLifecycleNotify LifecycleNotify OnFinalArtifact func(ctx context.Context, doc *DocumentRecord, markdown []byte, snapshotID int64) OnFinalArtifactTX func(ctx context.Context, tx pgx.Tx, doc *DocumentRecord, markdown []byte, snapshotID int64) error // docLocks 按 doc_id 分锁(T20 B3);meta 全局锁只保护分锁表本身。 docLocks *docLockIndex } // LifecycleNotify is invoked after a successful governance state transition (outside engine lock). type LifecycleNotify func(ctx context.Context, action string, doc *DocumentRecord, actorID int64, actorName, detail string) // SetLifecycleNotify registers the post-transition notification hook. func (e *GovernanceEngine) SetLifecycleNotify(hook LifecycleNotify) { if e == nil { return } e.mu.Lock() defer e.mu.Unlock() e.onLifecycleNotify = hook } // SetPendingDigestNotify registers a callback when pending supplements are digested on return to drafting. func (e *GovernanceEngine) SetPendingDigestNotify(hook PendingSupplementNotify) { if e == nil { return } e.mu.Lock() defer e.mu.Unlock() e.onPendingDigest = hook } // SetOnApprovedHook 注册文档终审批准时的回调钩子 func (e *GovernanceEngine) SetOnApprovedHook(hook func(ctx context.Context, doc *DocumentRecord)) { e.mu.Lock() defer e.mu.Unlock() e.onApprovedHook = hook } // AddOnApprovedHook 追加文档终审批准回调(与 SetOnApprovedHook 并存)。 func (e *GovernanceEngine) AddOnApprovedHook(hook func(ctx context.Context, doc *DocumentRecord)) { if hook == nil { return } e.mu.Lock() defer e.mu.Unlock() e.onApprovedHooks = append(e.onApprovedHooks, hook) } func (e *GovernanceEngine) runApprovedHooks(ctx context.Context, doc *DocumentRecord) { var primary func(context.Context, *DocumentRecord) var extra []func(context.Context, *DocumentRecord) e.mu.Lock() primary = e.onApprovedHook extra = append([]func(context.Context, *DocumentRecord){}, e.onApprovedHooks...) e.mu.Unlock() if primary != nil { primary(ctx, doc) } for _, hook := range extra { if hook != nil { hook(ctx, doc) } } } func (e *GovernanceEngine) UsingPG() bool { return e != nil && e.pool != nil } func (e *GovernanceEngine) RunApprovedHooksAfterCommit(ctx context.Context, doc *DocumentRecord) { e.runApprovedHooks(ctx, doc) } // NewGovernanceEngine 初始化治理引擎 func NewGovernanceEngine(pool *pgxpool.Pool) *GovernanceEngine { return &GovernanceEngine{ pool: pool, sm: NewStateMachine(), memDocs: make(map[string]*DocumentRecord), memComms: make(map[string][]*DocumentComment), memProps: make(map[string]*ChangeProposal), memAudits: make(map[string][]*AuditLog), docLocks: newDocLockIndex(), } }