feat: add operator and business reference fields to tenant ledgers

- Added `operator_user_id`, `biz_ref_type`, and `biz_ref_id` fields to the TenantLedger model for enhanced auditing and traceability.
- Updated the tenant ledgers query generation to include new fields.
- Introduced new API endpoint for retrieving tenant ledger records with filtering options based on the new fields.
- Enhanced Swagger documentation to reflect the new endpoint and its parameters.
- Created DTOs for admin ledger filtering and item representation.
- Implemented the admin ledger retrieval logic in the tenant service.
- Added database migration scripts to introduce new fields and indexes for efficient querying.
This commit is contained in:
2025-12-22 21:35:10 +08:00
parent 3cb2a6f586
commit 5dc0f89ac0
17 changed files with 983 additions and 171 deletions

View File

@@ -0,0 +1,41 @@
-- +goose Up
-- +goose StatementBegin
ALTER TABLE tenant_ledgers
ADD COLUMN IF NOT EXISTS operator_user_id bigint,
ADD COLUMN IF NOT EXISTS biz_ref_type varchar(32),
ADD COLUMN IF NOT EXISTS biz_ref_id bigint;
-- tenant_ledgers.operator_user_id操作者谁触发该流水
-- 用途:用于审计与风控追溯(例如后台代充值/代退款/调账等)。
COMMENT ON COLUMN tenant_ledgers.operator_user_id IS '操作者用户ID谁触发该流水admin/buyer/system用于审计与追责可为空历史数据或无法识别时';
-- tenant_ledgers.biz_ref_type/biz_ref_id业务引用幂等与追溯
-- 用途:在 idempotency_key 之外提供结构化引用(例如 order/refund/topup 等),便于报表与按业务对象追溯。
COMMENT ON COLUMN tenant_ledgers.biz_ref_type IS '业务引用类型order/refund/topup/etc与 biz_ref_id 组成可选的结构化幂等/追溯键';
COMMENT ON COLUMN tenant_ledgers.biz_ref_id IS '业务引用ID与 biz_ref_type 配合使用(例如 orders.id用于对账与审计';
-- 索引:按操作者检索敏感操作流水(后台审计用)。
CREATE INDEX IF NOT EXISTS ix_tenant_ledgers_tenant_operator ON tenant_ledgers(tenant_id, operator_user_id);
-- 索引:按业务引用快速定位同一业务对象的流水集合。
CREATE INDEX IF NOT EXISTS ix_tenant_ledgers_tenant_biz_ref ON tenant_ledgers(tenant_id, biz_ref_type, biz_ref_id);
-- 结构化幂等(可选):同一业务引用在同一流水类型下只能出现一条。
-- 说明biz_ref_* 允许为空;仅当两者都非空时才参与唯一性约束。
CREATE UNIQUE INDEX IF NOT EXISTS ux_tenant_ledgers_tenant_biz_ref_type_id_type
ON tenant_ledgers(tenant_id, biz_ref_type, biz_ref_id, type)
WHERE biz_ref_type IS NOT NULL AND biz_ref_id IS NOT NULL;
-- +goose StatementEnd
-- +goose Down
-- +goose StatementBegin
DROP INDEX IF EXISTS ux_tenant_ledgers_tenant_biz_ref_type_id_type;
DROP INDEX IF EXISTS ix_tenant_ledgers_tenant_biz_ref;
DROP INDEX IF EXISTS ix_tenant_ledgers_tenant_operator;
ALTER TABLE tenant_ledgers
DROP COLUMN IF EXISTS biz_ref_id,
DROP COLUMN IF EXISTS biz_ref_type,
DROP COLUMN IF EXISTS operator_user_id;
-- +goose StatementEnd

View File

@@ -0,0 +1,22 @@
-- +goose Up
-- +goose StatementBegin
-- 修正biz_ref_type/biz_ref_id 在 Go 模型侧为 string/int64非指针空值会写入 ''/0
-- 若唯一索引仅判断 NOT NULL会导致大量流水写入冲突。
-- 约束策略:仅当 biz_ref_type 非空 且 biz_ref_id > 0 时才参与唯一性约束。
DROP INDEX IF EXISTS ux_tenant_ledgers_tenant_biz_ref_type_id_type;
CREATE UNIQUE INDEX IF NOT EXISTS ux_tenant_ledgers_tenant_biz_ref_type_id_type
ON tenant_ledgers(tenant_id, biz_ref_type, biz_ref_id, type)
WHERE biz_ref_type IS NOT NULL AND biz_ref_type <> '' AND biz_ref_id IS NOT NULL AND biz_ref_id <> 0;
-- +goose StatementEnd
-- +goose Down
-- +goose StatementBegin
DROP INDEX IF EXISTS ux_tenant_ledgers_tenant_biz_ref_type_id_type;
-- Down 回滚为“仅判断 NOT NULL”的版本不建议在线上使用该版本
CREATE UNIQUE INDEX IF NOT EXISTS ux_tenant_ledgers_tenant_biz_ref_type_id_type
ON tenant_ledgers(tenant_id, biz_ref_type, biz_ref_id, type)
WHERE biz_ref_type IS NOT NULL AND biz_ref_id IS NOT NULL;
-- +goose StatementEnd