feat: add phone frequency controls and modularize codebase

This commit is contained in:
hectorzhao
2026-07-31 22:25:23 +08:00
parent 0af671b4ed
commit ca4f591a13
216 changed files with 41579 additions and 23694 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+65
View File
@@ -0,0 +1,65 @@
{
"version": "R11",
"stableEntry": "src/apps/admin/AdminChannelsPage.tsx",
"stableExport": "AdminChannelsPage",
"maxStableEntryLines": 300,
"modules": {
"src/apps/admin/channels/ChannelFormModal.tsx": ["ChannelFormModal"],
"src/apps/admin/channels/SmsTestModal.tsx": ["SmsTestModal"],
"src/apps/admin/channels/ChannelTable.tsx": ["ChannelTable"],
"src/apps/admin/channels/ChannelLogModal.tsx": ["ChannelLogModal"],
"src/apps/admin/channels/channelModel.ts": [
"formatLogDetail",
"resolveChannelStatus",
"mapApiChannel",
"mapUiStatusToApi",
"buildChannelPayload"
]
},
"apiCalls": {
"src/apps/admin/AdminChannelsPage.tsx": [
"listChannelsPage",
"getSendQuality",
"listChannelConnections",
"updateChannel",
"createChannel",
"changeChannelStatus",
"copyChannel",
"listChannelConnectionLogs"
],
"src/apps/admin/channels/SmsTestModal.tsx": ["testChannel"]
},
"styleFile": "src/apps/admin/channels/AdminChannelsPage.css",
"styleImport": "./channels/AdminChannelsPage.css",
"pageStyleSelectors": [
".sms-channel-page",
".sms-channel-filter",
".sms-channel-table",
".sms-channel-total",
".sms-channel-identity",
".sms-channel-carrier-price",
".sms-channel-status-cell",
".sms-channel-quality",
".sms-channel-rate",
".sms-channel-actions",
".sms-channel-pagination",
".sms-channel-form",
".sms-channel-radio-row",
".sms-channel-inline-field",
".sms-test-",
".channel-log-",
".channel-connection-summary"
],
"sharedSelectorsKeptGlobal": [],
"sharedSelectorsKeptInAdmin": [".channel-confirm"],
"interactionLabels": [
"添加通道",
"查询",
"重置",
"报备详情",
"编辑",
"复制通道",
"发送测试",
"连接日志"
]
}
@@ -0,0 +1,88 @@
{
"version": "R11",
"stableEntry": "src/apps/admin/AdminEnterpriseApplicationsPage.tsx",
"stableExport": "AdminEnterpriseApplicationsPage",
"maxStableEntryLines": 300,
"modules": {
"src/apps/admin/enterprise-applications/EnterpriseApplicationFilter.tsx": [
"EnterpriseApplicationFilter"
],
"src/apps/admin/enterprise-applications/EnterpriseApplicationTable.tsx": [
"EnterpriseApplicationTable"
],
"src/apps/admin/enterprise-applications/ApplicationLifecycleModals.tsx": [
"ConfirmModal",
"DeactivateApplicationModal",
"AddApplicationModal"
],
"src/apps/admin/enterprise-applications/ApplicationParamsModals.tsx": [
"CmppParamsModal",
"HttpParamsModal"
],
"src/apps/admin/enterprise-applications/CmppConnectionModal.tsx": [
"CmppConnectionModal"
],
"src/apps/admin/enterprise-applications/applicationModel.ts": [
"connectionStateMeta",
"formatCmppParams",
"mapConnection",
"mapApplication"
]
},
"apiCalls": {
"src/apps/admin/AdminEnterpriseApplicationsPage.tsx": [
"listEnterpriseApplicationsPage",
"listTenants",
"changeApplicationStatus",
"getApplicationDeactivationPreview",
"getApplicationCmppParams",
"getApplicationHttpApiConfig"
]
},
"styleFile": "src/apps/admin/enterprise-applications/AdminEnterpriseApplicationsPage.css",
"styleImport": "./enterprise-applications/AdminEnterpriseApplicationsPage.css",
"pageStyleSelectors": [
".admin-application-filter",
".cmpp-status-cell",
".enterprise-app-actions",
".cmpp-connection-detail",
".cmpp-connection-summary",
".cmpp-connection-list",
".cmpp-connection-card",
".cmpp-param-detail",
".cmpp-param-grid",
".cmpp-param-copy",
".app-create-modal"
],
"sharedSelectorsKeptGlobal": [],
"sharedSelectorsKeptInAdmin": [
".admin-split-filter",
".admin-split-filter__actions",
".admin-confirm-text"
],
"sharedSelectorsKeptInComponents": [
".template-modal-title",
".form-grid"
],
"sharedSelectorsKeptInShell": [
".section-stack"
],
"interactionLabels": [
"企业名称",
"企业应用名称",
"状态",
"查询",
"重置",
"添加应用",
"短信应用",
"彩信应用",
"编辑",
"停用",
"启用",
"删除",
"CMPP参数",
"HTTP参数",
"新建企业应用",
"CMPP连接详情"
]
}
@@ -0,0 +1,134 @@
{
"version": "R4",
"source": "src/apps/admin/AdminEnterpriseSignaturesPage.tsx",
"originalLines": 885,
"movedFunctions": [
{
"name": "carrierLabel",
"canonicalSha256": "cc074c9091c0c2198d8b38362242916c08457d2c7ecf9f0d7bb4c3a8e4912afd"
},
{
"name": "CarrierReportTag",
"canonicalSha256": "2ee4038f46fdb4c8e9af1fdbc5f7959f38d2360e081c7dd3b44d465be3b6cfef"
},
{
"name": "signatureCardVisual",
"canonicalSha256": "1cea544821c9c03b7c544644d5865e57810ae6f9c8d05d577ed104811ada63ec"
},
{
"name": "AuditStatusTag",
"canonicalSha256": "1a04a56dd4de4cb1988a15648738aa3cb8d8918dfac2ff15c159b663fa8756ee"
},
{
"name": "readDrainagePayload",
"canonicalSha256": "fa3d75286a89171511c9c4e52f4126b036128bbc91b15aedaa00360a4c7bbbcd"
},
{
"name": "buildDrainagePayload",
"canonicalSha256": "13ee432e93b20ba3dc104bd8be3cee31ae2092dbb244d6e12ad8eba018ad2d22"
},
{
"name": "normalizeReportValues",
"canonicalSha256": "ff050e5d4a1b2be8a606cb595a25d137bd0f08105e0f3cba8977dbb115612864"
},
{
"name": "hasMissingRequiredReportValue",
"canonicalSha256": "609c62b77ceee37afe961926fa897af0c3e156ce589709ae657a0038a38b481d"
},
{
"name": "normalizeUploadedFile",
"canonicalSha256": "f276b6ff6b3b9b6432ac638bd228c73923b00816e0f14dae5b43e0cb32393f08"
},
{
"name": "normalizeCarrierStatus",
"canonicalSha256": "5e4edd6bf9cacd5bcf6aa6197855780e03ab29cd3f5279b41a0eba2125ab1317"
},
{
"name": "formatDate",
"canonicalSha256": "fa6a491d6fa4f4e517cc9f3c07563424c9f7a8df30535274ddcbf6119c304b42"
},
{
"name": "SignatureUploadBox",
"canonicalSha256": "1e5c4d1e82c72ffd3bc1ddbd17628c1901d5ba81b0bb3ae161bcfb291a46dd98"
},
{
"name": "DynamicReportFields",
"canonicalSha256": "6370195b7a7afe5505003f233e31c07cbd3dac0ca55ce68b9859e83a827421f9"
},
{
"name": "SignatureFormModal",
"canonicalSha256": "664e1cd87309c64c03f9198543171bb519d448eec4a83cf890444fee16d6dd66"
},
{
"name": "DrainageFormModal",
"canonicalSha256": "0e63725f10e8021e0a7beb5a71f52773ce271faea137735d3fc184f07a39c6d6"
},
{
"name": "SignatureReportModal",
"canonicalSha256": "7439104e171e7d9eeb8449f497696b6d3736b881195c0b96a1a096079ba0789b"
},
{
"name": "ChannelReportStatusModal",
"canonicalSha256": "d32f8d7d3025ee286ed7898ed41a22404db3d684b80d23819965b3332e0e8310"
},
{
"name": "DrainageReportModal",
"canonicalSha256": "716a2d480a4b652ee951de0306854f1d8f6d72759d7b2fbffbfbb600abc8a789"
},
{
"name": "DrainageReportStatusModal",
"canonicalSha256": "ef692f08d2140e82e40fc12f716b15a902e3c66948140e8512f5a317c629215c"
},
{
"name": "ConfirmModal",
"canonicalSha256": "2f71bdc2f8044ca9b403affbb0cb3f31587e4c004a90e9e0836aa6143033b6da"
}
],
"tableJsxSha256": "203ec16e0ca67f0dafea08d659e84db02dd8346d06a52f41378625e39a43def7",
"apiCalls": [
"listEnterpriseSignaturesPage",
"listTenants",
"listEnterpriseApplicationOptions",
"updateEnterpriseSignature",
"createEnterpriseSignature",
"updateDrainageInfo",
"createDrainageInfo",
"changeDrainageInfoStatus"
],
"stateNames": [
"activeTab",
"applications",
"deleteTarget",
"drainageModal",
"drainageReport",
"drainageStatusTarget",
"enterpriseKeyword",
"appliedEnterpriseKeyword",
"applicationKeyword",
"appliedApplicationKeyword",
"drainageKeyword",
"appliedDrainageKeyword",
"error",
"expandedSignatureId",
"signatureKeyword",
"appliedSignatureKeyword",
"signatureModal",
"signatureReport",
"reportStatusTarget",
"signatures",
"total",
"tenants",
"page",
"importOpen",
"message"
],
"files": [
"signature.types.ts",
"signature.helpers.tsx",
"SignatureMaterialFields.tsx",
"SignatureFormModal.tsx",
"DrainageFormModal.tsx",
"SignatureReportModals.tsx",
"EnterpriseSignaturesTable.tsx"
]
}
@@ -0,0 +1,90 @@
{
"styleFile": "src/styles/admin.css",
"globalStyleFile": "src/styles/global.css",
"entryFile": "src/main.tsx",
"marker": "Admin-only shared page patterns migrated from global.css in R11 step 8.",
"minimumRuleCount": 117,
"minimumSelectorCount": 141,
"ownedClassPrefixes": [
"admin-audit-",
"admin-detail-metric-",
"admin-report-filter-",
"admin-security-",
"admin-split-",
"admin-system-",
"admin-task-",
"audit-filter-",
"downstream-breakdown-",
"downstream-bucket-"
],
"ownedExactClasses": [
"admin-app-form-row",
"admin-app-form-row--wide",
"admin-confirm-text",
"admin-uplink-empty-match",
"audit-actions",
"channel-confirm",
"channel-field-config",
"channel-field-config-title",
"channel-field-section-head",
"channel-report-empty",
"enterprise-form-footer",
"page-inline-hint",
"report-history",
"report-record-detail",
"report-record-page",
"report-task-table-card",
"signature-alert",
"sms-audit-filter"
],
"allowedContextClasses": [
"mini-status-card",
"page-heading"
],
"requiredSelectors": [
".audit-filter-grid",
".audit-filter-actions",
".admin-task-filter",
".admin-task-table-card .ui-table",
".admin-security-filter",
".admin-system-toolbar",
".admin-system-modal-form",
".admin-report-filter-grid--profit",
".admin-split-filter",
".admin-confirm-text",
".downstream-breakdown-table",
".channel-field-config",
".signature-alert"
],
"usageRequirements": {
"audit-filter-actions": 7,
"admin-task-filter": 7,
"admin-confirm-text": 5,
"admin-task-table-card": 5,
"admin-system-modal-form": 4,
"admin-report-filter-grid": 3,
"admin-security-filter": 3,
"admin-split-filter": 3,
"admin-system-page": 3,
"downstream-breakdown-table": 2,
"enterprise-form-footer": 2
},
"responsiveRequirements": [
{
"media": "(max-width: 780px)",
"selector": ".admin-task-filter"
},
{
"media": "(max-width: 780px)",
"selector": ".admin-report-filter-grid"
},
{
"media": "(max-width: 780px)",
"selector": ".audit-filter-actions"
},
{
"media": "(max-width: 360px)",
"selector": ".audit-filter-actions"
}
]
}
+77
View File
@@ -0,0 +1,77 @@
{
"version": "R11",
"stableEntry": "src/apps/admin/AdminSmsRecordsPage.tsx",
"stableExport": "AdminSmsRecordsPage",
"maxStableEntryLines": 220,
"modules": {
"src/apps/admin/sms-records/SmsRecordFilter.tsx": ["SmsRecordFilter"],
"src/apps/admin/sms-records/SmsRecordList.tsx": ["SmsRecordList"],
"src/apps/admin/sms-records/SendDetailModal.tsx": ["SendDetailModal"],
"src/apps/admin/sms-records/smsRecordModel.ts": [
"getDate",
"getTime",
"getClock",
"getRecordStatus",
"getRecordStatusLabel",
"getReceiptNotice",
"getCarrierLabel",
"buildRouteRows",
"downloadCsv",
"defaultSmsRecordDateRange"
]
},
"apiCalls": {
"src/apps/admin/AdminSmsRecordsPage.tsx": [
"listOperationMessages",
"listTenants",
"listEnterpriseApplicationOptions",
"listMessageSegmentAudits",
"exportOperationMessages"
]
},
"styleFile": "src/apps/admin/sms-records/AdminSmsRecordsPage.css",
"styleImport": "./sms-records/AdminSmsRecordsPage.css",
"pageStyleSelectors": [
".admin-sms-records-page",
".admin-sms-record-filter",
".admin-sms-record-table-card",
".admin-sms-record-toolbar",
".admin-sms-record-list",
".admin-sms-record-card",
".admin-sms-record-status",
".admin-sms-record-detail-link",
".admin-sms-send-detail",
".admin-sms-detail-overview",
".admin-sms-detail-notice",
".admin-sms-detail-content",
".admin-sms-detail-status-grid",
".admin-sms-detail-failure",
".admin-sms-segment-list",
".admin-sms-segment-card",
".admin-sms-route-list"
],
"sharedSelectorsKeptGlobal": [
".muted"
],
"sharedSelectorsKeptInComponents": [
".template-modal-title",
".ui-table__empty"
],
"interactionLabels": [
"企业",
"应用",
"提交日期",
"手机号码",
"运营商",
"短信内容",
"通道名称",
"发送状态",
"查询",
"重置",
"导出CSV",
"查看发送详情",
"发送详情",
"通道发送与回执",
"分片补偿审计"
]
}
@@ -0,0 +1,74 @@
{
"version": "R11",
"stableEntry": "src/apps/admin/AdminSmsTaskProgressPage.tsx",
"stableExport": "AdminSmsTaskProgressPage",
"maxStableEntryLines": 220,
"modules": {
"src/apps/admin/sms-task-progress/SmsTaskFilter.tsx": ["SmsTaskFilter"],
"src/apps/admin/sms-task-progress/SmsTaskTable.tsx": ["SmsTaskTable"],
"src/apps/admin/sms-task-progress/TaskDetailModal.tsx": ["TaskDetailModal"],
"src/apps/admin/sms-task-progress/TaskPhoneListModal.tsx": ["TaskPhoneListModal"],
"src/apps/admin/sms-task-progress/TerminateTaskModal.tsx": ["TerminateTaskModal"],
"src/apps/admin/sms-task-progress/taskModel.ts": [
"mapTask",
"getProgress",
"getSuccessRate",
"getRegionRate",
"splitSignature"
]
},
"apiCalls": {
"src/apps/admin/AdminSmsTaskProgressPage.tsx": [
"listAdminBatchTasksPage",
"listTenants",
"listEnterpriseApplicationOptions",
"terminateAdminBatchTask"
],
"src/apps/admin/sms-task-progress/TaskPhoneListModal.tsx": [
"listAdminBatchTaskMessages"
]
},
"styleFile": "src/apps/admin/sms-task-progress/AdminSmsTaskProgressPage.css",
"styleImport": "./sms-task-progress/AdminSmsTaskProgressPage.css",
"pageStyleSelectors": [
".admin-sms-task-page",
".admin-task-template-row",
".admin-task-detail-title",
".admin-task-detail",
".admin-task-metrics",
".admin-task-metric",
".admin-task-info-list",
".admin-task-progress-card",
".admin-task-progress-split",
".admin-task-template-block",
".admin-task-template",
".admin-task-billing-note",
".admin-task-card--full",
".admin-carrier-grid",
".admin-carrier-card",
".admin-success-text"
],
"sharedSelectorsKeptGlobal": [
".batch-progress"
],
"sharedSelectorsKeptInAdmin": [
".admin-task-filter",
".admin-task-table-card",
".admin-task-id",
".admin-task-enterprise",
".admin-task-card"
],
"interactionLabels": [
"发送批次号",
"选择企业",
"选择应用",
"提交时间",
"查询",
"重置",
"查看列表",
"详情",
"终止",
"发送批次详情",
"号码列表"
]
}
+130
View File
@@ -0,0 +1,130 @@
{
"version": "R11-step-6",
"entry": "src/main.tsx",
"component": "src/layouts/AppShell.tsx",
"shellFile": "src/styles/shell.css",
"legacyFiles": [
"src/styles/global.css",
"src/styles/components.css"
],
"importAfter": "@/styles/reset.css",
"importBefore": "@/styles/global.css",
"minimumRuleCount": 118,
"shellClasses": [
"app-shell",
"app-shell--collapsed",
"app-shell--mobile-nav-open",
"sidebar",
"sidebar--mobile-open",
"sidebar-brand-row",
"mobile-nav-close",
"mobile-nav-toggle",
"mobile-nav-backdrop",
"mobile-topbar-brand",
"brand-block",
"brand-logo",
"brand-logo--full",
"brand-logo--compact",
"side-nav",
"side-nav-section",
"side-nav-group-toggle",
"side-nav-group-label",
"side-nav-group-chevron",
"side-nav-list",
"side-nav-list--closed",
"side-nav-label",
"side-nav-label-text",
"dev-status-badge",
"side-nav-pending-badge",
"sidebar-footer",
"main-area",
"topbar",
"topbar-left",
"topbar-actions",
"desktop-nav-toggle",
"topbar-help",
"notice-menu-wrap",
"notice-count",
"notice-popover",
"notice-popover__header",
"user-menu",
"user-menu-wrap",
"user-menu-popover",
"user-avatar",
"page-content"
],
"legacyShellClasses": [
"brand-copy",
"brand-mark",
"brand-subtitle"
],
"sharedLayoutSelectors": [
".page-content",
".page-stack",
".page-heading",
".page-heading > p",
".page-heading__actions",
".page-actions",
".surface",
".section-stack",
".section-heading"
],
"requiredMediaQueries": [
"(min-width: 781px)",
"(max-width: 780px)",
"(prefers-reduced-motion: reduce)"
],
"requiredRuleFragments": [
{
"selector": ".app-shell",
"includes": [
"display:grid",
"grid-template-columns:var(--sidebar-width) minmax(0, 1fr)",
"overflow:hidden"
]
},
{
"selector": ".app-shell--collapsed",
"includes": [
"grid-template-columns:76px minmax(0, 1fr)"
]
},
{
"selector": ".sidebar",
"media": "(max-width: 780px)",
"includes": [
"position:fixed",
"transform:translateX(-105%)"
]
},
{
"selector": ".sidebar--mobile-open",
"media": "(max-width: 780px)",
"includes": [
"transform:translateX(0)"
]
},
{
"selector": ".mobile-nav-backdrop",
"media": "(max-width: 780px)",
"includes": [
"display:block",
"position:fixed"
]
},
{
"selector": ".page-content",
"includes": [
"overflow-y:auto",
"width:100%"
]
},
{
"selector": ".sidebar",
"media": "(prefers-reduced-motion: reduce)",
"includes": [
"transition:none"
]
}
]
}
+928
View File
@@ -0,0 +1,928 @@
{
"version": "R5",
"source": "api/src/channels/channels.service.ts",
"generatedAt": "2026-07-31T02:40:10.189Z",
"publicMethods": [
{
"name": "onModuleInit",
"signature": "onModuleInit()",
"canonicalBodySha256": "2a9debc88139a1a61f69060867abe7b4fcaf340ea3b40a19db9d4ae5aee7cfc2",
"originalLines": [
210,
231
],
"domain": "connection"
},
{
"name": "onModuleDestroy",
"signature": "async onModuleDestroy()",
"canonicalBodySha256": "9f72cbd51df2e3df22e08c15928e3382767eadfe9685e1db7dee2ed8a6d97155",
"originalLines": [
233,
246
],
"domain": "connection"
},
{
"name": "listChannels",
"signature": "listChannels()",
"canonicalBodySha256": "7ec25cd31ee4f261804a41a8781987abbfe246ac2118804b45efdef526c947b4",
"originalLines": [
248,
253
],
"domain": "configuration"
},
{
"name": "listChannelsPage",
"signature": "async listChannelsPage(query: { keyword?: string; carrier?: string; status?: string; page?: number; pageSize?: number })",
"canonicalBodySha256": "6b82d07ae76c4bfd979dbb319c64b8d8e0388df79e817b844d1e2700af7cc6be",
"originalLines": [
255,
274
],
"domain": "configuration"
},
{
"name": "createChannel",
"signature": "async createChannel(data: CreateChannelDto)",
"canonicalBodySha256": "eaee4eb581cb0891525f84c6912059785fd26cfff923e1973186f876b1e10745",
"originalLines": [
276,
323
],
"domain": "configuration"
},
{
"name": "updateChannel",
"signature": "async updateChannel(channelId: string, data: UpdateChannelDto)",
"canonicalBodySha256": "72eae5cdfca3c2563a6fa3f727056f582642ce3d6a8e35f24a47b1c1e53836d6",
"originalLines": [
325,
413
],
"domain": "configuration"
},
{
"name": "changeChannelStatus",
"signature": "async changeChannelStatus(channelId: string, data: ChangeChannelStatusDto)",
"canonicalBodySha256": "14ef7429e822ff520674699b449571424d9f7b0a13ce37a6c6fa9116449ac6d2",
"originalLines": [
415,
444
],
"domain": "configuration"
},
{
"name": "copyChannel",
"signature": "async copyChannel(channelId: string, data: CopyChannelDto = {})",
"canonicalBodySha256": "bdabf01a200cc5da9f9f17aee7df2fe0781bf79c36653cca9ddb8f84c7c63ed7",
"originalLines": [
446,
530
],
"domain": "copy"
},
{
"name": "deleteChannel",
"signature": "async deleteChannel(channelId: string, data: ChangeChannelStatusDto = { status: 'deleted' })",
"canonicalBodySha256": "1534ae0c91a6d12a97724d2d3f55b3e48469ad244e855be42aa93207be970d17",
"originalLines": [
532,
534
],
"domain": "deletion"
},
{
"name": "testChannel",
"signature": "async testChannel(channelId: string, data: TestChannelDto = {})",
"canonicalBodySha256": "e01b10f3981c66c5fab6cfd6d1b886abbb45e1fe53852b57c0903fcd826815d3",
"originalLines": [
536,
636
],
"domain": "testing"
},
{
"name": "listChannelMetrics",
"signature": "listChannelMetrics(channelId: string)",
"canonicalBodySha256": "bbe1b9191967c8eb13c413642786287382acbec93307d06ff843be1b9a163bcc",
"originalLines": [
638,
644
],
"domain": "connection"
},
{
"name": "listChannelConnections",
"signature": "listChannelConnections(channelId: string)",
"canonicalBodySha256": "07c644f24792d3c529daf39df4ac6d747e039c282d99d0f3cfffa8858a7ccf91",
"originalLines": [
646,
651
],
"domain": "connection"
},
{
"name": "listChannelConnectionLogs",
"signature": "async listChannelConnectionLogs(channelId: string)",
"canonicalBodySha256": "c01c6680974dc56813829bd6d47665e5be553ac6298f9207d19c951e4c540766",
"originalLines": [
653,
687
],
"domain": "connection"
},
{
"name": "listTenantConnections",
"signature": "listTenantConnections(tenantId: string)",
"canonicalBodySha256": "6aef43831f27c2ae7818dc449aadbaa7f521a6db54b78623b02d6bd0fc0a8810",
"originalLines": [
689,
695
],
"domain": "connection"
},
{
"name": "upsertConnectionState",
"signature": "async upsertConnectionState(data: UpsertConnectionStateDto)",
"canonicalBodySha256": "ce612114ed0abbf6653d11387d66c75c56fda22b8ceac7cdc3aece53cc999a8c",
"originalLines": [
697,
786
],
"domain": "connection"
},
{
"name": "markTimedOutConnectingChannels",
"signature": "async markTimedOutConnectingChannels(now = new Date())",
"canonicalBodySha256": "dbb713b158fa24088b5248a76eca5615c8a7fd3f89074d9627a6545622f55b70",
"originalLines": [
788,
851
],
"domain": "connection"
},
{
"name": "listGroups",
"signature": "listGroups()",
"canonicalBodySha256": "fc4ae9bd701db6f55108aa057f42a56b283901b3401903edb5464058d5a96374",
"originalLines": [
853,
858
],
"domain": "groups"
},
{
"name": "createGroup",
"signature": "createGroup(data: CreateChannelGroupDto)",
"canonicalBodySha256": "b5f50729da5cd843ba1a3ab5cd8ccc684d1baa06556610a030d91906dcf5d931",
"originalLines": [
860,
875
],
"domain": "groups"
},
{
"name": "addGroupItem",
"signature": "async addGroupItem(data: CreateChannelGroupItemDto)",
"canonicalBodySha256": "f34ae9a769d40a2ef7ccb6fab53d4a276190c71c2bee5084b1020a9bef85375a",
"originalLines": [
877,
929
],
"domain": "groups"
},
{
"name": "updateGroup",
"signature": "async updateGroup(groupId: string, data: UpdateChannelGroupDto)",
"canonicalBodySha256": "0a74b719119142424363c7b167f3b25daae018dbece386d863a4a0fcb7614645",
"originalLines": [
931,
996
],
"domain": "groups"
},
{
"name": "deleteGroup",
"signature": "async deleteGroup(groupId: string)",
"canonicalBodySha256": "ca89f1d6861fa4a5808e1d3e6a21062223faeab172246d5615d8447672105800",
"originalLines": [
998,
1015
],
"domain": "groups"
},
{
"name": "listRouteRules",
"signature": "listRouteRules()",
"canonicalBodySha256": "f4a905f76ab67b5ca8d66692b45ef17a2eaa8575329c871d40ec79a6d4b8a4ce",
"originalLines": [
1017,
1022
],
"domain": "groups"
},
{
"name": "createRouteRule",
"signature": "async createRouteRule(data: CreateRouteRuleDto)",
"canonicalBodySha256": "89d6bfc18ff419ac2a4e5eec92a2626e5c0d6e37728babe67a73924e5fcb0051",
"originalLines": [
1024,
1057
],
"domain": "groups"
},
{
"name": "listReportFields",
"signature": "listReportFields(channelId?: string)",
"canonicalBodySha256": "da3b95085c6d58739d4deda5ee7c0835fe181b84aba3473794a88653a6eb2def",
"originalLines": [
1059,
1065
],
"domain": "reporting"
},
{
"name": "createReportField",
"signature": "async createReportField(data: CreateReportFieldDto)",
"canonicalBodySha256": "c5c854beda64f87d1237d46a9d9f06ba98366edddb0a28ad1bbec7a92fc20f06",
"originalLines": [
1067,
1094
],
"domain": "reporting"
},
{
"name": "replaceReportFields",
"signature": "async replaceReportFields(channelId: string, reportType: 'signature' | 'drainage', data: ReplaceReportFieldsDto)",
"canonicalBodySha256": "fb1bc89d864d2423216d835e787821d4de5c2f6550573b8b20fdd966e5d41a5a",
"originalLines": [
1096,
1142
],
"domain": "reporting"
},
{
"name": "listReportMaterials",
"signature": "listReportMaterials(signatureId?: string, channelId?: string)",
"canonicalBodySha256": "ff2661b65e206d3a79966f1c921f56b72c3fd8bd08d49a0a8bedff088ee5539e",
"originalLines": [
1144,
1152
],
"domain": "reporting"
},
{
"name": "upsertReportMaterial",
"signature": "upsertReportMaterial(data: CreateReportMaterialDto)",
"canonicalBodySha256": "60704c21da36c28866e8ba12e4d3e8684785d87f34618710995525dbd77eaeb6",
"originalLines": [
1154,
1175
],
"domain": "reporting"
},
{
"name": "listReportTasks",
"signature": "async listReportTasks(tenantId?: string, status?: string, channelId?: string, reportType?: string)",
"canonicalBodySha256": "a1374204cf233ff5389e27491674d89f946b184b9bb3722dd5fd1ed74073d21d",
"originalLines": [
1177,
1303
],
"domain": "reporting"
},
{
"name": "listReportTasksPage",
"signature": "async listReportTasksPage(query: {\n tenantId?: string;\n status?: string;\n channelId?: string;\n reportType?: string;\n keyword?: string;\n createdAtFrom?: string;\n createdAtTo?: string;\n page?: number;\n pageSize?: number;\n })",
"canonicalBodySha256": "70ab547809d13c2c0a64898a5937444d819c1945ca1346e973059a8036e5a915",
"originalLines": [
1305,
1360
],
"domain": "reporting"
},
{
"name": "createReportTask",
"signature": "async createReportTask(data: CreateReportTaskDto)",
"canonicalBodySha256": "0aca4b72828ddae3707cc1f12cf9a485868047195140783f269a70a0beb2286d",
"originalLines": [
1362,
1384
],
"domain": "reporting"
},
{
"name": "changeReportTaskStatuses",
"signature": "async changeReportTaskStatuses(data: ChangeReportTaskStatusesDto)",
"canonicalBodySha256": "8427ebc2fa8246481b4232a45b647d28409a26d1a208176856b61690ae21da79",
"originalLines": [
1386,
1422
],
"domain": "reporting"
},
{
"name": "createReportExport",
"signature": "async createReportExport(taskId: string, data: CreateReportExportDto)",
"canonicalBodySha256": "148dd68546b615108fec4ae54d00a435175adb7caa7ef82a3f98ebb6cc3016d8",
"originalLines": [
1447,
1459
],
"domain": "reporting"
},
{
"name": "importReportReceipt",
"signature": "async importReportReceipt(taskId: string, data: CreateReceiptImportDto)",
"canonicalBodySha256": "47c55771a6f8cdc9ff23661d254521dd29905bb717562cbae9d643630d224a6d",
"originalLines": [
1461,
1485
],
"domain": "reporting"
},
{
"name": "listReportRecords",
"signature": "listReportRecords(taskId?: string, channelId?: string)",
"canonicalBodySha256": "0dcea8c84fff26589de04fbd04a60913c46ab76a34f553d083db55525c327ffd",
"originalLines": [
1487,
1493
],
"domain": "reporting"
},
{
"name": "listReportRecordsPage",
"signature": "async listReportRecordsPage(query: {\n taskId?: string;\n channelId?: string;\n keyword?: string;\n reportType?: string;\n createdAtFrom?: string;\n createdAtTo?: string;\n page?: number;\n pageSize?: number;\n })",
"canonicalBodySha256": "10516c3980113b0904b316e160cd1036dfd268cf8b16baf6bbfd791f4cebed32",
"originalLines": [
1495,
1537
],
"domain": "reporting"
},
{
"name": "reconcileGatewayConnections",
"signature": "async reconcileGatewayConnections(now = new Date())",
"canonicalBodySha256": "95751f1fd97cd5991063a7a41e835e088df9754d6b735a3f1c796c2055d2879f",
"originalLines": [
1726,
1773
],
"domain": "connection"
}
],
"internalMethods": [
{
"name": "recomputeSignatureReportSummary",
"signature": "private async recomputeSignatureReportSummary(tx: Prisma.TransactionClient, signatureId: string)",
"canonicalBodySha256": "ced499f221e3132b85ed3152dda8d890a062bd6fbf4287db7d78410e03f746cf",
"originalLines": [
1424,
1445
],
"domain": "reporting"
},
{
"name": "getReportTaskOrThrow",
"signature": "private async getReportTaskOrThrow(taskId: string)",
"canonicalBodySha256": "360c3d76c6b882765f4870ed5f56fdc3f09477d887f866d67876c2f64f504359",
"originalLines": [
1539,
1548
],
"domain": "reporting"
},
{
"name": "updateReportTaskStatus",
"signature": "private async updateReportTaskStatus(\n taskId: string,\n channelId: string,\n statusBefore: string,\n statusAfter: string,\n action: string,\n reason?: string,\n )",
"canonicalBodySha256": "abcfd90557ef6c3ec91ac3ed43ff0d267520f7fc12c5e6a43c4d57545acdb692",
"originalLines": [
1550,
1563
],
"domain": "reporting"
},
{
"name": "recordReportTask",
"signature": "private recordReportTask(\n taskId: string,\n channelId: string,\n action: string,\n statusBefore: string | undefined,\n statusAfter: string,\n reason?: string,\n )",
"canonicalBodySha256": "2128e08b3e3d52e396e0c58350b9d76e40d02e34e2f60bc75e413eca87f62a57",
"originalLines": [
1565,
1583
],
"domain": "reporting"
},
{
"name": "requestChannelConnection",
"signature": "private async requestChannelConnection(\n channel: {\n id: string;\n code: string;\n name: string;\n gatewayHost: string;\n gatewayPort: number;\n account: string;\n passwordCipher: string;\n srcId: string;\n cmppVersion: string;\n rateLimitPerSecond: number;\n config?: Prisma.JsonValue | null;\n },\n reason: 'channel_created' | 'channel_enabled' | 'channel_updated' | 'gateway_restarted' | 'automatic_reconnect',\n operatorId?: string,\n )",
"canonicalBodySha256": "df68d72a118a88e4ace78823e95d8af96079ccd03b756889c49d16adedb7a579",
"originalLines": [
1585,
1709
],
"domain": "connection"
},
{
"name": "reconnectActiveChannelsAfterGatewayRestart",
"signature": "private async reconnectActiveChannelsAfterGatewayRestart()",
"canonicalBodySha256": "e288503945449483bbd2120c0c36eff8b157c7045efe6fce9331ffba354dd958",
"originalLines": [
1711,
1724
],
"domain": "connection"
},
{
"name": "withGatewayReconcileLock",
"signature": "private async withGatewayReconcileLock(channelId: string, action: () => Promise<void>)",
"canonicalBodySha256": "8bbade14b639897f686c7cc3d4de32917b0a3525fbc27f08a44872c4824a3384",
"originalLines": [
1775,
1793
],
"domain": "connection"
},
{
"name": "requestChannelDisconnection",
"signature": "private async requestChannelDisconnection(\n channel: { id: string },\n reason: 'channel_disabled' | 'channel_deleted' | 'inactive_channel_reconcile',\n operatorId?: string,\n )",
"canonicalBodySha256": "02cfac1dc9953dfdbd95d63abd006f0e9b14be75a088a81c3773067a8719c92e",
"originalLines": [
1795,
1852
],
"domain": "connection"
},
{
"name": "getGatewayConnectionQueue",
"signature": "private getGatewayConnectionQueue()",
"canonicalBodySha256": "eb40aa7810cd4a26571eddfd2f21d7f2440b7e39fdb0657214ded056d8e286a3",
"originalLines": [
1854,
1857
],
"domain": "connection"
},
{
"name": "getGatewaySubmitQueue",
"signature": "private getGatewaySubmitQueue()",
"canonicalBodySha256": "d00641e15e3db84893cd302c767d6ac80a13e2ca3da5bc3d88f665fe3ffcacea",
"originalLines": [
1859,
1862
],
"domain": "connection"
},
{
"name": "getRedis",
"signature": "private getRedis()",
"canonicalBodySha256": "80f3524ea6442ba63f979b8daf0c19adbcec58a179e1deda3ce7fd3c7923cf62",
"originalLines": [
1864,
1871
],
"domain": "connection"
},
{
"name": "publishGatewaySubmitCommand",
"signature": "private async publishGatewaySubmitCommand(command: unknown)",
"canonicalBodySha256": "b6d027c12ca7d01a42a3ec81384b77fb07b16297ece386f9021e65d2148c4efc",
"originalLines": [
1873,
1882
],
"domain": "connection"
},
{
"name": "notifyGatewayConnect",
"signature": "private async notifyGatewayConnect(command: Record<string, unknown>)",
"canonicalBodySha256": "edc028c9fcb834e24cc9bc4fbc6aada5daff70674981cf5078d9db8631f007db",
"originalLines": [
1884,
1901
],
"domain": "connection"
},
{
"name": "notifyGatewayDisconnect",
"signature": "private async notifyGatewayDisconnect(command: Record<string, unknown>)",
"canonicalBodySha256": "8422aaf771157bcdd001c6b742eee437cb33c660872424845885c5850de1aaab",
"originalLines": [
1903,
1920
],
"domain": "connection"
}
],
"contracts": [
{
"name": "CreateChannelDto",
"sha256": "5de2dff2a196fd99894e03223e169b87b8a9a8d5251c9fd5f700334c3cebbe00"
},
{
"name": "UpdateChannelDto",
"sha256": "63a98a44dac414fbb8063794d243f823b77dd63c213e677e7c3eb1c22fa92530"
},
{
"name": "CreateChannelGroupDto",
"sha256": "2d6c30f269ba7bf0c3d15d1a77175900edfad4184d4d469d0db0733878d4fd83"
},
{
"name": "CreateChannelGroupItemDto",
"sha256": "1a03b65c71ac8f52b84c87c599413bc747e8bb5402ecd23a91ad0ad1f513c2cb"
},
{
"name": "UpdateChannelGroupDto",
"sha256": "16c4ffdbd94c367e2932bee995d0b2c5357b57617ca2d48556efe896cd68e006"
},
{
"name": "CreateRouteRuleDto",
"sha256": "c0d24d5c1a266749098a7cecde488262dbebf9131429f018ec4bc05815b8c79d"
},
{
"name": "CreateReportFieldDto",
"sha256": "dff3ea95e4a5cfd9f880fa1ee8b5399452b3d4ac511e18ec5805f49856a061ef"
},
{
"name": "ReplaceReportFieldsDto",
"sha256": "3a8f0ca7d9f9113ad4612b50010d4138912b06851e84311a2d3f8b3f6c1b0adb"
},
{
"name": "CreateReportMaterialDto",
"sha256": "15a83e490bfefbc4c84cc0d70c9b18ab674ce2768577b0b3e7b19fa9fb40f3ac"
},
{
"name": "CreateReportTaskDto",
"sha256": "5ea18848e89c44f8ad9450af79f97a2cff7e3168fa62d23c6a881fbc61cea62b"
},
{
"name": "ChangeReportTaskStatusesDto",
"sha256": "028e467f76f796987e232b73d63f3d6babc6c15d7534f1cd4ceb5a67194107e4"
},
{
"name": "CreateReportExportDto",
"sha256": "e4ba2142b291c1939990c81b66dcef0cdc2747765c3c06a7a75becd1e4e08526"
},
{
"name": "CreateReceiptImportDto",
"sha256": "1c2a09ae37fba9adb03e5d6860757713d174eaed83b04aa2252d224d643e22cc"
},
{
"name": "UpsertConnectionStateDto",
"sha256": "432a9bdd2e0e9bcba7f9ae82c1bb45399881ada6faca3f8541dc4f43c3f58c1d"
},
{
"name": "ChangeChannelStatusDto",
"sha256": "61a8eab26aaf370ff6ceecc4d89810079857945386a1fdb3a10c99fd15d2c2fa"
},
{
"name": "CopyChannelDto",
"sha256": "9f0bbacd18c38a623dc3a2fc761506e91603f4a1b720a24000e76eff6e493039"
},
{
"name": "TestChannelDto",
"sha256": "fd1ed651d6a233fa044c4f5f2cd3e50aa046072ab6f39d810d89f15fead09820"
}
],
"helpers": [
{
"name": "normalizeTestPhones",
"sha256": "2f989fb549ddb0bf44ecc7912e0fd5a9b3c7fd8c99e5b7db4e8b97a11585d2b4"
},
{
"name": "normalizeTestContent",
"sha256": "c6aad6035f9afbe795cc1ba17b438d2ad5659fbe4b61900e8aa03ab29520e91e"
},
{
"name": "calculateBillingUnits",
"sha256": "a8e1449d3781c1bee1adfdeb2df5c2fff066990ca8260d827c8dfd2eb833452a"
},
{
"name": "buildChannelTestSubmitCommand",
"sha256": "d16842aed45059d881e4b844a5ec66b725fb9419cec4bcdc4fe3831cc5f49a2a"
},
{
"name": "getConfigValue",
"sha256": "6b5419962b5f1bc918a3d39f3d95a199bb663fd54372981090c51119cf49d1b0"
},
{
"name": "getStringConfigValue",
"sha256": "35b39e21df3d416c25682e29eda6d0e4626c35beae73e1fb47f77cf1bf9ef2ed"
},
{
"name": "normalizeConnectionAction",
"sha256": "8d0b596a85db2cb1816f909d180c390f10162f3d10d2cd16ce8eb7424ead399c"
},
{
"name": "normalizeCmppVersion",
"sha256": "220a9fbda9aeccab9c7331ee118d0f31fc1fca5bf0015e25c849e79d8bb12985"
},
{
"name": "normalizeGatewayConnectionStatus",
"sha256": "bf81060a9ddd788079bb1e22d3ffa64321a2df18c5fa902b20cdf1298cb40781"
},
{
"name": "defaultChannelConnectionId",
"sha256": "2ef3e882c598f1e5c003302f4f6143d67c151907b65af6f3eff06b1e89c91a3f"
},
{
"name": "getDesiredConnections",
"sha256": "d6e3f7b0134f0b94cc59c4b7ef117932980e5d4f86f9f9df6e7e63729232aee6"
},
{
"name": "ChannelConnectionSettings",
"sha256": "906b57eec65a23d27994c9e8130108cc95c4d4b1f169f05e61a39f76cb885abd"
},
{
"name": "getRuntimeConfigInteger",
"sha256": "0e595766faa70ba9a33716c10d7c7478f87d0543fc4c7e2b86c95bc5df30221d"
},
{
"name": "channelConnectionSettingsChanged",
"sha256": "1d9371059cc95c3080577fd9e7c71ba50b16f7ee3e01b70c486c61bb056c89e3"
},
{
"name": "channelGroupAuditSnapshot",
"sha256": "8ac6c3de6cf9f843b4635e8fb3ff89691b9b0762febe26a3887a5f17fa9de5b6"
},
{
"name": "normalizeChannelRuntimeConfig",
"sha256": "a979b4bcb5e7b8d1acfb0b99196a9c8dec7f834116140af170113b25da7d14d5"
},
{
"name": "normalizeCmppServiceId",
"sha256": "e1f620b4df0283aa08421ebe05c25c0cc1407edc105d54df27f655122423debf"
},
{
"name": "normalizeChannelRateLimit",
"sha256": "897aca7bc66a023e1d4ca2cf1ab5d3d9660128432b4726f88c878da2f55c5098"
},
{
"name": "normalizeExtensionDigits",
"sha256": "91e1526daad821cddc886cf0f8fe580aa8f7b8beeaef2be836d7c2ebd57eb96d"
},
{
"name": "getPositiveRuntimeInteger",
"sha256": "b2aff43304863e222db1788ee6177a3a8b14b0c5c3097b1ff3fda98e71fd50a2"
},
{
"name": "bullmqConnection",
"sha256": "1fe9095c9ed383419f640913f033ff0715d4e241c8114543097a51dbf1acaf67"
},
{
"name": "getPositiveIntegerEnv",
"sha256": "db5d7ea71b1dc0e9bb72724c533893117f27c689ce485b180a2409ae6a3eed2c"
},
{
"name": "parseReceiptContent",
"sha256": "068290aef6af4376b6f0ed012914716296dfc1a43d10f447b0939b8aea9a7ec8"
},
{
"name": "splitReceiptLine",
"sha256": "29768fe9359e8dfc2e280743d3a5eaa0374aaf311eccd3c4ede6ef4e9bf35299"
},
{
"name": "stripReceiptCell",
"sha256": "bc29e649d5381c1c0c060102cd3e421114f32475e7156260b915a9984acb5369"
},
{
"name": "findReceiptStatusIndex",
"sha256": "cdd4244f0265164ac134f1645e603d112dde73100975e6438c71b11b3dfa40e0"
},
{
"name": "normalizeReceiptStatus",
"sha256": "b92ba14156d4e61722d2539e9c6b16ac29f920799fcdd4fcb917feb135394375"
},
{
"name": "deriveReceiptStatus",
"sha256": "465c39b82cd2cb9ea99b399f7290dfec8859172c8ffb6ad09683656f058b0847"
},
{
"name": "ChannelReportDeliveryRow",
"sha256": "216600c3398717f2ad200d9352cd64920593d8a07f6127b528eda9daf9404f3c"
},
{
"name": "summarizeChannelReportDelivery",
"sha256": "411701471d807f3ee01f6894016cb61b03c88c8018bc15a8465ca8296005b9bf"
},
{
"name": "sumReportDelivery",
"sha256": "73583b6176cbcd2f4625332a852c458bacaf0e3ebf87c5a391739176a612db9f"
},
{
"name": "percentage",
"sha256": "0745594434cceab4d6e2c4098d996dd338b7406c1506b7fc01edc4fdf488b404"
},
{
"name": "latestDate",
"sha256": "6686352cea283be461c9b15e76d83725c501397ccb6fbb739f86b05ddd9eec43"
},
{
"name": "currentShanghaiDayRange",
"sha256": "2684fcc9f35792427c24ad6044b491f8a24ca717ad963e662698983910da1ce3"
},
{
"name": "normalizeRetryTimeLimitMinutes",
"sha256": "68869e767b9820f076a41bb347bcd93e8245f7e6d8be351bfe17378b0d9b83a3"
},
{
"name": "normalizeSpreadsheetSize",
"sha256": "bcf7f1849728cf246e41561df3239b5327ce5926c49da43c014337c6bfa4090a"
},
{
"name": "normalizeBusinessCarrier",
"sha256": "44f10156d5d0da501a56b477ea44c143f41f330fa49d48272bc993b1e698cfa6"
},
{
"name": "normalizeChannelCarrier",
"sha256": "eb8e4e1b7c192aa3b2cb57586c7415207c3531d31614d8608a5f80e5c64e77d4"
},
{
"name": "isChannelCarrierCompatible",
"sha256": "35350532169cf227d4222dc48bf0c0b232c1bd74b13a139d8cffd0564a7738f5"
},
{
"name": "normalizeRegion",
"sha256": "3775eb50779ce87f8982ce691b18f91d8ed145a5dc9c27c8a315b0f55cb09152"
},
{
"name": "isRegionCompatible",
"sha256": "bbe33cc0c45cb58dbd5ee2daf241df6485abe52713dba185ee4493462b00e1de"
},
{
"name": "validateGroupItems",
"sha256": "eaf0f6e54c38cbcc52fa8c970fe1d6f7729e3bb12b2366dca89c93da8088bd2c"
},
{
"name": "normalizeReportType",
"sha256": "22fbaaa9756d56f0665b2bd8571c3bea1c84144a8dc81855e982c757217a920a"
},
{
"name": "summarizeReportStatuses",
"sha256": "ca9c3f0eece4b9e04f30cbc317041c52d63dcbb74ef1f87021dae5b20ca154b0"
},
{
"name": "normalizeLinkEvent",
"sha256": "4843d9bd396f02c8e5dcca4eb4b7abaefe422b4caead5aa23ca331bc41f47376"
}
],
"sharedDeclarations": [
{
"name": "GATEWAY_CONNECTION_QUEUE",
"sha256": "e76ea45c5057f6597dc25a8b94a34c43a38f2d189577ba8fa04285d5a1f4902f"
},
{
"name": "GATEWAY_SUBMIT_QUEUE",
"sha256": "c69e4af1b3939a576aa63833947b10b86b87a646b373684d9726dfbaf4c95d8c"
},
{
"name": "GATEWAY_SUBMIT_STREAM",
"sha256": "70d662152ad15ff017e1f61aca86525554c5b6a83f97686529dca1a0eaf28849"
},
{
"name": "DEFAULT_GATEWAY_CONTROL_URL",
"sha256": "e4b9884f5435352e666ee82acd2073917c0aea9215cb25c0ef18f1ca2cc1c88e"
},
{
"name": "DEFAULT_CHANNEL_CONNECTION_ID",
"sha256": "26a18e1d0aaea4a67b919a10ea8e847ea14851a0106d153f545c22c124e41098"
},
{
"name": "DEFAULT_CONNECTING_TIMEOUT_MS",
"sha256": "50748837da843f79079acee716b39498605a3129285f9e4d48576a05cb7180ad"
},
{
"name": "DEFAULT_CONNECTING_TIMEOUT_SCAN_MS",
"sha256": "80bc3b12df7aef1b067931d0ed1cd07b9bb56f675543ed03524c51bf6ca64fc8"
},
{
"name": "DEFAULT_GATEWAY_STARTUP_RECONNECT_DELAY_MS",
"sha256": "1b0a0499b6970c99be17ce4e4384e83eaf81b8c3323839e769c5f1a7f6ef6f93"
},
{
"name": "DEFAULT_GATEWAY_RECONCILE_INTERVAL_MS",
"sha256": "a02067c10cce5264097823109e2cdd5a24f4d8a592d4b845f4180506c8879358"
},
{
"name": "DEFAULT_GATEWAY_CONTROL_TIMEOUT_MS",
"sha256": "c7cb65a45b9e3e12bedd579190ca0a9b5a07dc74e314ede6874417dba1f51125"
},
{
"name": "DEFAULT_HEARTBEAT_INTERVAL_SECONDS",
"sha256": "7b96e3a74159fe87eac349f0602d33c9982e1785c89aaec7ec72d5966c3cc449"
},
{
"name": "DEFAULT_HEARTBEAT_MISS_THRESHOLD",
"sha256": "33d0d1bfbcafb1811d3a521c68d7dfff34c969314fa132badad9576030b2875d"
},
{
"name": "HEARTBEAT_AUDIT_INTERVAL_MS",
"sha256": "ed7d05fb517bf7ffe6dc5d16af7aa61dc70e6e69ef216706f013b783dfcc03aa"
},
{
"name": "CONNECTING_TIMEOUT_ERROR",
"sha256": "6b6c5057edff678a5f3d7fef7f5764354ee4b9e80cc9130de25e1baf5e50f33d"
},
{
"name": "DEFAULT_CMPP_VERSION",
"sha256": "e2c460ac8b6427fa3874e3763c9ba98e5a13d9e14b039be1fccd3d4ae828d358"
}
],
"domains": {
"configuration": {
"className": "ChannelConfigurationService",
"file": "api/src/channels/channel-configuration.service.ts",
"methods": [
"listChannels",
"listChannelsPage",
"createChannel",
"updateChannel",
"changeChannelStatus"
]
},
"connection": {
"className": "ChannelConnectionService",
"file": "api/src/channels/channel-connection.service.ts",
"methods": [
"onModuleInit",
"onModuleDestroy",
"listChannelMetrics",
"listChannelConnections",
"listChannelConnectionLogs",
"listTenantConnections",
"upsertConnectionState",
"markTimedOutConnectingChannels",
"requestChannelConnection",
"reconnectActiveChannelsAfterGatewayRestart",
"reconcileGatewayConnections",
"withGatewayReconcileLock",
"requestChannelDisconnection",
"getGatewayConnectionQueue",
"getGatewaySubmitQueue",
"getRedis",
"publishGatewaySubmitCommand",
"notifyGatewayConnect",
"notifyGatewayDisconnect"
]
},
"testing": {
"className": "ChannelTestService",
"file": "api/src/channels/channel-test.service.ts",
"methods": [
"testChannel"
]
},
"groups": {
"className": "ChannelGroupRoutingService",
"file": "api/src/channels/channel-group-routing.service.ts",
"methods": [
"listGroups",
"createGroup",
"addGroupItem",
"updateGroup",
"deleteGroup",
"listRouteRules",
"createRouteRule"
]
},
"reporting": {
"className": "ChannelReportingService",
"file": "api/src/channels/channel-reporting.service.ts",
"methods": [
"listReportFields",
"createReportField",
"replaceReportFields",
"listReportMaterials",
"upsertReportMaterial",
"listReportTasks",
"listReportTasksPage",
"createReportTask",
"changeReportTaskStatuses",
"recomputeSignatureReportSummary",
"createReportExport",
"importReportReceipt",
"listReportRecords",
"listReportRecordsPage",
"getReportTaskOrThrow",
"updateReportTaskStatus",
"recordReportTask"
]
},
"copy": {
"className": "ChannelCopyService",
"file": "api/src/channels/channel-copy.service.ts",
"methods": [
"copyChannel"
]
},
"deletion": {
"className": "ChannelDeletionService",
"file": "api/src/channels/channel-deletion.service.ts",
"methods": [
"deleteChannel"
]
}
}
}
@@ -0,0 +1,38 @@
{
"styleFile": "src/styles/client.css",
"globalStyleFile": "src/styles/global.css",
"entryFile": "src/main.tsx",
"marker": "Client-only cross-page patterns migrated from global.css in R11 step 9.",
"ownedClasses": [
"eyebrow"
],
"minimumRuleCount": 1,
"minimumSelectorCount": 1,
"usageRequirements": {
"eyebrow": 2
},
"requiredGlobalContextSelectors": [
".overview-hero .eyebrow"
],
"crossPortalClassesKeptGlobal": {
"sms-send-title": {
"minimumClientFiles": 9,
"minimumAdminFiles": 1
},
"system-page-toolbar": {
"minimumClientFiles": 3,
"minimumAdminFiles": 1
},
"system-table-card": {
"minimumClientFiles": 2,
"minimumAdminFiles": 1
}
},
"singlePageClassesKeptGlobal": [
"client-signature-page",
"sms-send-page",
"enterprise-page",
"send-detail-table",
"template-card-grid"
]
}
+54
View File
@@ -0,0 +1,54 @@
{
"version": "R11-step-5",
"entry": "src/main.tsx",
"importOrder": [
"@/styles/tokens.css",
"@/styles/reset.css",
"@/styles/shell.css",
"@/styles/global.css",
"@/styles/admin.css",
"@/styles/client.css",
"@/styles/components.css"
],
"applicationImport": "import { AppRoutes } from '@/routes/AppRoutes';",
"tokensFile": "src/styles/tokens.css",
"minimumTokenCount": 76,
"requiredTokens": [
"--color-brand",
"--color-bg",
"--color-surface",
"--color-text",
"--color-success",
"--color-warning",
"--color-danger",
"--font-family",
"--font-size-md",
"--line-height-base",
"--space-4",
"--radius-md",
"--shadow-md",
"--focus-ring",
"--transition-base",
"--sidebar-width",
"--topbar-height",
"--control-height-md",
"--z-modal"
],
"resetFile": "src/styles/reset.css",
"sourceFile": "src/styles/global.css",
"resetRuleHashes": {
"*": "06a686d623d71b39cbece4a1d14e066e9fca18db0a088f919462faeb6d866b79",
"html": "c5e097ee4c514843a085f38e8a4092cf8c791561496021e835fe8b075741b973",
"body": "959e2ae61d9722a688f7bb11c48ef52ff9cad53367bfd719b4fb19c8113386fc",
"a": "00e72791df6422df87fbc1aba2097c700dc3fbab83a5bdb1c04a89a03f4c4058",
"button,input,textarea,select": "bba903ee69611779f6c456ba3d96685aeed0e4ba3422d17b1f21cda6c6cebc7c",
"button": "ecfbb78629d7763f151589ad78e4e635758c53eeeb07a7bffef7c00d1785fe2a",
"button:disabled,input:disabled,textarea:disabled,select:disabled": "09672a6b885e18268ff3715646b191eb2d842befcda5b0f5f6630d8201f825cc",
":focus": "1f6d5babe8d9f56a802929a5c4da11bde3de6d636925eb3898e66c17714d13ea",
":focus-visible": "f6de580d559ff9e468267d7f3173fc241cff1e65096402696e5ac407fbe8fbad",
"h1,h2,h3,p": "de52e3be99f485f9aeba54183525162a236998888c83bd06c1e543b545afef30",
"h1": "140b54a87d2ccdb060105bf2213e51ac5cc3592ee0992bfc80c830b59d1c78ac",
"h2": "171665ed54789deace1ccfa93b2e7b0c4d9c3bf0ea02a935eddeb18abc99fef3",
"h3": "2b6273b83065e5938f3bf8f1b14d6daba9bd9abecf09aea6d5c9ded4303f6aee"
}
}
+564
View File
@@ -0,0 +1,564 @@
{
"version": "R6",
"source": "gateway/internal/inbound/server.go@HEAD-before-R6",
"declarations": [
{
"name": "beginDownstreamSubmitBarrier",
"kind": "func",
"file": "acknowledgement.go",
"sha256": "0ccbbba14c2ecff9da00681aa9e44181925e9f1793de1e793587ac931e3644e3"
},
{
"name": "defaultDownstreamAckTimeout",
"kind": "const",
"file": "acknowledgement.go",
"sha256": "92565b410c5f61c6b1a93eb40bc28be9131962f811e0ee912d69332aaefa12df"
},
{
"name": "downstreamAckKey",
"kind": "func",
"file": "acknowledgement.go",
"sha256": "a3ff3a57dd6952a9a859867136d8a532c9b9c99b60dfc1ba0f4aad8ea51f7bc0"
},
{
"name": "downstreamAckRegistry",
"kind": "var",
"file": "acknowledgement.go",
"sha256": "0f2c687864a9c57295739510f26ad343d7a5eb22e1f15fb7cdbb13d8e72d440c"
},
{
"name": "downstreamAckTimeout",
"kind": "func",
"file": "acknowledgement.go",
"sha256": "97d0878d73a6e1d6890207a776e536ad4bcd5efb8fc2bda49f930b23d3c740cc"
},
{
"name": "downstreamAckTracker",
"kind": "type",
"file": "acknowledgement.go",
"sha256": "53bfa44f334cc06acf6ce564d84d641dc6aafed6b57416023cef4c4ae86d2771"
},
{
"name": "downstreamSubmitBarrier",
"kind": "var",
"file": "acknowledgement.go",
"sha256": "211cb910963239f8660aa639607b955bbb54cc7d38484c6f89815c4127315cb3"
},
{
"name": "downstreamSubmitResponsePending",
"kind": "func",
"file": "acknowledgement.go",
"sha256": "9c43ecb4303ea8a70918a211f7e1ab1162947e98fe44b77d5e86f4995d5a16e2"
},
{
"name": "handleDownstreamAcknowledgement",
"kind": "func",
"file": "acknowledgement.go",
"sha256": "2bf1b5292111360bdda24e6c9348de739e95f2a9bbd56b8c3d2744e5b6ffe071"
},
{
"name": "registerDownstreamAck",
"kind": "func",
"file": "acknowledgement.go",
"sha256": "33a12b5d4ed3f949d2670a717af6e8febc54de4a1f008e3cbad6b43837b4779a"
},
{
"name": "removeDownstreamAck",
"kind": "func",
"file": "acknowledgement.go",
"sha256": "76d357d99c8b14dd04d0f6bf0c09699c6f75966f639f7499b26d854899d723a6"
},
{
"name": "takeDownstreamAck",
"kind": "func",
"file": "acknowledgement.go",
"sha256": "947085393b5a694df4b234040bafaa59ecfe86c3ade0404808f243ae55f0d6b8"
},
{
"name": "authRequest",
"kind": "type",
"file": "authentication.go",
"sha256": "0d3e6ab7ec4f418fefb88d2930b01c23eaff926097474c50ba678d553a1aa5a1"
},
{
"name": "authResponse",
"kind": "type",
"file": "authentication.go",
"sha256": "387ff32b3067a0eb342d09e1e5d3308f8359415171a2045f10dc56ca01205727"
},
{
"name": "authenticate",
"kind": "func",
"file": "authentication.go",
"sha256": "3dba30340070be6b78dcb1de963fde7a567701925684279c5b675ee9b197ec2c"
},
{
"name": "cmppVersionName",
"kind": "func",
"file": "authentication.go",
"sha256": "b9ab5ed0382868bb23cde01142e4245038ed22501fbef0605ff0c936df07149d"
},
{
"name": "handleLogin",
"kind": "func",
"file": "authentication.go",
"sha256": "bf3bdbcda7ddfd9f0e2ff53b436e151c94247b4ed40bcf60ec2f78fdb2559e64"
},
{
"name": "setInboundConnectResponse",
"kind": "func",
"file": "authentication.go",
"sha256": "4dbf12a8fda63789457f9f610871eec97da0122e23ba0e55d1db95a15f5c47ae"
},
{
"name": "DownstreamReceipt",
"kind": "type",
"file": "delivery.go",
"sha256": "772d9cc917b7f2968532480366634a595ba0b0f501d25b85eb0d799eec991eb0"
},
{
"name": "DownstreamSendResult",
"kind": "type",
"file": "delivery.go",
"sha256": "28af9ad91e045e2a11e5b91b9d989f7b7b09ef6cc3b2fa5cf420722fcbe5538b"
},
{
"name": "DownstreamUplink",
"kind": "type",
"file": "delivery.go",
"sha256": "22be370c5a551b5739b0d4f849ad2990febf0db57ec3ae89ec699f9a95895c80"
},
{
"name": "PushReceipt",
"kind": "func",
"file": "delivery.go",
"sha256": "321b26a357ae633278d92cc87e7f2f796af12c22b165eb19ba5c3e2b80dc67ce"
},
{
"name": "PushReceiptWithResult",
"kind": "func",
"file": "delivery.go",
"sha256": "ecc96ae40af974c3faedbe991fa01e71d9ed79c3fccaf964526a726cd6853487"
},
{
"name": "PushUplink",
"kind": "func",
"file": "delivery.go",
"sha256": "47f42edc03b663ba189defc91207da76263837535f1292fe52c9dbf542a4c8a0"
},
{
"name": "PushUplinkWithResult",
"kind": "func",
"file": "delivery.go",
"sha256": "2ec907ba43d4906b92c0aae693eb19f1e3a26d7a61d1efaa93e9258a11482ad0"
},
{
"name": "cmppReceiptStatus",
"kind": "func",
"file": "delivery.go",
"sha256": "ba6b72b46f9869fe22005f7d48b2668b0aa2242bf5a01203d8c62b2b778ed8cb"
},
{
"name": "downstreamDeliverMessageID",
"kind": "func",
"file": "delivery.go",
"sha256": "a58e6d0da35b374361518f7573f5f92b987eddd2f6753bc1e6e4312986cff7ed"
},
{
"name": "downstreamDeliverMetadata",
"kind": "func",
"file": "delivery.go",
"sha256": "a510caae34ffc46577985cd8b538e5924a3f4a43dcfedf8d60678c497d185912"
},
{
"name": "downstreamDeliverPacket",
"kind": "func",
"file": "delivery.go",
"sha256": "721de5632b72041a6102687cf4dece41b854c5bb34150c586a01c662b2cb1bbf"
},
{
"name": "downstreamDeliveryLifecycleEvent",
"kind": "type",
"file": "delivery.go",
"sha256": "4acf5485100e1bc6bb19a8004a3b1b7796fd8a6192fe2899e163abed7d134b69"
},
{
"name": "errorMessageWithCode",
"kind": "func",
"file": "delivery.go",
"sha256": "56e4380e43ee3fb9f99e6daf6e468583077372ffe0049133589907b87ab5aa3d"
},
{
"name": "findReceiptSession",
"kind": "func",
"file": "delivery.go",
"sha256": "af27e3accceff7023b09bb7f4ba716978edf89e3a9a4981c41439e279cf3bb5a"
},
{
"name": "findSession",
"kind": "func",
"file": "delivery.go",
"sha256": "cd9ddd0acd71bdd0ac32d2f2892f37c1461181038f193f9f9411a48b64dd0f22"
},
{
"name": "pushReceiptWithResult",
"kind": "func",
"file": "delivery.go",
"sha256": "ed0be61791a471b59a92601aa34f47b9d72c606096863493bb1dbb89a2d5e0a9"
},
{
"name": "recoverReceiptSession",
"kind": "func",
"file": "delivery.go",
"sha256": "b64f7eb8d7817580ddbdb88008169fa2f1f239bbf2d1cf3d976129da40799bee"
},
{
"name": "reportDownstreamDelivery",
"kind": "func",
"file": "delivery.go",
"sha256": "ea3bb61fb23718fc8d3b5ce2d75984eb00bc7f965612655f08951fc83d8147d9"
},
{
"name": "sendDownstream",
"kind": "func",
"file": "delivery.go",
"sha256": "1f85300328d803f5efab654f3038e7da59444a53feb5c41db1833b8d1824c2cc"
},
{
"name": "flushOnlineAccounts",
"kind": "func",
"file": "pending_recovery.go",
"sha256": "692d49fcb9ff3e116ce9476f826445996de00e5f714f21a5fa56a28afba18a10"
},
{
"name": "flushPending",
"kind": "func",
"file": "pending_recovery.go",
"sha256": "e4e2cfaa9471e132360fd9fdd8e83e03142f6fb450b76ada4b368b5cc6ae1fd2"
},
{
"name": "logRecoveryCandidates",
"kind": "func",
"file": "pending_recovery.go",
"sha256": "cd44224d2b6f4b4dbadc9a37d94a285d900c3e8323e36d57cea2f578ba818f24"
},
{
"name": "pendingDelivery",
"kind": "type",
"file": "pending_recovery.go",
"sha256": "fd6d25266aecc90ec7f68c88699c444e74b21215a518775678bbd84d28181c81"
},
{
"name": "pendingDeliveryRequest",
"kind": "type",
"file": "pending_recovery.go",
"sha256": "f7e72647951c29203eae90189368434d2bdcc3473f2a3ba7eb05f6ba489bc221"
},
{
"name": "pendingFlushInterval",
"kind": "func",
"file": "pending_recovery.go",
"sha256": "2b11f99b604ff894fba202947ab656b0578f55d0c291fee418574c099852a796"
},
{
"name": "pendingFlushResult",
"kind": "type",
"file": "pending_recovery.go",
"sha256": "6cb42b62fed78024a6401657e0bb48969fced040da914d043aac49bf7332caa1"
},
{
"name": "pushPendingDelivery",
"kind": "func",
"file": "pending_recovery.go",
"sha256": "a228f8e0ad2f43a68a9308b31d457294a3b967cfbcd8acb6b9117ccd92e027c7"
},
{
"name": "recoverPendingCandidates",
"kind": "func",
"file": "pending_recovery.go",
"sha256": "3c4949a98f31e60b1f38a83d3eec4b0fc28719d7300848bb0ed561c77f119e82"
},
{
"name": "recoveryFailureCategory",
"kind": "func",
"file": "pending_recovery.go",
"sha256": "b1686eeb07ede06fd5f77bee6fe203e5e5ea99a394bd318127c419f0924ce4b4"
},
{
"name": "runPendingFlusher",
"kind": "func",
"file": "pending_recovery.go",
"sha256": "5b2031765192bd9818931d8418e2790a491e6d76275cd71994d2df023617973a"
},
{
"name": "syncRecoveryStatus",
"kind": "func",
"file": "pending_recovery.go",
"sha256": "b63dfdf300570e510d45b2ac71cd0ebf06af9cf6b157db2fc436a7fa0e4345d0"
},
{
"name": "emitProtocolLog",
"kind": "func",
"file": "protocol_log.go",
"sha256": "2f162fe182184f1f2c940e48e5cb35680b41ef828cf375def5839e8713b1a079"
},
{
"name": "protocolLogEvent",
"kind": "type",
"file": "protocol_log.go",
"sha256": "67492ad6e52c6b57c52d8cf37c5564d4fafbd3655aaad706548da412e93fccaf"
},
{
"name": "protocolSendResultCode",
"kind": "func",
"file": "protocol_log.go",
"sha256": "f338ef80a1f9baeac7c3ce42f4d89ae629724de3121c13f6568f3b64a1f53472"
},
{
"name": "protocolSendStatus",
"kind": "func",
"file": "protocol_log.go",
"sha256": "c18f5b646d2b08fe6bf0d007293b1abe432a552ff19f0a27aee29ad765ba2451"
},
{
"name": "protocolSubmitResponseDetail",
"kind": "func",
"file": "protocol_log.go",
"sha256": "db6055b3e156e733b195f197f4f6ea324dc188f59cf6511a5617c6ba6f8c75aa"
},
{
"name": "recordDownstreamProtocol",
"kind": "func",
"file": "protocol_log.go",
"sha256": "4a4e70075e619a094abaa5a13885938544a7055f3aa582a861cd5b0e596495c3"
},
{
"name": "submitResponseProtocolLogger",
"kind": "func",
"file": "protocol_log.go",
"sha256": "94441a243f14e376d6e4f0ac00358752f43a0928f7215943b8e81d0bb9fd3969"
},
{
"name": "ListenAndServe",
"kind": "func",
"file": "server.go",
"sha256": "c57e5d860f6bdbb7d47a5414e0d186fe34cf61c42f94fc2b1ab5739b6272c272"
},
{
"name": "Server",
"kind": "type",
"file": "server.go",
"sha256": "9dacd52458fb19e19752e201de3b9c9b6e8fd9ba93afda454e7d7444b17148f5"
},
{
"name": "defaultHTTPTimeout",
"kind": "const",
"file": "server.go",
"sha256": "247aaf1070a6886f01059677dad739e69cb9dd10bd55d6397ba5fb9d385fe39a"
},
{
"name": "DisconnectAccount",
"kind": "func",
"file": "sessions.go",
"sha256": "306c822ca618b5d47dd002595e0896b87d86c26a0b35ef7ea6b032df8cefe66b"
},
{
"name": "downstreamConnectionEvent",
"kind": "type",
"file": "sessions.go",
"sha256": "d56a2bde011b9499ca6436f1da858f66f8aab02b790fe41aef7b49a70190be7e"
},
{
"name": "downstreamRegistry",
"kind": "var",
"file": "sessions.go",
"sha256": "c1cf77d72cbe4ceff9def118bfdbfbe54417e6156e9af3345a87cd6c4a02fe05"
},
{
"name": "downstreamSession",
"kind": "type",
"file": "sessions.go",
"sha256": "36d85eab72c673e4e4d47a2b60e68d96561ecb93b0a851de850280706e6779bc"
},
{
"name": "findSessionByConn",
"kind": "func",
"file": "sessions.go",
"sha256": "5563363dae78b586715ee48b3e6eb93a3ea397116a40e1bb99d0b1ce1072f255"
},
{
"name": "forgetDownstream",
"kind": "func",
"file": "sessions.go",
"sha256": "7e5b930ff7d1b7400936504d91cc850bce8334ac0953370da3b2d6786d4e6372"
},
{
"name": "gatewayInstanceID",
"kind": "func",
"file": "sessions.go",
"sha256": "0175fef1017de9e0c65adfe894375a463e8769185c8f7b17d7acbe96993edcb0"
},
{
"name": "handleActivity",
"kind": "func",
"file": "sessions.go",
"sha256": "7ec78fd7054aca6c55fd4b3a16bf8fa3b3a9c53e398a4164f06a39018fbaa5aa"
},
{
"name": "handleConnectionClosed",
"kind": "func",
"file": "sessions.go",
"sha256": "a3ed1e51c1057fa9f4a899de266f1750257ad9b7742d319cf5dac22a3341afd0"
},
{
"name": "onlineAccounts",
"kind": "func",
"file": "sessions.go",
"sha256": "fbbdd0bbe4e222a7d7e83302986bedefb4dcc762bbd9b31e2a886c0ef5f1564f"
},
{
"name": "rememberAccount",
"kind": "func",
"file": "sessions.go",
"sha256": "50ee995075641dcb3bb7dd2d1aefd72e1ec7fb352ad69862e8504db91c78eafd"
},
{
"name": "rememberDownstream",
"kind": "func",
"file": "sessions.go",
"sha256": "0803f1f2b2c69d47ac4adf0ec3d48fc122b5c994318dda93738b9c4d5ea56f64"
},
{
"name": "removePresence",
"kind": "func",
"file": "sessions.go",
"sha256": "4a5332055b810da8432712f2e4d0566d2245ca638401288f9ea616686de13af2"
},
{
"name": "reportConnection",
"kind": "func",
"file": "sessions.go",
"sha256": "6cdbadc05d0f7afe3dd2a5e77965380474949734ab05eddb463b31753a9064fc"
},
{
"name": "reportConnectionChecked",
"kind": "func",
"file": "sessions.go",
"sha256": "af5321ddf095bd00f3c790796ae3731bd0aa7b1c52d07bc9e909354bf731df1d"
},
{
"name": "reportConnectionOrDisconnect",
"kind": "func",
"file": "sessions.go",
"sha256": "61cf0ec3ac4278be5ccbd112d196aec662ae20f6aebd6079ac7102e83b1e7008"
},
{
"name": "touchPresence",
"kind": "func",
"file": "sessions.go",
"sha256": "d3f55aaaf52c33e3b6916f9e0d4e91754c88b28b997ae80b8d647fb07a3f7fc4"
},
{
"name": "decodeContent",
"kind": "func",
"file": "submit.go",
"sha256": "a66a6cc45a405c028cf41c7946dc89c6b1a313019863d6aa4b0a468d3ce7ef3f"
},
{
"name": "decodeInboundSubmitContent",
"kind": "func",
"file": "submit.go",
"sha256": "84f72bc74d7953096788001675d426bde14285a4a617e0524c0d194ce8744fe6"
},
{
"name": "handleSubmit",
"kind": "func",
"file": "submit.go",
"sha256": "fcb1d5ada61ff28a39976506e6a14f1fc09f840eaa4033ec9ea3fb9b8f0882f0"
},
{
"name": "inboundLongMessageFragment",
"kind": "type",
"file": "submit.go",
"sha256": "65fccbf8525f98948c307291bced71dff6c31e0f6a4015dcde4a9a45fc85c236"
},
{
"name": "inboundSubmitPacket",
"kind": "type",
"file": "submit.go",
"sha256": "50984034ef07833dcc2f4c4156cfe7f0add8767ae2b4d376001931e4f211e9d5"
},
{
"name": "messageIDFrom",
"kind": "func",
"file": "submit.go",
"sha256": "a5b5d130552b844568055e06e96d6d0aa9a421ef61fb8e4ff4fb6e5b6cecc984"
},
{
"name": "normalizeInboundSubmit",
"kind": "func",
"file": "submit.go",
"sha256": "e9f6b5bee5fe114d0fefee910d818bafa6834a00709fade7f4e0468f821e69fd"
},
{
"name": "setInboundSubmitResponse",
"kind": "func",
"file": "submit.go",
"sha256": "a21d1418c08aeb65a545f2e9d713f9a6c3fd720e80f996757f9af8d5bc982cc4"
},
{
"name": "submit",
"kind": "func",
"file": "submit.go",
"sha256": "b541d2c1d7e5592a6b8ad213d0cdbb81fcc98702023f1d5a4d35207476767ae7"
},
{
"name": "submitRequest",
"kind": "type",
"file": "submit.go",
"sha256": "8b622eefb6255f762b332a1d161269b116c234018a32cc881b9bde138a8fb1cd"
},
{
"name": "submitResponse",
"kind": "type",
"file": "submit.go",
"sha256": "aa2f05c154f7d6682d4214e8f16063784edabc7d60380c167f7a3b0c01cdfbea"
},
{
"name": "submitResponseMessage",
"kind": "type",
"file": "submit.go",
"sha256": "4a3b3c59d27627712d40e5caecb760d1dfefab51377c9ff45479850f46e4e9cf"
},
{
"name": "apiBaseURL",
"kind": "func",
"file": "transport.go",
"sha256": "96f0f2b1f3807bc966ff1b5e81917e2dfe09c64b1e13037563a2a83bb448c06a"
},
{
"name": "defaultString",
"kind": "func",
"file": "transport.go",
"sha256": "e3f1c7ba3d2aa985b2df53748e307f4e2769815d3cb8500dc616b929cee1e38a"
},
{
"name": "formatRFC3339Nano",
"kind": "func",
"file": "transport.go",
"sha256": "fd069087ad8497197f55a98ecfb9e5b1234ce641a0fb0a9161f8c320f436dd37"
},
{
"name": "post",
"kind": "func",
"file": "transport.go",
"sha256": "10fac868d1fe77fe2c261f14692245b6a08b573ee460cde0c7a77f6ee3ca77b1"
},
{
"name": "remoteIP",
"kind": "func",
"file": "transport.go",
"sha256": "84831ab34bb3ac39f998829ea9e4b61f92711c9c4eafa5ab214ddadefd969bd4"
}
]
}
+280
View File
@@ -0,0 +1,280 @@
{
"version": "r2",
"baselineCommit": "0af671b4ed4713912e703defd08791f164d4eb25",
"generatedAt": "2026-07-31",
"contracts": {
"MessageQuery": "07530ba61641758c96b5cd91dcdaba8692d5da4d9657d66e71009e7abf338f13",
"TraceQuery": "636138d9593d61b2936eb32231d071b4682ca1d36cbf6a2b07d3b71b4f5d8453",
"OperationLogQuery": "084d60f6487a2b38264211bf030950baacd2bc9b218e992867fb0e429dae7ece",
"GatewaySubmitDeadLetterQuery": "d40dea1cc7d5ee369ab16a49cada5c6bcfae2b21fc66459c49d9377374aa1445",
"DownstreamDeliveryQuery": "fd5b570bce0723aa6e848dd74ee326f3fb920dca86d5a60ffb8b1ed743343027",
"DownstreamDeliveryDashboardQuery": "62f06aba6ac8bc90b0885a70bcc6038901c1727438e7e9b70c16bfa88b2c7f08",
"DownstreamRecoveryStatusQuery": "74f3018a6d582a4ffde9711217fcc32d42131a9e262ae9b39b3025bd03d2b7f3",
"MessageSegmentAuditQuery": "90cf141034feb9fec50d54a2f6c0b5491d6e38cc05e87a687e9caa487f018f84",
"SignatureQualityQuery": "880bf2a7d74d94f552e50d9d0e19dbe95e893f7deaac16bb831ec4c9171ce663"
},
"methods": [
{
"name": "listBatchTasks",
"group": "messages",
"isPrivate": false,
"signatureSha256": "1a807b62cd5a6553fb7736503ad2fdba03dbbed36578d69c6a4d3ea42cc33131",
"bodySha256": "ab7f0cf4b606772d574549e552e081b36e339e3a800d82e7a948ab6dd7e090e8"
},
{
"name": "listClientBatchTasks",
"group": "messages",
"isPrivate": false,
"signatureSha256": "0561e37c80d66c53cca310d05db707b14a640f7c184e309c3a7ef4d7d0aec3af",
"bodySha256": "530af84aa681bcfdb3b2a7d919955ee3e047d3d5d5c77a96700796aef7db38eb"
},
{
"name": "listMessages",
"group": "messages",
"isPrivate": false,
"signatureSha256": "566e0533151b80b2d94ca77b1c65ab6faf5d94defc4467ebc521636a92a1a8c2",
"bodySha256": "e422326e97868efacff02ea767a7b4f71ed18231c85315674c9f267c2a13cffb"
},
{
"name": "listMessagesPage",
"group": "messages",
"isPrivate": false,
"signatureSha256": "fbae7a944bd2cd8c398c4d1f1a72ca272cbb9b4d17eb1092acaadd681a5fe7a8",
"bodySha256": "1bef139de372ce4335e69898f7a078a9ced9d531d545fbae02ec68e8085c56e7"
},
{
"name": "exportMessages",
"group": "messages",
"isPrivate": false,
"signatureSha256": "37075fd6448d81f6acc25efe9a3670c8d6ec962add6a0b1e3115a31c05f8d7a6",
"bodySha256": "649439bf58c411100dcc24d634c7f2c87c6323c74cfc76539f853485c3c59461"
},
{
"name": "listClientMessages",
"group": "messages",
"isPrivate": false,
"signatureSha256": "585b2dcab9df6f95965e9df59965bdb525a516fde88b2fcfa2719a8374df2ec2",
"bodySha256": "af305e69074e100706864afdc83fcc29c63222b0628c2dc514a18ff74273c763"
},
{
"name": "listClientMessagesPage",
"group": "messages",
"isPrivate": false,
"signatureSha256": "2655a52bcb2755a944e7fb95d2d12169b487bc965719739376fe7447dcfe2770",
"bodySha256": "3ea79e41bfe3f9ca09774754ba9213213184153a4ce93bff6f68d085e99baa9b"
},
{
"name": "listUplinkMessages",
"group": "uplink",
"isPrivate": false,
"signatureSha256": "3384d96065b6fa29c5785d27b5193488b7deb27f2d6fe1482abfdb94cf5e1096",
"bodySha256": "f5a949d7587ff83ca40f0fe1f68677e3dafd3d634ea11086ae633de2b93320cf"
},
{
"name": "listClientUplinkMessages",
"group": "uplink",
"isPrivate": false,
"signatureSha256": "a06d90bad32600a836a5d823f91914c70e8937bdecb5d140108de348f08ed7bd",
"bodySha256": "bec584ee827d27e65225377e1baa41982f241181804e74c0aa4eae560ed8c861"
},
{
"name": "listUplinkMessagesPage",
"group": "uplink",
"isPrivate": false,
"signatureSha256": "0ee52e770b7e79b26667d3846e36bc7b1e46352b92c8a48f7f1c1d03dc78b9ac",
"bodySha256": "c067c19488d4f74acc04e3af3e8956cecbf511571e4f3b8315a06ade21a58ff9"
},
{
"name": "monitor",
"group": "uplink",
"isPrivate": false,
"signatureSha256": "b3e5732d2f136021b62b5bd35c2cb332bfcdfc7a9cb5d4cf6288835152314287",
"bodySha256": "58758622feed4546da827b2b2e5d7a4e73c926349c258819604302626940250b"
},
{
"name": "dashboard",
"group": "dashboard",
"isPrivate": false,
"signatureSha256": "7bea6ce2744f19d6a6c7ec2078e986b9f36aa8ac139c83a9bf21f2554550a3b0",
"bodySha256": "50f10c48dcb9a0e7a7fdeae445fcd6a930a51894a76ce9834e306a70a598c574"
},
{
"name": "clientDashboard",
"group": "dashboard",
"isPrivate": false,
"signatureSha256": "56ce59f4e54b1811ade9a04040bafed17a454371dfd6e8780a8c268e6d59f30e",
"bodySha256": "6f257604b3a6bf2e6b9da84b9c76b8b3f26f0987038a2ff1cfec06c7024aa2ec"
},
{
"name": "statistics",
"group": "quality",
"isPrivate": false,
"signatureSha256": "3e4afcc84ee2dfc40e52ef4bea80fc737c23204b40c0522363e276469f96947b",
"bodySha256": "723a194c3ef3bfc732d36d0ab4b6ebce178782fab7f5d4b6b12a8e0906cf51ed"
},
{
"name": "sendQuality",
"group": "quality",
"isPrivate": false,
"signatureSha256": "7fa4cd6bcee4092390a38d693aa30c7980781ca1baa73dd07a3a61f097774e9c",
"bodySha256": "730b291f2fa96a9bcb054589a1341bc21f8ade161d232141d74f77eb426c4522"
},
{
"name": "signatureQuality",
"group": "quality",
"isPrivate": false,
"signatureSha256": "6b9c3761674cb0d01000caca5e12cf91a6e526757592ffb783fc673c178b204c",
"bodySha256": "c85644b03f607339c2eae5390b01fb520264e87f16d0439c81a0c101b4277fa2"
},
{
"name": "auditLogs",
"group": "logs",
"isPrivate": false,
"signatureSha256": "d4ad56308f1d27e5e131b75c74f03484ae21c1a85d26efc7c5fa2237e94da41e",
"bodySha256": "32646b12989c4a313558779d74fd7a75fbc3d8a965b5e9f4da9830f2a08ee785"
},
{
"name": "systemLogs",
"group": "logs",
"isPrivate": false,
"signatureSha256": "a2e578db34e6100b6257fd1ed6beabf28d732f014e9fc8f8cf914587f0feb5b2",
"bodySha256": "d0a1fc83b2c306f52679129b235db79ed88ae1ac30af6e27793b6891af3933e8"
},
{
"name": "exportSystemLogs",
"group": "logs",
"isPrivate": false,
"signatureSha256": "101ded394553c05cd4ed3f80f95a1716bdfb505029ba38f7d04d3f20564b88c3",
"bodySha256": "5f95e55b1095be6370b9327e622e3881c415d34af6f926a94ec8c0bd91ba75dc"
},
{
"name": "resolveClientTenantId",
"group": "logs",
"isPrivate": true,
"signatureSha256": "2935888aed8bbcfbd04f73f68c1feed70ca3dc0b3b31ef38bd34b479e656b51d",
"bodySha256": "292a41d7e213a6d85c44061f2e04aeed8b18e9b61f2cf6656802cb89f9e32611"
},
{
"name": "listGatewaySubmitDeadLetters",
"group": "downstream",
"isPrivate": false,
"signatureSha256": "fe33722f549a09191d3132c67c2664b5ce9df518aac70aaf3234b5abaef5e0d8",
"bodySha256": "c9552eb39c44c863d7d916191245620274275229e3f7246ad2596a46ce28560b"
},
{
"name": "listDownstreamDeliveries",
"group": "downstream",
"isPrivate": false,
"signatureSha256": "5fe6e1847a711fbcf547934513367ba591e6364d630b89a7133f8400cd0a1c84",
"bodySha256": "9f5f8efa141a4efcb057586008c6d942a346ac1b64889e381d4ce23155fe06e9"
},
{
"name": "downstreamDeliveryDashboard",
"group": "downstream",
"isPrivate": false,
"signatureSha256": "a47a03bfeada0a7ccc284a8a13f9a6481213f9c4d3bd8a9ffc6567396290a376",
"bodySha256": "88412a45bdf75fb2b99873191ca0637deffa6b4fb23e345915ef58ee152f83c0"
},
{
"name": "listDownstreamRecoveryStatuses",
"group": "downstream",
"isPrivate": false,
"signatureSha256": "cdf304441b834467417e60cf9476589910f84697fae2ec8a911519b202142baa",
"bodySha256": "1db9498db2129d8977604c199de2bf07bcf28fec9f370a7c272aba3cf876c575"
},
{
"name": "listMessageSegmentAudits",
"group": "downstream",
"isPrivate": false,
"signatureSha256": "fe617d8ba6907506f7d0327d5e0dfed23cd50681c55eeae66291e12058c2d26e",
"bodySha256": "9644db4083b0d960060664254d86449f06ad5bed577941ca52a08983fb470045"
},
{
"name": "getDownstreamRecoveryStatus",
"group": "downstream",
"isPrivate": false,
"signatureSha256": "00f7598b8bf8b997df01d5ae2471c9941e224342c47d8a77c5701754ee4d4c26",
"bodySha256": "55d9da10bc9357e05f2de7fff47d269e5f64e28791d93d1ee1bae2c8d3d731dd"
},
{
"name": "exportDownstreamRecoveryStatuses",
"group": "downstream",
"isPrivate": false,
"signatureSha256": "cbf335de93fb85ef3b530f0fcdccb2b1457c2f114a4ae5213db62cfdea98b9e3",
"bodySha256": "3ae45777799c1982ff787886a2a26c896fb1511cd6e51563a9f2fd95feccdb1b"
},
{
"name": "auditSummary",
"group": "trace",
"isPrivate": false,
"signatureSha256": "ae3db8f6fd9e940bf1bd246e80732dce2cd2a855df5c3acfafa072886e5e9ded",
"bodySha256": "f722254cbd78802ae4b5842e66c4f72b73db18c0701b95575635067dd8aaf11a"
},
{
"name": "trace",
"group": "trace",
"isPrivate": false,
"signatureSha256": "8d9526bf0683b53c79615d70f2eaa4a33e5e83c4f455c30467361e97b3f20393",
"bodySha256": "eda2d1e0f98a5bf0c25678aaf30efedbe1ce1d90128877b86d3d655f3d2397cb"
},
{
"name": "reconciliation",
"group": "trace",
"isPrivate": false,
"signatureSha256": "c6d1db8ff18f46f60f3fa5d3c4a8390469bf1f190d245a8a8b07e7fcf6ae0cbb",
"bodySha256": "f1bded76987def7292858bc303485a64403f2c28fe4c2f1a7eed359c30a4f8f6"
},
{
"name": "countPendingAudits",
"group": "dashboard",
"isPrivate": true,
"signatureSha256": "033be4c74aaaf745ad29c524f528e8db97706034dd907860c56b91b6a599aba3",
"bodySha256": "ee021da1d250f65d7956bcab163a310b74cf1530cb1baf5a78052d1aeef8d654"
},
{
"name": "gatewayDownstreamRecoveryStatusDelegate",
"group": "downstream",
"isPrivate": true,
"signatureSha256": "f0aae13f430c40e5c0d948b153c60b8a8bac832f8183d5fde9ebd6ded520067e",
"bodySha256": "9b451cd926f3bcfa471aebf4744967d6cdb35726fe5bce64424ae105022b765f"
}
],
"helpers": {
"messageWhere": "8d73104a7035970fceee92d95f2f76960c64aa5e1862be3441879d666d57a947",
"recognizedCarrierValues": "d60957621e921bf9f5df8fdef616f4e2a0b16be78623c85316a65bae83025bdb",
"carrierWhere": "1c7947c02a1a5cd3aaeda4a586421f6d7d63ae2f912cb11292831af2ffa4c379",
"startOfShanghaiDay": "12eb964ff5ab3680837cf50bccabe5e8e7af733c248d06cb57f20c0c65ce0b4e",
"endOfShanghaiDay": "36fcf2c3f6e7e0144305f1c175d03ab82b3ee43c3b3880e43ad14aa203d8cb4a",
"qualityBusinessDay": "2031fe0fc330b7374596cf340afe6c25ab85499de471d41a2ffb20e5be284def",
"shanghaiDateKey": "aa52e688283b13746a62628c7967b3ac0dbbd4418833701531e0a1004880aaf2",
"normalizeGroupBy": "d1f3b5e846fd9e0904a0e25d5bf9c6a1bb34f3e2d4b4c30fb683c1aa666f6c44",
"returnedTransactionWhere": "9048c20c268204b4bd5ffd14e075b915d846da11f6f13d836f87b47f8eb2e46e",
"createdAtRange": "c1d64506752fba90d17a47531e7939ff57fcdde101b05d1ac6395d9c5bf7c251",
"downstreamAlertPendingMinutes": "49a6e5a6ad05ccf4db538a639aa027c300c60b5748721cecc8cbc847d163fa7a",
"downstreamAlertRecentFailedHours": "66bbfb5ae98bf65119dd05d6c3fde97856c4b279f39d1dcd926d447b9e480b72",
"downstreamAlertWindows": "8b3ff0f8cf2a629ea488361404d30c027f0d9ed3c692b942b1d3bbda299c5cd2",
"downstreamAlertWhere": "d0699b58ae58f4357560aeca47acaf2de6c66b5a57a70d66dbddd63fbbe253e6",
"stalledPendingWhere": "2a2266a9f8888d0a21b0f6123aaf99ab9597419e79ff08115584b39b778473ef",
"downstreamDeliveryScopedWhere": "edf3bd93334fb31744ef28b59b1d15171c88e5c30ae27b2e998a2796cda38e05",
"parseDateBoundary": "62b768f59c084c4b8c4384700c98a88430cb10d8b27554c2cd730eb23e87bc23",
"downstreamRecoveryStatusWhere": "a9d59fac3bad87291ac9c0fb7206df82b7722b5d199fe31521efb97ade44931e",
"escapeCsvCell": "abcd0660648ee2978f2634aeda4de084298828b44d68d4cfbfa72e0a414724b7",
"formatCsvDate": "c52b4517a846bbd1a6010e20e0a8d2413b4e6c478ba830e05af109139cd00ff0",
"formatExportTimestamp": "1ed41fc5ffbc208bbe6752b186ac2b2111f700d7b15bf1197aaf0e8057811bac",
"clientApplicationView": "8af7f3d67d4c38930a4a5cd59e0048881a996de07220c561b65f8b4f97b3b931",
"clientReceiptView": "365eca8e3936433d0d71da2bc83d0e4ae27a7b15e7233dacf49eddd397b71baf",
"clientMessageView": "3bf33efe7c5c94b64148ff44172dd18997147b458703825277b98b24b0bbc37d",
"clientBatchTaskView": "b7d1fd9955f6b1362f8f2ff69e72315c6bda7e58c962ba1fa6667b54c9b71204",
"clientUplinkView": "b9c0093e74b93764de8759710614acf44282b48be1ae154ae459cbaa771b1d03",
"clientAccountView": "d97dd44290b999f97fcad7448e2129746de5080342899d448ace3335ea70ac0f",
"clientRechargeView": "0554a521fd9f7d89aa146185fa8655aeb577f743ebed3ce8bdd9b617f7d4192c",
"summarizeMessageGroups": "4eee30accc8c33587ed16cc9a404fde33ae321325a33e7c3dcd207c82f1e69eb",
"groupDownstreamByType": "1d38bd9ee894dce37eaeb51986220713d3d72c2cfb04be13021d985d354298ed",
"groupDownstreamByApplication": "540d5247bd99115b6d338ee3a4a91a005047a44eef7d492dbb23aab7fc753ab1",
"positiveInteger": "6febd4b21ae047e3c37128677bb6d908f703bc1cbfe7029c2c54c5e9e239a303",
"operationLogLevelWhere": "88ffdb591f2ed3dbb931e5dada32d05f9899e02d2f8e18d7711a5e6ba5b35b03",
"normalizeOperationLog": "f1949cfa395f9d2efe7ecc7f31a058b3fc4e837f08cdaa22cbbc521765cfdda7",
"sanitizeGatewaySubmitException": "3392287e5af7d5557ecbc957820011f81135c1f24ac8eed750c6f9c2fec82203",
"redactGatewayCommandValue": "475f1a557191626e29311fe578277350817ac3d246c821922b2bc7ee305827e7"
}
}
@@ -0,0 +1,55 @@
{
"version": "r0",
"baselineCommit": "0af671b4ed4713912e703defd08791f164d4eb25",
"purpose": "Freeze the cross-process contracts and characterization gates before production code is split.",
"contracts": [
{
"kind": "redis-stream",
"schema": "docs/contracts/gateway-queue-messages.schema.json",
"examples": [
"docs/contracts/examples/submit-command.json",
"docs/contracts/examples/submit-result.json",
"docs/contracts/examples/receipt-event.json",
"docs/contracts/examples/uplink-event.json"
],
"validator": "tools/spike/validate-gateway-queue-contract.mjs"
},
{
"kind": "cmpp-packet",
"tests": [
"gateway/internal/cmpp/gocmpp_integration_test.go",
"gateway/internal/upstream/submit_packet_test.go",
"gateway/internal/inbound/server_test.go"
],
"invariants": [
"CMPP 2.0 and 3.0 packets remain separately encoded and decoded.",
"SubmitResp preserves the request Sequence_Id.",
"Deliver receipts preserve Msg_Id and require a non-zero business acknowledgement."
]
},
{
"kind": "gateway-reconnect",
"tests": [
"gateway/internal/upstream/reconnect_integration_test.go",
"gateway/internal/upstream/connection_loss_test.go"
],
"invariants": [
"Network reconnect uses capped backoff.",
"Authentication failures use slow retry.",
"An explicit disconnect does not start an automatic reconnect."
]
},
{
"kind": "send-and-billing",
"tests": [
"api/src/send-chain/send-chain.service.spec.ts",
"api/src/billing/billing.service.spec.ts"
],
"invariants": [
"Concurrent claims cause one enqueue, retry, downstream delivery, or refund.",
"Stale events cannot downgrade a later terminal state.",
"Freeze, charge, release, and refund operations retain their idempotency keys."
]
}
]
}
@@ -0,0 +1,478 @@
{
"version": "R4",
"source": "api/src/report-materials/report-materials.service.ts",
"generatedAt": "2026-07-31T02:11:40.149Z",
"publicMethods": [
{
"name": "buildOfficialTemplate",
"signature": "async buildOfficialTemplate(reportType: 'signature' | 'drainage', operatorId?: string)",
"canonicalBodySha256": "507a97f3e067489fb16a33a040612f5a5e4524227ca8f9d8361e24d1b2baf785",
"originalLines": [
99,
120
],
"domain": "officialExport"
},
{
"name": "exportPending",
"signature": "async exportPending(query: { reportType?: 'signature' | 'drainage'; tenantId?: string; applicationId?: string }, operatorId?: string)",
"canonicalBodySha256": "f9f1cca955a9ce267f6b9c9a6d6c0b81be994908668705da1591bc550ee07cfe",
"originalLines": [
122,
139
],
"domain": "officialExport"
},
{
"name": "listPending",
"signature": "async listPending(query: { reportType?: 'signature' | 'drainage'; tenantId?: string; applicationId?: string } & PagedQuery)",
"canonicalBodySha256": "ecd97e4e397b63e7578645100bae82af66a9494ddefb4c1a627d8c30208ffdd9",
"originalLines": [
141,
151
],
"domain": "pendingQuery"
},
{
"name": "listImportProfiles",
"signature": "listImportProfiles(reportType?: 'signature' | 'drainage')",
"canonicalBodySha256": "37b13cca9ffb528b106871cdd3c89023f6d0f9e053080e6891d4271e35e2525d",
"originalLines": [
198,
204
],
"domain": "importParser"
},
{
"name": "saveImportProfile",
"signature": "async saveImportProfile(data: CreateImportProfileDto)",
"canonicalBodySha256": "6712ab96ded2c18120377b7b0c49193d374a858a2916b898df8b161bbbad4795",
"originalLines": [
206,
229
],
"domain": "importParser"
},
{
"name": "analyzeImport",
"signature": "async analyzeImport(file: { originalname: string; mimetype: string; size: number; buffer: Buffer }, options: AnalyzeImportOptions)",
"canonicalBodySha256": "ba5429c8b3fedce0de7420f9c9773215e5a6888cbb72a2b25eec152decb14aa4",
"originalLines": [
231,
297
],
"domain": "importParser"
},
{
"name": "commitImport",
"signature": "async commitImport(batchId: string, data: ImportCommitDto)",
"canonicalBodySha256": "8f68974ad5f7ae0231167e1801b5a3e2dccdcc78b691075967ab5838f62ec1dc",
"originalLines": [
299,
383
],
"domain": "importReview"
},
{
"name": "listImportReviewBatches",
"signature": "async listImportReviewBatches(query: PagedQuery & { reportType?: 'signature' | 'drainage'; status?: string } = {})",
"canonicalBodySha256": "6373de6acab0f6f12d99b000965ad798bd8c9aaeddcceece74080b033da5364e",
"originalLines": [
385,
436
],
"domain": "importReview"
},
{
"name": "reviewImportItems",
"signature": "async reviewImportItems(batchId: string, data: ReviewImportItemsDto)",
"canonicalBodySha256": "5303e3a9f6d0313edc69cd5fa6d93cb1408ebe782cbbe3f9e210f3ade939f27f",
"originalLines": [
438,
504
],
"domain": "importReview"
},
{
"name": "listBatches",
"signature": "async listBatches(query: PagedQuery = {})",
"canonicalBodySha256": "a9b65be1a5e9fa64a9aa863c70f3d19f7fe1d175fc8c3494b22c48d9ba425279",
"originalLines": [
506,
546
],
"domain": "batchGeneration"
},
{
"name": "createBatch",
"signature": "async createBatch(data: CreateReportBatchDto)",
"canonicalBodySha256": "59da60790350e19299b7fc80b9dd0d1763f118fb6f82fe3a09b458a3cb02db94",
"originalLines": [
548,
618
],
"domain": "batchGeneration"
},
{
"name": "preflightBatch",
"signature": "async preflightBatch(data: Pick<CreateReportBatchDto, 'items'>)",
"canonicalBodySha256": "6eb007143fbba353d39a3cca80f93cc4ba9fb9f6bab5182449dc2ca462234c9e",
"originalLines": [
620,
637
],
"domain": "batchGeneration"
}
],
"internalMethods": [
{
"name": "findPendingItems",
"signature": "private async findPendingItems(query: { reportType?: 'signature' | 'drainage'; tenantId?: string; applicationId?: string } & PagedQuery)",
"canonicalBodySha256": "6a4b0b9953f5499afc60605d6f68a17893dad51b89348f25799846ba7ae57f4e",
"originalLines": [
153,
196
],
"domain": "pendingQuery"
},
{
"name": "stageSignatureRow",
"signature": "private async stageSignatureRow(tenantId: string, applicationId: string | undefined, mappings: ImportMapping[], values: Record<string, unknown>)",
"canonicalBodySha256": "c9431e56ee3c93b416c17830feff3eee66dc5a0940d6a28b29f21f7d897a23b3",
"originalLines": [
639,
665
],
"domain": "importReview"
},
{
"name": "stageDrainageRow",
"signature": "private async stageDrainageRow(tenantId: string, applicationId: string | undefined, mappings: ImportMapping[], values: Record<string, unknown>)",
"canonicalBodySha256": "2a174fcb79e93e9abc293ad9205f9aa7d2c740731a250e75e598394b7c083d7c",
"originalLines": [
667,
691
],
"domain": "importReview"
},
{
"name": "applyImportItem",
"signature": "private async applyImportItem(\n batch: { tenantId: string; applicationId: string | null; reportType: string },\n item: { reportType: string; targetId: string | null; payload: Prisma.JsonValue },\n reviewerId: string,\n )",
"canonicalBodySha256": "2c016f04fb0a0aa2f6658a721a0e2c298a6c93d0d9111caf8f9adbdda5233d41",
"originalLines": [
693,
756
],
"domain": "importReview"
},
{
"name": "prepareBatchItem",
"signature": "private async prepareBatchItem(batchId: string, selected: CreateReportBatchDto['items'][number], inspection: ReportBatchInspection)",
"canonicalBodySha256": "f61ad17413f40c65437264b8ddf412de9184ebfcbd6fbc23cab5c2a7617e9674",
"originalLines": [
758,
777
],
"domain": "batchGeneration"
},
{
"name": "inspectBatchItem",
"signature": "private async inspectBatchItem(selected: CreateReportBatchDto['items'][number]): Promise<ReportBatchInspection>",
"canonicalBodySha256": "e04d7e20b23ac726eff80d6847290676b390b016013315523f05d58bf5fbece9",
"originalLines": [
779,
858
],
"domain": "batchGeneration"
},
{
"name": "claimBatchOperation",
"signature": "private async claimBatchOperation(idempotencyKey: string, fingerprint: string, userId?: string)",
"canonicalBodySha256": "c14878a5728ae576e703f7429bc83e947f922e85aeae349e62bb52ae3cf230d4",
"originalLines": [
860,
873
],
"domain": "batchOperation"
},
{
"name": "completeBatchOperation",
"signature": "private async completeBatchOperation(operationId: string, batchId: string, result: Record<string, unknown>)",
"canonicalBodySha256": "f4500197f33a4d023fbd735b9f38fbcd18fdd8fdca4419174b04f903531abdfb",
"originalLines": [
875,
877
],
"domain": "batchOperation"
},
{
"name": "failBatchOperation",
"signature": "private async failBatchOperation(operationId: string, message: string, batchId?: string)",
"canonicalBodySha256": "eb33a3102646844242592cb51dde16a455ca0055ee61e9c97f43ce07e51c12f8",
"originalLines": [
879,
882
],
"domain": "batchOperation"
},
{
"name": "exportChannelBatch",
"signature": "private async exportChannelBatch(batchId: string, channelId: string, items: Array<Awaited<ReturnType<ReportMaterialsService['prepareBatchItem']>>>)",
"canonicalBodySha256": "ea0df6daed595dfd4bea01ab6e4f51f3dd0bb6883e6e18c1c38e5997c0a9007c",
"originalLines": [
884,
943
],
"domain": "channelExport"
},
{
"name": "recordTask",
"signature": "private recordTask(taskId: string, channelId: string, statusBefore: string | undefined, statusAfter: string, reason?: string)",
"canonicalBodySha256": "9d1ce8db45c7623800d3117e2d246823dd7eb13e0970a5fa14f0392e8e4489eb",
"originalLines": [
945,
947
],
"domain": "channelExport"
}
],
"contracts": [
{
"name": "ImportMapping",
"sha256": "a0d06f96f2f99f135d8d86eaeb3f3a7525fa24224d5664e80567da75cdecee06"
},
{
"name": "CreateImportProfileDto",
"sha256": "6ffebbc39754d4b9df71a47d09c55f139ea33f9c4c0e26d8fa9c9756f7d642e6"
},
{
"name": "ImportCommitDto",
"sha256": "7c4c7b25184101b781037d97e93c5b4c1f836259153cc7cb26ded7f9bcf504c1"
},
{
"name": "ReviewImportItemsDto",
"sha256": "73be0348645a4316428eec4bd39d0ef02f84cef43c24530200d6c896cfae40e7"
},
{
"name": "PagedQuery",
"sha256": "78ddbb3a41b07a37729b80c84e969cf3344d44c19bdebff93b593bacf2b51293"
},
{
"name": "CreateReportBatchDto",
"sha256": "530b306e1f237c522e4a202ed1d43bca6e527eb6dd44afa113988de54fdad35f"
},
{
"name": "ReportBatchTarget",
"sha256": "a91a765ad37d69e0f797c2b9c4b692789765b539a6b13d212f1a93cd5b1b4e65"
},
{
"name": "ReportBatchInspection",
"sha256": "e00a2a0750dad4c413466426a2710a2ea59c2c8b369e61726db3f175b700cc00"
},
{
"name": "AnalyzeImportOptions",
"sha256": "74e5e84a09befe64caada9f8574a52dde7e30770a7ffe4b99e417c60c6eda40b"
},
{
"name": "EmbeddedImage",
"sha256": "9db22983b69311e82b0899663cd1534dd72510f14259ba37693bd63bc9bad59b"
}
],
"helpers": [
{
"name": "profileData",
"sha256": "e61848d9a038403295c40d26588ca44c32d4372529726ad9f2e22232474efc69"
},
{
"name": "validateProfile",
"sha256": "6fe77bdd3830c93b40d9f3d3282f0fdd2c5afa8f025504ba57f9f8113a725947"
},
{
"name": "loadWorkbook",
"sha256": "46ce8da23dce75f31ab29d00c0dae8e063d14cb72ccfbec95333bb1064bbcf39"
},
{
"name": "assertSafeWorkbook",
"sha256": "5ed20a1e12793355949b5cf951b4113c9c61517bf5a97491cc22671ee6ccaa56"
},
{
"name": "safeSpreadsheetText",
"sha256": "5a7db626de509e78628fc87ebf20e43d227e6ce3fefdf48bd82dd040ffd35683"
},
{
"name": "readEmbeddedImages",
"sha256": "9fbd0df019528353aa7fc5220a279b23711d36fa61f78e0880d8bb2cc6228f4d"
},
{
"name": "suggestMappings",
"sha256": "79abe1b569ffb867fd39ace7e731f1885dd113ac470d8b8dea315775d0eb3c28"
},
{
"name": "remapProfileColumns",
"sha256": "4b58e11d2e3d97a1b352109a9be7c26aa25bdecdbb5e542a0fb241e46c7f657a"
},
{
"name": "signatureCoreMapping",
"sha256": "5d4b0bdc68886cb022eecbf4eb4721613df74210d3165fd737b9badea00e5729"
},
{
"name": "drainageCoreMapping",
"sha256": "256323027325923786e84c308eeebcd0dde0e0b5d27a563d10e794d318b7bddd"
},
{
"name": "normalizeHeader",
"sha256": "b30ab7e6903b8e8411e3195c23581379badb6241bd518e327eb10ad0358e0c5c"
},
{
"name": "normalizeFieldCode",
"sha256": "49387c9ca040ea2cbc5a4732652c4389f32be8169536f9e132225579dff839fa"
},
{
"name": "clamp",
"sha256": "0aaed2dc249288c7f197e033b858c35aa10a0a2642203d5d92c94bd5db323926"
},
{
"name": "normalizePage",
"sha256": "f04be3697001d814b86457cdd93eb6a83cff1b712327a4e74960c2436b784b19"
},
{
"name": "normalizePageSize",
"sha256": "af1c28386f9802cb9c7cc3dddc712c1559d92d2c777b2bbce65d12cb1c5ecc38"
},
{
"name": "dateRange",
"sha256": "a0029a9c2eac718e2c7d63b30a7b3b65c504f859838ac9de7499ec1103ae1e89"
},
{
"name": "cellText",
"sha256": "a6f5fd540e5cbcbc8fc1ef1dfb4b8203e16212bb2d7c4a8b3aa0068f296f8981"
},
{
"name": "transformValue",
"sha256": "584b33bf430cd5c47e6e9a36b88a75519335125e80b0b63e3139e5f156333118"
},
{
"name": "mappedCoreValue",
"sha256": "a34b22e2cfbe93445eeedcfbf4f0b60d9ee0f5ed872c069e6db260a58dda723f"
},
{
"name": "dynamicValues",
"sha256": "a955844529a42a1f0bd73645bb4407980c7ae570bcd7d52a738fcae46f444d9b"
},
{
"name": "jsonRecord",
"sha256": "2f7c1984863c82abc61e7f753bd5bf1d752802d4ab552dd7ee03d6ddd7844ce1"
},
{
"name": "hasValue",
"sha256": "ae0550bd772c41447e7f975cb12a4812bc7ccde1ade718cd4fa1b3ae6af34583"
},
{
"name": "isFileRef",
"sha256": "37413460e45e152f80c3b49e82addfc332dacf0d3585cffe8868e8b93f2da87b"
},
{
"name": "resolveExportValue",
"sha256": "c6aae47afc4ece039eb97053ed491136a38563506deb0246a3d0c37784b7bccc"
},
{
"name": "applyExportTransform",
"sha256": "197b0126b8a8cf69d0087e45ec221ad608c7e5e2e94d8a2735adebfdcd801fad"
},
{
"name": "styleHeader",
"sha256": "8c419d0cd3fcbd2f84d4b079ae025557560fa479d59b5d3aca4970c65319d496"
},
{
"name": "normalizeImageExtension",
"sha256": "8c2f57eedc5c5294001b6a842581cf4b3cb9a61dbe392c700e0672416692fddc"
},
{
"name": "imageContentType",
"sha256": "589cd67492e900039830c1c6694cc910b726bf78e3b275d53664965842b122c7"
},
{
"name": "safeFileName",
"sha256": "948e0371435a10f79bc24a9c70ed0911bff050c209cba794e42b713fecd50a34"
},
{
"name": "normalizeBatchIdempotencyKey",
"sha256": "e2f921d15dc1300b15c23089fd63c6c1ecafdfb11fbce93cdb3f7dd7b3a7b760"
},
{
"name": "jsonStringArray",
"sha256": "469f80e2ba2119bfa26c19e371224b239c2df8ab6bdbe75f5906ab2047744622"
},
{
"name": "jsonSafe",
"sha256": "3f72a3704848a68c9488c3b692c4f6144e64a7f6cb51ca3ad2ba5d7d92cd3e4f"
}
],
"domains": {
"officialExport": {
"className": "ReportOfficialExportService",
"file": "api/src/report-materials/official-export.service.ts",
"methods": [
"buildOfficialTemplate",
"exportPending"
]
},
"importParser": {
"className": "ReportImportParserService",
"file": "api/src/report-materials/import-parser.service.ts",
"methods": [
"listImportProfiles",
"saveImportProfile",
"analyzeImport"
]
},
"importReview": {
"className": "ReportImportReviewService",
"file": "api/src/report-materials/import-review.service.ts",
"methods": [
"commitImport",
"listImportReviewBatches",
"reviewImportItems",
"stageSignatureRow",
"stageDrainageRow",
"applyImportItem"
]
},
"pendingQuery": {
"className": "ReportPendingQueryService",
"file": "api/src/report-materials/pending-query.service.ts",
"methods": [
"listPending",
"findPendingItems"
]
},
"batchGeneration": {
"className": "ReportBatchGenerationService",
"file": "api/src/report-materials/batch-generation.service.ts",
"methods": [
"listBatches",
"createBatch",
"preflightBatch",
"prepareBatchItem",
"inspectBatchItem"
]
},
"channelExport": {
"className": "ReportChannelExportService",
"file": "api/src/report-materials/channel-export.service.ts",
"methods": [
"exportChannelBatch",
"recordTask"
]
},
"batchOperation": {
"className": "ReportBatchOperationService",
"file": "api/src/report-materials/batch-operation.service.ts",
"methods": [
"claimBatchOperation",
"completeBatchOperation",
"failBatchOperation"
]
}
}
}
@@ -0,0 +1,250 @@
{
"version": "R10",
"generatedAt": "2026-07-31",
"source": "api/src/send-chain/send-chain.service.ts at R9 local baseline",
"facade": "api/src/send-chain/send-completion.service.ts",
"methods": [
{
"name": "handleSubmitSegmentResult",
"file": "send-gateway-result.service.ts",
"bodySha256": "1a508cba1eb3547bfeabdecdbc0e62bf4971807212439b0adf1f2b52a2699878"
},
{
"name": "resolveSubmitRecordForGatewaySegmentResult",
"file": "send-gateway-result.service.ts",
"bodySha256": "a4e233c6b4c13858355573e3d61e77f07ef141e20d3a98c0108d6ff27157f3e2"
},
{
"name": "handleSubmitResult",
"file": "send-gateway-result.service.ts",
"bodySha256": "6184170748eb3934496b060ea3b6704f1d1a831e7ffde7e7f8b73a7c223a869c"
},
{
"name": "resolveSubmitRecordForGatewayResult",
"file": "send-gateway-result.service.ts",
"bodySha256": "a904de3a2fe6c9ad1a6aa50982a9dfb1633b6a27466f421c978afe72ba974b8b"
},
{
"name": "smsMessageSegmentAuditDelegate",
"file": "send-gateway-result.service.ts",
"bodySha256": "c907ad9b162874735ecdf0d024f18a4ff15cf8f1be3a95c628b3bfe793230b65"
},
{
"name": "recordSubmitSegments",
"file": "send-gateway-result.service.ts",
"bodySha256": "897c27559d20613b5fd87a22f2748658f31c4bf9435935a523e21d5d1100206f"
},
{
"name": "findMessageByGatewayEvent",
"file": "send-gateway-result.service.ts",
"bodySha256": "8212cecfa19b3be90ce565c9f4446183bf06073c633683e0f94ea4e104b23760"
},
{
"name": "requireMessageByGatewayEvent",
"file": "send-gateway-result.service.ts",
"bodySha256": "76757dad543ee12c9622a25fbfdace943e9be537d5e68f1592768c4504eb5617"
},
{
"name": "intakeReceipt",
"file": "send-receipt.service.ts",
"bodySha256": "42cad611473ebb973beca6b4f5c05192dc1e2e35ee9f85e2d7cb86b35129a32b"
},
{
"name": "processPendingUpstreamReceiptInbox",
"file": "send-receipt.service.ts",
"bodySha256": "3614b8aabb5640a94b4b2f8a65c9dff3425a7578e753410413eead52c33f747f"
},
{
"name": "processUpstreamReceiptInboxRecord",
"file": "send-receipt.service.ts",
"bodySha256": "5882e14d9474e6c940a9a28d6a9b78f4e9e46184caa616971674dfb9efd1b70d"
},
{
"name": "runUpstreamReceiptInboxScan",
"file": "send-receipt.service.ts",
"bodySha256": "a1bda2f26563c0cfe5cb5564aa5ef34f513e2c99bb302a0a0ad7917b4887c7ed"
},
{
"name": "handleReceipt",
"file": "send-receipt.service.ts",
"bodySha256": "e3b63dc74af50db96d899c805124c7974067ca729e44a1ec8a558569e81fbd6c"
},
{
"name": "recordReceiptSegment",
"file": "send-receipt.service.ts",
"bodySha256": "acb776e7ee67b07c9e635411ef2a4286db60366fd6b20083be870c9314dab8f0"
},
{
"name": "aggregateReceiptSegments",
"file": "send-receipt.service.ts",
"bodySha256": "7dc565bd0847462bd0e23b5f072a4f82fd6daa88f164485138ce653d8cf936b8"
},
{
"name": "resolveReceiptMessage",
"file": "send-receipt.service.ts",
"bodySha256": "caadd32d37d3b72e2b7e526f86cdb422c054c2ed9c910a4b4d1d1f3eb1c6b522"
},
{
"name": "recordGatewaySubmitDeadLetter",
"file": "send-retry.service.ts",
"bodySha256": "85180d382ba99b9e714d406ab14f30de91445fa2a7a695acebf9ee359716fdff"
},
{
"name": "requeueGatewaySubmitDeadLetter",
"file": "send-retry.service.ts",
"bodySha256": "e1092c28b657e522a4bf77d833c694460c871bb82424f2604b01d204a00dcdc0"
},
{
"name": "recoverStaleGatewaySubmitRequeues",
"file": "send-retry.service.ts",
"bodySha256": "cc36a00787acfc00a1e1797ce83550d4de0441e1b83025d16624ba966577a6ba"
},
{
"name": "retryMessageIfAllowed",
"file": "send-retry.service.ts",
"bodySha256": "6892322b81983c99ad9063e334b435ab369eb5a6fd0268e09ef3772cd56bc484"
},
{
"name": "chargeAcceptedMessage",
"file": "send-accounting.service.ts",
"bodySha256": "4ca42fd6ea6e41509a1ff6d62164a1dcfa81f62256386cdb49294451162312dc"
},
{
"name": "releaseMessageReservation",
"file": "send-accounting.service.ts",
"bodySha256": "0838524d280b3c9b0c0146ea53b8b35e77295d8f626325a80b62e8f2a9faa607"
},
{
"name": "refundMessage",
"file": "send-accounting.service.ts",
"bodySha256": "4cca77a11bbdc419107f4e5c12a7d73190901c323dde0492f7489cac337759cb"
},
{
"name": "listPendingDownstreamDeliveries",
"file": "send-downstream-state.service.ts",
"bodySha256": "1c5e0bc271fcbfdf8a0c55e2870e9ddb41ffbbf24d3fe0c2285b4806e4854012"
},
{
"name": "markDownstreamDeliveryDelivered",
"file": "send-downstream-state.service.ts",
"bodySha256": "5fe521d4d5e50ec0a6b4ddda45f6dc67633da792161975837e6bb32c4025daaf"
},
{
"name": "markDownstreamDeliverySent",
"file": "send-downstream-state.service.ts",
"bodySha256": "08bd1cbc9c5662c158b598acb80374f36b9b7f623907345ff6821fd65b843167"
},
{
"name": "acknowledgeDownstreamDelivery",
"file": "send-downstream-state.service.ts",
"bodySha256": "5c53b04f37e891e77159256663e72071229ccb867b1d53ad1e0c9f6ec9595af6"
},
{
"name": "markDownstreamDeliveryFailed",
"file": "send-downstream-state.service.ts",
"bodySha256": "1b072fef54577d5de077a7086386c218a20b6d79c2171319e2e4c7fee99eddc5"
},
{
"name": "recordGatewayDownstreamRecoveryStatus",
"file": "send-downstream-state.service.ts",
"bodySha256": "0375019b79ceba79a39067c9d27b249c1a1554813ae8c272d9f7711d986d463d"
},
{
"name": "requeueDownstreamDelivery",
"file": "send-downstream-state.service.ts",
"bodySha256": "1e680512bd7a02735a8fd3713ec22d83cbc70505d494fd06a57cd628d8df6e99"
},
{
"name": "recoverStaleDownstreamManualRequeues",
"file": "send-downstream-state.service.ts",
"bodySha256": "0c6142754daff8df2e0bd7f1d323fd1ca0c9b2d83bc195cb664e21b119b8a972"
},
{
"name": "batchRequeueDownstreamDeliveries",
"file": "send-downstream-state.service.ts",
"bodySha256": "00af2d3af7cde4791190d0eebb50d97fca6e9a1c1b595fefe2d13bdc18dffebd"
},
{
"name": "handleUplink",
"file": "send-downstream-delivery.service.ts",
"bodySha256": "a0623ca0407ecab8b1b558e1784fe299a4a01008209bc1ff4bc60afed2c3e280"
},
{
"name": "claimUplinkMatchCandidate",
"file": "send-downstream-delivery.service.ts",
"bodySha256": "4330127ec62d2653ba0411a824378dec30ea657d0b688927d867d750932b67b5"
},
{
"name": "queueAndTryDownstreamDelivery",
"file": "send-downstream-delivery.service.ts",
"bodySha256": "0b5f6f5e9ffebad5ddda003962efdabb0daeb2ec5942a246bdf9d922f274d4ac"
},
{
"name": "resolveUplinkMatch",
"file": "send-downstream-delivery.service.ts",
"bodySha256": "2f017f39bb6332b43f78da2cbc8195bcec9e926d585f95f05b1da4b5df51b9cb"
},
{
"name": "recordCmppFailureReceipt",
"file": "send-downstream-delivery.service.ts",
"bodySha256": "d48ecabfcce62787668486a8f14b3ea7afc935d5d5d910651fc1ddf8d8ac3952"
},
{
"name": "postGatewayControl",
"file": "send-downstream-delivery.service.ts",
"bodySha256": "0f991ecb7f58268b5d44d2b32ddd940f0ce16420d8a7c94534e2eaaf36e38d5f"
},
{
"name": "markUnknownTimeout",
"file": "send-timeout.service.ts",
"bodySha256": "6f254ffbf05067483801cdd2c131f32cb9aaaf755d19f3aff065fe99b8d7753b"
},
{
"name": "markExpiredDownstreamDeliveries",
"file": "send-timeout.service.ts",
"bodySha256": "6d06c11e68394df57b0cb981ba566e5ce34924c85b14b4add93e8d3856a0d02d"
},
{
"name": "runReceiptTimeoutScan",
"file": "send-timeout.service.ts",
"bodySha256": "5e2942916813d62218dd63f51d05554ce9e455d1b3283704c3fd54dc124a4e5f"
}
],
"domains": [
{
"file": "send-gateway-result.service.ts",
"className": "SendGatewayResultService",
"methodCount": 8
},
{
"file": "send-receipt.service.ts",
"className": "SendReceiptService",
"methodCount": 8
},
{
"file": "send-retry.service.ts",
"className": "SendRetryService",
"methodCount": 4
},
{
"file": "send-accounting.service.ts",
"className": "SendAccountingService",
"methodCount": 3
},
{
"file": "send-downstream-state.service.ts",
"className": "SendDownstreamStateService",
"methodCount": 9
},
{
"file": "send-downstream-delivery.service.ts",
"className": "SendDownstreamDeliveryService",
"methodCount": 6
},
{
"file": "send-timeout.service.ts",
"className": "SendTimeoutService",
"methodCount": 3
}
]
}
@@ -0,0 +1,448 @@
{
"version": "R8",
"source": "api/src/send-chain/send-chain.service.ts@workspace-before-R8",
"contracts": [
{
"name": "CreateBatchTaskDto",
"kind": "interface",
"sha256": "70414ba63f4da4a501e60c2ba69d785113692d14c775289e6740065e5124fdf8"
},
{
"name": "CreateHttpBatchTaskDto",
"kind": "type",
"sha256": "a83aa71a11c756d84afa7b5ccb1af46d9008f59a77fd5329236beef752309abe"
},
{
"name": "GatewayInboundAuthDto",
"kind": "interface",
"sha256": "1e55f6a2a393cd72c7aca2b4a1e18e293ae20f513412f627197515448c8da166"
},
{
"name": "GatewayInboundSubmitDto",
"kind": "interface",
"sha256": "28f99a1e29385b64c3a6b4eab2e5befa3fc6cd8a6995090e0865f5af6871246a"
},
{
"name": "GatewayInboundSingleSubmitResult",
"kind": "interface",
"sha256": "6e71836ba8c38cc0634e5540a70d8a2cfb98c1b11f0e5ef8749f57a81fd3443b"
},
{
"name": "GatewaySubmitResultDto",
"kind": "interface",
"sha256": "a403995091710ac369b727fbcd5191515da7e10df5aad631dedb6dbcf751fe49"
},
{
"name": "GatewaySubmitSegmentResultDto",
"kind": "interface",
"sha256": "11ecd1395daac263757bc364a5551a7c8b41307622f446d191b25628fa287410"
},
{
"name": "GatewayReceiptEventDto",
"kind": "interface",
"sha256": "d2f68b459392e50e481dadaed9cd222087175b266613d265dd1b41a235cfd539"
},
{
"name": "GatewayUplinkEventDto",
"kind": "interface",
"sha256": "4b81ac70af7584956c706877bbea932d62851c79fd2e8e333e4a8b1023eedf98"
},
{
"name": "UplinkMatchCandidateInput",
"kind": "type",
"sha256": "a82efe64ba28740ad691ed645ed7e8ea205a555bf68ac3a18ffec9e36251b929"
},
{
"name": "GatewayPendingDeliveryQueryDto",
"kind": "interface",
"sha256": "8208ddf3a047c684e513f1828d5be0af617b28b84f1bb6b75c3e8822f58341bd"
},
{
"name": "GatewayDownstreamSentDto",
"kind": "interface",
"sha256": "a1d45c4dd241159afc02e87c3441c4e31cb06e6853ee13a5f22a75f9a5156464"
},
{
"name": "GatewayDownstreamAcknowledgedDto",
"kind": "interface",
"sha256": "d91e0bebf4abcd7f5506b75b2106d7899fa4d6c120e28c5db5f7c8e4d472bf87"
},
{
"name": "GatewayDownstreamFailureType",
"kind": "type",
"sha256": "f0d4da34c9194b679816527b87f7077c78f85ffde37aabb81f76f91ddcf5ef4a"
},
{
"name": "GatewayControlDeliveryResult",
"kind": "type",
"sha256": "916a1700848b5dd369196c105bdc99928e186608baf140ae0860d34e0725ea34"
},
{
"name": "GatewaySubmitDeadLetterDto",
"kind": "interface",
"sha256": "ee032743d02f7f76c073695b5579ccd9884b5d94e016a17e548227a6f36ed4e2"
},
{
"name": "RequeueGatewaySubmitExceptionDto",
"kind": "interface",
"sha256": "0b0973656d0cecb25ac9c8c6ed863fbebfbb26178a6056c956f72e29f4d9dc94"
},
{
"name": "GatewayDownstreamRecoveryStatusDto",
"kind": "interface",
"sha256": "0c3b31cc6cce50dec8454e8427ba1f369d2f81ad7e583e564d62bab1db46260f"
},
{
"name": "TimeoutUnknownDto",
"kind": "interface",
"sha256": "231ca785c112103fa9432a19f0cb79745da52126b76055498678a6ebdc053a83"
},
{
"name": "ImportPreviewDto",
"kind": "interface",
"sha256": "0123d0e98b1355a64c317254e9e0d8776ad7a4043da8e3ada245ea8a5ea2f352"
},
{
"name": "ConfirmImportDto",
"kind": "interface",
"sha256": "ce98fe82a9d5052d8d8654b60985225240985c5473194f71987af92e311c0b89"
},
{
"name": "SendJob",
"kind": "interface",
"sha256": "57a692f8dae8e37ba3758f7afd75056ea629ed58c20139ebd60144cb99fd4177"
},
{
"name": "QueuePriority",
"kind": "type",
"sha256": "ca80dc4d2708054b7388426c1ca71a3e84db3ed08999ed89f9f791878fa03f70"
},
{
"name": "RoutedChannel",
"kind": "type",
"sha256": "d82fe045e8ae72380f575ecbd47ab9849d6eb2b85e74a27e6f116a019da7f2a4"
}
],
"helpers": [
{
"name": "SEND_QUEUE",
"kind": "const",
"sha256": "11a3c2aaf41c2ffe7ae251b5b5da00591624e21d345324563844e59f517b67d3"
},
{
"name": "GATEWAY_SUBMIT_QUEUE",
"kind": "const",
"sha256": "c69e4af1b3939a576aa63833947b10b86b87a646b373684d9726dfbaf4c95d8c"
},
{
"name": "GATEWAY_SUBMIT_STREAM",
"kind": "const",
"sha256": "70d662152ad15ff017e1f61aca86525554c5b6a83f97686529dca1a0eaf28849"
},
{
"name": "DEFAULT_DOWNSTREAM_RETRY_DELAY_MS",
"kind": "const",
"sha256": "5c216981884a2422ee8765d00745e99414d52976df4b68e90e5f2bc6bf22d090"
},
{
"name": "DEFAULT_DOWNSTREAM_RETRY_MAX_DELAY_MS",
"kind": "const",
"sha256": "02a1e63eb1887f5f924a5ed2f87f09edaf7eed54e419a9ce4c5afe1f52a061fa"
},
{
"name": "DEFAULT_DOWNSTREAM_MAX_RETRIES",
"kind": "const",
"sha256": "fa2107f33e9c2173a8cb91140c59a28193ca88d8c8bb9b14788af5427e406c38"
},
{
"name": "DEFAULT_DOWNSTREAM_PENDING_TIMEOUT_HOURS",
"kind": "const",
"sha256": "f7038a98205b1fe6f30df3e3af01a74336408cce7acc92f9254b737d608ca189"
},
{
"name": "DEFAULT_RECEIPT_TIMEOUT_HOURS",
"kind": "const",
"sha256": "3ffc70f45997ee0a68bb4ff1a041bf4408c0c71a3a3dc8517a6c152d20e4c931"
},
{
"name": "DEFAULT_RECEIPT_TIMEOUT_SCAN_INTERVAL_MS",
"kind": "const",
"sha256": "833d0c26f3f6e57b7f451a4bd0472c33ba99fdb8dc2479bea7b50759efcbf948"
},
{
"name": "RECEIPT_TIMEOUT_INITIAL_DELAY_MS",
"kind": "const",
"sha256": "d8ffa15508dad01de044034ddefbd379ac8a654a5f2e90dcfa05c0bb45990359"
},
{
"name": "DEFAULT_SCHEDULED_DISPATCH_SCAN_INTERVAL_MS",
"kind": "const",
"sha256": "86cc465a9fea068fa0f945d645a5129a17b021baa9daa05dc5ee666b669a6aca"
},
{
"name": "DEFAULT_SCHEDULED_DISPATCH_STALE_MS",
"kind": "const",
"sha256": "3337c4f2b53a6ca4a3b65326482f08c4d04be84324acc109d39cca65d2cb89ea"
},
{
"name": "SCHEDULED_DISPATCH_INITIAL_DELAY_MS",
"kind": "const",
"sha256": "61ee979c2d1d57cf977180c198cdb3e4a65683a6149619153db69ca72fa12d8b"
},
{
"name": "DEFAULT_GATEWAY_SUBMIT_REQUEUE_STALE_MS",
"kind": "const",
"sha256": "934da39a488b3a640c1649f8fb8a5a0a06b6e7c12896f4f7bf5756d1db53f6d7"
},
{
"name": "DEFAULT_DOWNSTREAM_MANUAL_REQUEUE_STALE_MS",
"kind": "const",
"sha256": "90e094f303fc32dbe7c5264b516cf69ae471ebe445344f991f38bff411dfe9fd"
},
{
"name": "DEFAULT_INBOUND_LONG_MESSAGE_SCAN_INTERVAL_MS",
"kind": "const",
"sha256": "a8e7362d181929843a1a4602f75077e22fd39a4566a435ea46edcd8a14289cca"
},
{
"name": "INBOUND_LONG_MESSAGE_SCAN_INITIAL_DELAY_MS",
"kind": "const",
"sha256": "596cac172bef8509c819282e30e2312477148c9740ee3c818ec6428408695fb9"
},
{
"name": "DEFAULT_INBOUND_LONG_MESSAGE_PROCESSING_STALE_SECONDS",
"kind": "const",
"sha256": "9025a5ff2f673eabdd15d6f4a4a81af9485ea96680d4db637eb04a0287d7e9dc"
},
{
"name": "DEFAULT_UPSTREAM_RECEIPT_INBOX_SCAN_INTERVAL_MS",
"kind": "const",
"sha256": "6f32cbb21fe7511234b8227fadca11e58ede0c902ce25c45ecbd6122c9cc9ded"
},
{
"name": "UPSTREAM_RECEIPT_INBOX_INITIAL_DELAY_MS",
"kind": "const",
"sha256": "a763a37b4e3af5ba91267b8c901097cd384aa618b13b7e5459788c791e83520d"
},
{
"name": "DEFAULT_UPSTREAM_RECEIPT_INBOX_PROCESSING_STALE_MS",
"kind": "const",
"sha256": "dac7d3fd5cd652cef9b59fd7458b9af13e27e32748c72618934fe21cb89b96d3"
},
{
"name": "DEFAULT_UPSTREAM_RECEIPT_INBOX_MAX_ATTEMPTS",
"kind": "const",
"sha256": "4b15ce126f631f5120298ff35a6e9a521db51c773b863914231cef27e4fa4d55"
},
{
"name": "DEFAULT_UPSTREAM_RECEIPT_INBOX_MAX_AGE_HOURS",
"kind": "const",
"sha256": "1f58c45b6f69eec7b09c071d5cbc6b38332fdd5f7db08aa9e62f89cc6914c552"
},
{
"name": "GATEWAY_SUBMIT_REQUEUE_IDEMPOTENCY_TTL_SECONDS",
"kind": "const",
"sha256": "a0c1f68b87266d20ab33df0192bb0cf0265276c7fa2ef2adc9b910efdc42f791"
},
{
"name": "BULLMQ_PRIORITY",
"kind": "const",
"sha256": "6ad900e1addfdabe932080b8f7e8976f28257bd1d838c4490b4410dd669988fd"
},
{
"name": "gatewaySubmitRequeueKey",
"kind": "function",
"sha256": "08f7ddf26ee168fe054ba96e425023b234447a6fe7ceb129e825eb2cbca6d5e5"
},
{
"name": "drainageRejectionReason",
"kind": "function",
"sha256": "4bc0aa5e5c7f96549cd8bad93d3b25fd5e65e6b017ae9bf83baa5c47cab08c02"
},
{
"name": "statusFromRisk",
"kind": "function",
"sha256": "4fb98f5add40278521c314dac20ec3c233b73c589714f11146964a3752ebce3a"
},
{
"name": "parseSchedule",
"kind": "function",
"sha256": "e335aca59919111f2727b4e07cc8d50ab9443a3f06b83af807ea17d84ece861c"
},
{
"name": "isObjectRecord",
"kind": "function",
"sha256": "c26e34d94f53b7befe62971546edd54d5a392b12aa10848e66a295624eff0c67"
},
{
"name": "asDateOrNull",
"kind": "function",
"sha256": "f755f5ae6babe0e6626c07a9822190fb808a74fffefe69012c269da5b0650e43"
},
{
"name": "downstreamRetryDelayMs",
"kind": "function",
"sha256": "8bab0089029e48a1027b4b4533b7c7fa0587b15e761bf566ce772b80c858f44a"
},
{
"name": "downstreamAckTimeoutMs",
"kind": "function",
"sha256": "99d3c8f3192498f344f3bec496e0997c77740c56ea973081af1ac0acd8b52374"
},
{
"name": "downstreamRetryBaseDelayMs",
"kind": "function",
"sha256": "2e4227ae9b787adfed98922c757e26d5b7776a225da2007d909d119476c391aa"
},
{
"name": "downstreamRetryMaxDelayMs",
"kind": "function",
"sha256": "aa34e8a657c24224b0290222944c1b82302126921d268516d637301a4e21923f"
},
{
"name": "downstreamMaxRetries",
"kind": "function",
"sha256": "0642b4d1609abd898d392af18ebfb074335e71fd8eea0f8fd695ae698672aaaa"
},
{
"name": "downstreamPendingTimeoutHours",
"kind": "function",
"sha256": "41eefd652ad90dc265b22c42485f171dcd164038b69adfa1dd187fa6edfd53ea"
},
{
"name": "downstreamControlFailureMessage",
"kind": "function",
"sha256": "1f98e86fb2dbb6cfbf48ee4e16edcad0517c4b0da9cd51bb05b7059056da03f3"
},
{
"name": "parseImportRows",
"kind": "function",
"sha256": "abab46d40b8a7e9363dbbe7c0c7cee8412446099195ee58c08e5212855215fe7"
},
{
"name": "splitImportLine",
"kind": "function",
"sha256": "574735eeefcc95e240fbcf9426025302382318a599fdd2207b23519637209bc8"
},
{
"name": "cellByHeader",
"kind": "function",
"sha256": "b867ffb1936e164311b56d4735d45c8b4d9719f55e1bef4b2b3b6036d4a27470"
},
{
"name": "normalizeCarrier",
"kind": "function",
"sha256": "d9cf3cca1702c7cd0dfc75f5aa58daa7759acbba66a1884471f710bb024ac06a"
},
{
"name": "normalizeQueuePriority",
"kind": "function",
"sha256": "bcd2ddee1f71a873966e30bb6dcdb8b09c47998bd6c4846c8fa8db248e38df3c"
},
{
"name": "getPositiveConfigInteger",
"kind": "function",
"sha256": "7bf2cf0a512143da511716327721a235ba60b40decb50a3dc28555e583af76f0"
},
{
"name": "getNonNegativeConfigInteger",
"kind": "function",
"sha256": "b7782a614fa04dd858411ed86f39301313da4d35c5a66d96993266e939621cd8"
},
{
"name": "isCarrierCompatible",
"kind": "function",
"sha256": "5353ca585ca05dd07f82eedd240a2a0c2e22d0361cc8636dd0a25ed010ccbdc5"
},
{
"name": "normalizeRegion",
"kind": "function",
"sha256": "3775eb50779ce87f8982ce691b18f91d8ed145a5dc9c27c8a315b0f55cb09152"
},
{
"name": "matchTemplateContent",
"kind": "function",
"sha256": "793a46db4cd6b5387214597f034bc14068d9733710b7a4d42124ee8503095243"
},
{
"name": "escapeRegularExpression",
"kind": "function",
"sha256": "8c895b59e4a50a28f11a62883bf68be67a4672fca55774f3060c7992acce734a"
},
{
"name": "isNationalChannel",
"kind": "function",
"sha256": "29f495b1163cc240bccbfc6a490fb04aa892ec65dc40d599f14fbd8f0628f625"
},
{
"name": "isProvinceChannel",
"kind": "function",
"sha256": "ad1d1f53cfc50c474d455fb021fba6ae31887c911d3691d80e2dbfbf6731d73f"
},
{
"name": "validateInboundApplicationSrcId",
"kind": "function",
"sha256": "35e9e29d174f3bc265fb26b1222480e071a16c02e8898fc6b88ba493145350cf"
},
{
"name": "composeUpstreamSrcId",
"kind": "function",
"sha256": "f02d16cd4a722d53b3295d40b24fa0e5e8191475a050b08b99ea256d20746176"
},
{
"name": "positiveInteger",
"kind": "function",
"sha256": "f461d0cb8b5dd9a131337cf2114f0db83ea5a449f752b03c429e8d19e5d95b78"
},
{
"name": "parseOptionalSequenceId",
"kind": "function",
"sha256": "45c7cb2852b6e491ea4ca51c9198bf4e681a728b44ac71cdf226f119795d7ac6"
},
{
"name": "normalizeSubmitStatus",
"kind": "function",
"sha256": "c63234b410942e86f3f8c8dfb65028f75f1e3fe9499e614d578d2c4f4a6ddcb9"
},
{
"name": "normalizeReceiptStatus",
"kind": "function",
"sha256": "5db75635aac978593035af0746422d4842a01008a6d7223c960659120c91d740"
},
{
"name": "downstreamDeliveryAttemptKey",
"kind": "function",
"sha256": "e62c0e52d6484f1599ffc3aaad21871efe8dd29d4cdc4bc6f49f5e95b9c7ad4b"
},
{
"name": "shanghaiDateKey",
"kind": "function",
"sha256": "6bd70c1020b95c8013b29490754a8f2ac243c2d97c7b3fcf043d87cba6bb3296"
},
{
"name": "bullmqConnection",
"kind": "function",
"sha256": "1fe9095c9ed383419f640913f033ff0715d4e241c8114543097a51dbf1acaf67"
},
{
"name": "matchesApplicationSecret",
"kind": "function",
"sha256": "5ff5731f341a2a5ca427f3c232d74b2ef0d54280aba8bf4b4728274dde9b0e4e"
},
{
"name": "octetString",
"kind": "function",
"sha256": "c3c7e6248530121ba0792d8918f43f0869d62fb94e1627f1c0173462fd0c4499"
},
{
"name": "hasRecoveryAuditStateChanged",
"kind": "function",
"sha256": "de4073a3dfd772f0cbb9d57255618cc5f54543ac378325ab35558617749c28ca"
},
{
"name": "normalizeRecoveryFailureCategory",
"kind": "function",
"sha256": "69f4f1dd9c09e4d84277a92eb28cf6d117ac10fa649faf7898ceb0cd0c68a9c5"
}
]
}
@@ -0,0 +1,260 @@
{
"version": "R9",
"generatedAt": "2026-07-31",
"source": "api/src/send-chain/send-chain.service.ts at R8 local baseline",
"target": "api/src/send-chain/send-*.service.ts via send-submission.service.ts compatibility facade",
"methods": [
{
"name": "createBatchTask",
"bodySha256": "c7baccb2b49a95ef4b36a97f6f56c987f0ac60c45ed634cd050201f2a9bce8b5",
"file": "send-batch-entry.service.ts"
},
{
"name": "createHttpBatchTask",
"bodySha256": "9c5a8d4a1a257e418f8abf83b7ae4fc10148e966a77d45e78568207eeabf92a6",
"file": "send-batch-entry.service.ts"
},
{
"name": "getBatchTask",
"bodySha256": "ce25b495f876e746e7b707410e699479bb7d9cb27c2a749c89dd45a956a23c07",
"file": "send-batch-entry.service.ts"
},
{
"name": "previewImport",
"bodySha256": "c722c90e014ee4b7301e8c7a01591b0573574f15b49df5fc9498067235613013",
"file": "send-batch-entry.service.ts"
},
{
"name": "confirmImport",
"bodySha256": "48ed35f8271892be111909dcce3ddf0705e3054ca38a236c416e9b8d41747864",
"file": "send-batch-entry.service.ts"
},
{
"name": "enqueueBatchTask",
"bodySha256": "909972eb0accfb6e31b9fd6118750005c4a6671577ef5b5c9222a341dac59800",
"file": "send-gateway-submit.service.ts"
},
{
"name": "handleReviewDecision",
"bodySha256": "62f118fa543b8db59773300c5218008c25ae779ab9e0a888aac26c7e85ed3db1",
"file": "send-review-continuation.service.ts"
},
{
"name": "dispatchDueScheduledTasks",
"bodySha256": "8fd154bd1318b362b844a97a42cde360623ecb372bd476b92baa54db8a4be768",
"file": "send-scheduled-dispatch.service.ts"
},
{
"name": "runScheduledDispatchScan",
"bodySha256": "02167ffcf1972ee2d85e40d933f0c02fe031300e973fa4307dfd1678a14f27ba",
"file": "send-scheduled-dispatch.service.ts"
},
{
"name": "startWorker",
"bodySha256": "82fe6e5b27f95b15f4a5c218cb6c30e99a9128c293192e7443657d8b245f84d6",
"file": "send-gateway-submit.service.ts"
},
{
"name": "processSendJob",
"bodySha256": "cec399a6552c118a77530f760e2c05b4d2d1fd01c9bdc477f342e0015d461207",
"file": "send-gateway-submit.service.ts"
},
{
"name": "authenticateInboundApplication",
"bodySha256": "2630dd1066b5a3e86c805d13102973e1c928ca2747bd0c3741481d03169eba2f",
"file": "send-inbound-entry.service.ts"
},
{
"name": "submitInboundMessage",
"bodySha256": "281e33a732f80e4ede6cc9d04a5b206a9348e17e66dee33d53f2d8d1d9bb9472",
"file": "send-inbound-entry.service.ts"
},
{
"name": "recoverCompletedInboundLongMessageResponse",
"bodySha256": "d98dd2a7606f45711f9dafbcbf4668c27a4d17a9343ee790ebe2c8b36ff5e49c",
"file": "send-inbound-entry.service.ts"
},
{
"name": "submitCompleteInboundMessage",
"bodySha256": "10e2140580e4bae2055853981de65f4adf82c228b647dbb56fce7c39469acaf3",
"file": "send-inbound-entry.service.ts"
},
{
"name": "collectInboundLongMessageFragment",
"bodySha256": "5b4e7f795966462fccb8c4c7a2cfae649ef19ee1b8176e7356eb2d621526ba41",
"file": "send-inbound-entry.service.ts"
},
{
"name": "expireInboundLongMessages",
"bodySha256": "2328633d6c410089b3be4e38245d238a783015e3411baee0f8202a9c953aa427",
"file": "send-inbound-entry.service.ts"
},
{
"name": "submitInboundSingleMessage",
"bodySha256": "df97548b1710b217f118cc297104d6c5cc845acc40947df4180036b8d284d847",
"file": "send-inbound-entry.service.ts"
},
{
"name": "evaluateRiskWithPhoneFrequency",
"bodySha256": "2e9fab56cd8ae85856fae2e88bb49c1ac1438feea79b7410069554c4fb494782",
"file": "send-inbound-entry.service.ts"
},
{
"name": "submitMessageToGateway",
"bodySha256": "4a928eab5727ba457ee1d4a202e719b6e389361ab2be8ad13ccf146dcebdc141",
"file": "send-gateway-submit.service.ts"
},
{
"name": "selectChannelForMessage",
"bodySha256": "3ab89dbfea42c99a898e7ea62742b200a18615e7aed541c2978af913b9689c68",
"file": "send-gateway-submit.service.ts"
},
{
"name": "findApplicationRoute",
"bodySha256": "110dd4b6d716ee0b08306a16818617b73fba8c6148ae6b7bc87480a2a3f75b54",
"file": "send-gateway-submit.service.ts"
},
{
"name": "identifyCarrier",
"bodySha256": "18e82894203d50d9b2371b9da0ac06fc34e83dd5600d3411f3a09a912955f0b4",
"file": "send-gateway-submit.service.ts"
},
{
"name": "identifyProvince",
"bodySha256": "56d1859733bfe44b6d32295f5706d06b64f1bb03e797e8c894f98b012a71fa35",
"file": "send-gateway-submit.service.ts"
},
{
"name": "resolveUnitPrice",
"bodySha256": "1d14202d83fcc9baa4e56ff2e33771db81f64159852142fadfeae4a89eb5e5c9",
"file": "send-batch-entry.service.ts"
},
{
"name": "resolveQueuePriority",
"bodySha256": "752b13877a4b7a5f89f95cc7f52718e0c473a7c70cb0b99eec63370790540b89",
"file": "send-batch-entry.service.ts"
},
{
"name": "resolveApplicationAccessNumber",
"bodySha256": "948dbcb3106c96c1c2aa3fe4e914590b38f3961d720357b2df3ede07e80663f5",
"file": "send-batch-entry.service.ts"
},
{
"name": "findInboundApplication",
"bodySha256": "6d0bfcb122d0d824f7db542ed3d6a84d034d816f412c61cf96a38510d1738023",
"file": "send-inbound-entry.service.ts"
},
{
"name": "resolveInboundTemplateCandidate",
"bodySha256": "0bd1ccad86d18797132a4f142b24bcfff080021c76217f946301befc81b51b4e",
"file": "send-inbound-entry.service.ts"
},
{
"name": "resolveInboundSignatureCandidate",
"bodySha256": "716a526ea36f92012670c48e3f9cf4a2453435bed6b1943a310e603531998412",
"file": "send-inbound-entry.service.ts"
},
{
"name": "resolveTemplateMessageClassification",
"bodySha256": "f2b99e2e9d7fa00172b3cca72f080493fbf6f090f378784611388320254575f7",
"file": "send-batch-entry.service.ts"
},
{
"name": "resolveDrainageInfoMatch",
"bodySha256": "31c393cd6b5b641776dc50cee46fe79cc5243adb57c6296a1b0cd8b346896021",
"file": "send-inbound-entry.service.ts"
},
{
"name": "attachMessageToReviewTask",
"bodySha256": "55485f011465ae62006552c1343822623a8d914d2989f74b3e809eea659539c2",
"file": "send-inbound-entry.service.ts"
},
{
"name": "classifyRejectedPhones",
"bodySha256": "cd9fe84399dcf83d4e7926c4c3900f04fb84a526135009e5af17b417bf81b108",
"file": "send-batch-entry.service.ts"
},
{
"name": "validateSendResources",
"bodySha256": "3c96b0edae411fb291cc9f52b0c3de8681c00f870c9e25cfd458703257639f00",
"file": "send-batch-entry.service.ts"
},
{
"name": "reserveDailySendQuota",
"bodySha256": "2f3132ec25ad778d24ca8129263e2a4db9120697160f908fd247c9824dc7bc49",
"file": "send-batch-entry.service.ts"
},
{
"name": "tryReserveDailySendQuota",
"bodySha256": "3de44b2c155cb25a8c327b465235d1ec627b375f5fa521e2c0fc0a9f3b62b3b5",
"file": "send-batch-entry.service.ts"
},
{
"name": "ensureSignatureReportedForChannel",
"bodySha256": "8c2c5c6f4ef9a26a4643f215c5e590e25d91642946094705e6c1fc7070e0bbd3",
"file": "send-gateway-submit.service.ts"
},
{
"name": "resolveMessageSignatureId",
"bodySha256": "4c67a20f76e520afc23756ae475a365769c6eaea18c453a7516f2502c26b756a",
"file": "send-gateway-submit.service.ts"
},
{
"name": "waitForChannelRateLimit",
"bodySha256": "7706917a2535caf85fa17cbe8732179211ebca96ac233ba986c1e713f78f26b8",
"file": "send-gateway-submit.service.ts"
},
{
"name": "refreshTaskProgress",
"bodySha256": "3c5521193128d2d738abf37b7bd6213bfb7c60973d85daa28e4d9f28e2ea81e3",
"file": "send-gateway-submit.service.ts"
},
{
"name": "getSendQueue",
"bodySha256": "9dca5a9008ebd0c472db8807e64be409aed46e5dd289638149f56a4b23970d7e",
"file": "send-gateway-submit.service.ts"
},
{
"name": "getGatewayQueue",
"bodySha256": "0f24d7cbf91cf33b9620c6f6197edddfe64cc49e8d9e237eb656e84fb9965c66",
"file": "send-gateway-submit.service.ts"
},
{
"name": "getRedis",
"bodySha256": "f487638a6b656e0d297ed0f6f3181face99b71895dec42762c834bf1d20dc635",
"file": "send-gateway-submit.service.ts"
},
{
"name": "publishGatewaySubmitCommand",
"bodySha256": "ad68171579e3790c3f9176f6a2c9fd900783da5ae6ded9593f3e156ea0e297de",
"file": "send-gateway-submit.service.ts"
}
],
"domains": [
{
"file": "send-batch-entry.service.ts",
"className": "SendBatchEntryService",
"methodCount": 13
},
{
"file": "send-inbound-entry.service.ts",
"className": "SendInboundEntryService",
"methodCount": 13
},
{
"file": "send-review-continuation.service.ts",
"className": "SendReviewContinuationService",
"methodCount": 1
},
{
"file": "send-scheduled-dispatch.service.ts",
"className": "SendScheduledDispatchService",
"methodCount": 2
},
{
"file": "send-gateway-submit.service.ts",
"className": "SendGatewaySubmitService",
"methodCount": 16
}
]
}
+146
View File
@@ -0,0 +1,146 @@
{
"version": "R11-step-7",
"entry": "src/main.tsx",
"componentsFile": "src/styles/components.css",
"legacyFile": "src/styles/global.css",
"minimumRuleCount": 259,
"minimumSelectorCount": 291,
"compatibilityMarker": "Shared table, form, and modal compatibility primitives migrated in R11 step 7.",
"canonicalMarker": "Canonical reusable component rules.",
"responsiveMarker": "Shared responsive table and form behavior migrated in R11 step 7.",
"genericClasses": [
"table-cell-note",
"modal-footer-actions",
"icon-button",
"table-subline",
"table-link",
"table-actions",
"table-mono-id",
"table-strong-text",
"table-long-text",
"table-long-text--sms-template",
"template-modal-title",
"form-grid",
"form-grid--two",
"radio-row"
],
"allowedStateClasses": [
"has-dot",
"is-disabled"
],
"requiredComponentBindings": {
"src/components/ui/Button.tsx": [
"ui-button"
],
"src/components/ui/Input.tsx": [
"ui-field",
"ui-input"
],
"src/components/ui/Select.tsx": [
"ui-select",
"ui-select__dropdown"
],
"src/components/ui/Table.tsx": [
"ui-table-wrap",
"ui-table",
"ui-table__empty"
],
"src/components/ui/Modal.tsx": [
"ui-modal",
"ui-modal__mask",
"ui-modal__panel",
"ui-modal__header",
"ui-modal__body",
"ui-modal__footer"
]
},
"requiredRuleFragments": [
{
"selector": ".icon-button",
"includes": [
"display:inline-flex",
"height:var(--control-height-md)"
]
},
{
"selector": ".ui-table-wrap",
"includes": [
"max-width:100%",
"border:1px solid var(--color-border)"
]
},
{
"selector": ".ui-table",
"includes": [
"border-collapse:collapse",
"width:100%"
]
},
{
"selector": ".ui-modal",
"includes": [
"display:grid",
"position:fixed",
"z-index:var(--z-modal)"
]
},
{
"selector": ".ui-modal__panel",
"includes": [
"min-width:min(520px, calc(100vw - 48px))",
"transform:translate(-50%, -50%)"
]
},
{
"selector": ".form-grid",
"includes": [
"display:grid",
"gap:var(--space-4)"
]
},
{
"selector": ".radio-row",
"includes": [
"display:flex",
"gap:var(--space-6)"
]
},
{
"selector": ".form-grid--two",
"media": "(max-width: 780px)",
"includes": [
"grid-template-columns:1fr"
]
},
{
"selector": ".table-actions",
"media": "(max-width: 780px)",
"includes": [
"flex-wrap:wrap"
]
},
{
"selector": ".ui-table",
"media": "(max-width: 780px)",
"includes": [
"display:block",
"min-width:0 !important"
]
},
{
"selector": ".ui-table td",
"media": "(max-width: 780px)",
"includes": [
"display:grid",
"grid-template-columns:minmax(84px, 0.42fr) minmax(0, 1fr)"
]
},
{
"selector": ".ui-modal__panel",
"media": "(max-width: 780px)",
"includes": [
"width:calc(100vw - 24px)"
]
}
]
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,455 @@
{
"version": "R7",
"source": "gateway/internal/upstream/manager.go@HEAD-before-R7",
"declarations": [
{
"name": "connection",
"kind": "type",
"file": "connection.go",
"sha256": "4df1abc8aaf424b2a5f500dc795a481d22b3759ca4c1a23fb4c619d4104b9ac4"
},
{
"name": "submitPartResponse",
"kind": "type",
"file": "connection.go",
"sha256": "98f6612c555a8189ff6b32811807cbb566a21de3889359afc11fdebec0a4dd1f"
},
{
"name": "close",
"kind": "func",
"receiver": "connection",
"file": "connection.go",
"sha256": "c56f9c0839b6efad46968e5b7669b60dc757b1aa3b3db4793101667be90e88c7"
},
{
"name": "ensureConnected",
"kind": "func",
"receiver": "connection",
"file": "connection.go",
"sha256": "588082992ce35ee45ef1635c1332d50ab2d642313b65c176edf5c169a3e84d82"
},
{
"name": "handleConnectionLoss",
"kind": "func",
"receiver": "connection",
"file": "connection.go",
"sha256": "c6fdad8cc5cead7b87490d4075b2dbd7a4abdb693669b8dac6484d87f42c1762"
},
{
"name": "identity",
"kind": "func",
"receiver": "connection",
"file": "connection.go",
"sha256": "755d4df355d64e7faf4d75f09ad64a52efecb2770724a1af1f3efa8862eb5456"
},
{
"name": "matches",
"kind": "func",
"receiver": "connection",
"file": "connection.go",
"sha256": "7ebd52a39510f1108159a1666357a0e71ffe2f95df7cd1612d63a95ef600e81b"
},
{
"name": "readLoop",
"kind": "func",
"receiver": "connection",
"file": "connection.go",
"sha256": "5a4cd84fb6eb546dce10790fb8e09872a8308608ca2c7d6dbd773d6af4fbbade"
},
{
"name": "sendResponse",
"kind": "func",
"receiver": "connection",
"file": "connection.go",
"sha256": "af80603adc9ad0a9757c042b2bfcc88582f4e4ad96ac4142e67833ddcb348bce"
},
{
"name": "decodeContent",
"kind": "func",
"file": "deliver.go",
"sha256": "a66a6cc45a405c028cf41c7946dc89c6b1a313019863d6aa4b0a468d3ce7ef3f"
},
{
"name": "deliverPacket",
"kind": "type",
"file": "deliver.go",
"sha256": "ec8b102d29392592af2b840927171a8037b9254fa1e02c50840b552db0f4efb4"
},
{
"name": "deliverPacketFromCMPP2",
"kind": "func",
"file": "deliver.go",
"sha256": "d8a8210f0a756eaa4354ca74089b8af02c7839c35434e49e616c69c3fe22f02f"
},
{
"name": "deliverPacketFromCMPP3",
"kind": "func",
"file": "deliver.go",
"sha256": "31354345d9e3ed87658fc8f8b353a4a3607eff191e836b1f10913a8a2f22e34c"
},
{
"name": "receiptStatus",
"kind": "func",
"file": "deliver.go",
"sha256": "28f650601bb209e123371e8f04cd2e7103686c3b425ea60a6abf5440595c8fb8"
},
{
"name": "commandFor",
"kind": "func",
"receiver": "connection",
"file": "deliver.go",
"sha256": "ec725550863714d1a18497ff7fea01dfa8987fa81d72dd7bbcb65c168a7dde5b"
},
{
"name": "decodeUplinkContent",
"kind": "func",
"receiver": "connection",
"file": "deliver.go",
"sha256": "49bef95beb72d7b780c95d54d7fe7264e820610277a01bc38575d27cc1758b6d"
},
{
"name": "handleDeliver",
"kind": "func",
"receiver": "connection",
"file": "deliver.go",
"sha256": "a4fe7d49043e2454548bdf4efdd2e312688f467e83ae9c4a4c0beff158471a52"
},
{
"name": "handleHeartbeatResponse",
"kind": "func",
"receiver": "connection",
"file": "flow_control.go",
"sha256": "8b677a42a3d62d16e59f0e8bf1faaeae170bcf8f17e00c9b4c0cb3f6f05b52ed"
},
{
"name": "heartbeatLoop",
"kind": "func",
"receiver": "connection",
"file": "flow_control.go",
"sha256": "b89ac640cf9b3b888ecf73c4848119b347e0fda2edb4ac1983ebda0dc7da8e57"
},
{
"name": "releaseWindow",
"kind": "func",
"receiver": "connection",
"file": "flow_control.go",
"sha256": "5bb5aa24192d85ad7a0619ef2f702b0f76975a8e73dbe75e8179af5c767da53d"
},
{
"name": "sendHeartbeat",
"kind": "func",
"receiver": "connection",
"file": "flow_control.go",
"sha256": "9c0164b3257072cc7c4c1827f3213baf2e8d73a077323b83e0278d0f1213be28"
},
{
"name": "tryAcquireWindow",
"kind": "func",
"receiver": "connection",
"file": "flow_control.go",
"sha256": "e766bd3e3554d6b03496652ffb3e16779cc1a5743ab2e016c030f16858651b8c"
},
{
"name": "acquireConnection",
"kind": "func",
"receiver": "connectionPool",
"file": "flow_control.go",
"sha256": "63edb09faf3d5fe19dc1f1e80251e11188707a79e4cb97b854e7a2642653844d"
},
{
"name": "tryAcquireConnection",
"kind": "func",
"receiver": "connectionPool",
"file": "flow_control.go",
"sha256": "11378d52c134e485d434cc396d31d6188a1d2abb322e92cadfd6ec2eddb73c23"
},
{
"name": "ConnectionState",
"kind": "type",
"file": "manager.go",
"sha256": "adc946f31d60738834305e2d1b2c94514ffd57decc6dcf49069eabe6f5adc61c"
},
{
"name": "Manager",
"kind": "type",
"file": "manager.go",
"sha256": "c7ead8b037bc87ad9800650ce191f5fcee9648b8805a133b9506743c762ea608"
},
{
"name": "defaultChannelConnectionID",
"kind": "func",
"file": "manager.go",
"sha256": "1344ae4c7831f4b85b01ab0b69a1d01ff6029c3475973e55a694227bd0081de8"
},
{
"name": "defaultConnectTimeout",
"kind": "const",
"file": "manager.go",
"sha256": "4cd56f6b6b4d26dce6682233198d91f895440b0945c16dc2e734419de269a9e0"
},
{
"name": "normalizeUpstreamConfig",
"kind": "func",
"file": "manager.go",
"sha256": "6922f679a80f15b0562408284baa1633530321748f82064b4599486ebccf33e9"
},
{
"name": "validateConnectChannelCommand",
"kind": "func",
"file": "manager.go",
"sha256": "e74d75116b7189530160608369ee9fa0c11b8aea3608b1da039cc032a51a3738"
},
{
"name": "ConnectChannel",
"kind": "func",
"receiver": "Manager",
"file": "manager.go",
"sha256": "376f150d5375e8068768e5ac6910e96336ae72b7a8967c65de68c44e0d66832f"
},
{
"name": "DisconnectChannel",
"kind": "func",
"receiver": "Manager",
"file": "manager.go",
"sha256": "68eba625ebce875254dd12d9140675bd80a2aac02dbbda947ebb2795cd6aaa8d"
},
{
"name": "connectionFor",
"kind": "func",
"receiver": "Manager",
"file": "manager.go",
"sha256": "90fd44cb9a3a3bc5860fa4c41b1bc230f1a8b49150948a6482f3a3e16341d2a2"
},
{
"name": "ensureDefaultsLocked",
"kind": "func",
"receiver": "Manager",
"file": "manager.go",
"sha256": "1050738b55672cee730f87d7c2e00f555e2c59242319b8970009e318480f7b80"
},
{
"name": "newConnectionPool",
"kind": "func",
"receiver": "Manager",
"file": "manager.go",
"sha256": "0e4ce662f1d076aaad3ee28415395f9447b2675c5f9ac21daf5e188857f3f95b"
},
{
"name": "connectionPool",
"kind": "type",
"file": "pool.go",
"sha256": "6b89ef24af5a726ace99d569dda5b7d8d48530337924d8eb8fd5712d41147098"
},
{
"name": "close",
"kind": "func",
"receiver": "connectionPool",
"file": "pool.go",
"sha256": "2e88c346d26e134071e1d5235249521e3a87df25ef4b441cb04baa549e485d83"
},
{
"name": "countActiveConnections",
"kind": "func",
"receiver": "connectionPool",
"file": "pool.go",
"sha256": "fe0888a6894a67b9558711e4ae8ab81953fe49d9bd3e07548dcaacdf75b208dc"
},
{
"name": "ensureConnected",
"kind": "func",
"receiver": "connectionPool",
"file": "pool.go",
"sha256": "471b79729cb8a28ff77837a42a8fef87a7f9ca638ef05fcb6d584195deffbc33"
},
{
"name": "matches",
"kind": "func",
"receiver": "connectionPool",
"file": "pool.go",
"sha256": "cef5bfa15168f238cd67f459796764a573553923de9392af55341e961c614fc7"
},
{
"name": "protocolLogEvent",
"kind": "type",
"file": "protocol_log.go",
"sha256": "5be7ca704c11594b6b72edbd83b2baac11d22bffd9a1e6c9698a6c07d909a008"
},
{
"name": "emitDeliverResponse",
"kind": "func",
"receiver": "connection",
"file": "protocol_log.go",
"sha256": "96e9ea5776f20d97663b0c1502a65c5d49e9dc53ac28bad5b8df54bac18825d9"
},
{
"name": "emitProtocolLog",
"kind": "func",
"receiver": "connection",
"file": "protocol_log.go",
"sha256": "d44dcf7c538cfd3578a6756d89e23dcad53aa76627a52b781fd7e59e6e3ed302"
},
{
"name": "connectionErrorCategory",
"kind": "func",
"file": "reconnect.go",
"sha256": "6598e63e63ede1035651cee20e085ee5408b328391d2a0c49a59d4c1d74a4d04"
},
{
"name": "isTemporaryReadTimeout",
"kind": "func",
"file": "reconnect.go",
"sha256": "4d25d0d0ab0650d549518bca0b1a8f766dff8d6346aec288bfdfff5357350fe6"
},
{
"name": "reconnectDelay",
"kind": "func",
"file": "reconnect.go",
"sha256": "30acd31250bac730a3a561a3b91829ffc28890c9d94718db524ffb20ab8cbc5d"
},
{
"name": "resetReconnectState",
"kind": "func",
"receiver": "connectionPool",
"file": "reconnect.go",
"sha256": "5373b80c609ab33f99296c5a69b8d1e7a35309eeaabff0160a7ee110d472cf60"
},
{
"name": "scheduleReconnect",
"kind": "func",
"receiver": "connectionPool",
"file": "reconnect.go",
"sha256": "d5a5b113f90b81192d1e2e9e08cc0105ea66044eaf13834cc7cffd9393d46c9f"
},
{
"name": "signalReconnect",
"kind": "func",
"receiver": "connectionPool",
"file": "reconnect.go",
"sha256": "d8d747a45e8f8a7647e73482ad8057e36bd081489d2e8181fe905b2cb5808faa"
},
{
"name": "startSupervisor",
"kind": "func",
"receiver": "connectionPool",
"file": "reconnect.go",
"sha256": "e4d0455ac0c62f5e3e5dee516415d200e7e33e419df8e9ff5e5c741648bd65da"
},
{
"name": "stopped",
"kind": "func",
"receiver": "connectionPool",
"file": "reconnect.go",
"sha256": "4dd236bbdf5e30f3d188a5de75e0c8d1b781d758f50287b8fe4ee55a02136368"
},
{
"name": "superviseReconnects",
"kind": "func",
"receiver": "connectionPool",
"file": "reconnect.go",
"sha256": "081deef84986116b80d635c1ab202a90a668f1e6ea4b556d0222e217b9867df8"
},
{
"name": "encodeContent",
"kind": "func",
"file": "submit.go",
"sha256": "961071e5ad611ee1c9f55f68dbb2d6ba5d3dbddc7daf9027b76e7292cb492d89"
},
{
"name": "protocolVersion",
"kind": "func",
"file": "submit.go",
"sha256": "aaef75fad9276b48e18ed22a23bd2a6b05e983b9a8ec8c3de216656b1f81e38d"
},
{
"name": "submitRequestFields",
"kind": "type",
"file": "submit.go",
"sha256": "dbf2cb6c377f487d543d8f08a1167e0ca77f038fd0d86dcff1d982542b9cbc7f"
},
{
"name": "submitResult",
"kind": "func",
"file": "submit.go",
"sha256": "01a16e0be0695baab3a5cb7056b3d8b2fa51dcaa56caec75a8f277c490d9d8c8"
},
{
"name": "submitSegmentResult",
"kind": "func",
"file": "submit.go",
"sha256": "a5dfdaf6b4a9b5f222d3a370f4310d9ba271ebb3546f0b3969ba679821e6c815"
},
{
"name": "validateSubmitCommand",
"kind": "func",
"file": "submit.go",
"sha256": "b4786c6e421a7fd188d2c2e84b2acfa39dc3e62c79ac8f32262f1a6f078ee14c"
},
{
"name": "Submit",
"kind": "func",
"receiver": "Manager",
"file": "submit.go",
"sha256": "81d3554f05c38d91cde37b4fa918c2d30d7f4e6da2265c2fe0f9b499650375f3"
},
{
"name": "submitPart",
"kind": "func",
"receiver": "connection",
"file": "submit.go",
"sha256": "38407f46b9d5626ba5c854a17d5831727e920e7cc881bb1004a9167c53420363"
},
{
"name": "submitRequestPacket",
"kind": "func",
"receiver": "connection",
"file": "submit.go",
"sha256": "14b2fd65a4c407817bc86d0e79524296ccb8b325a289cc44fb2227b9c5834a2a"
},
{
"name": "submit",
"kind": "func",
"receiver": "connectionPool",
"file": "submit.go",
"sha256": "9efe1c726215a512d7039c852fdca06544f603ed810daae3fe291cc51038315b"
},
{
"name": "defaultInt",
"kind": "func",
"file": "transport.go",
"sha256": "cec47c9a91ab21247e5c62b0c36f24449f622f338bc449e14aaa8cbb9888e295"
},
{
"name": "defaultString",
"kind": "func",
"file": "transport.go",
"sha256": "e3f1c7ba3d2aa985b2df53748e307f4e2769815d3cb8500dc616b929cee1e38a"
},
{
"name": "postJSON",
"kind": "func",
"file": "transport.go",
"sha256": "f173638019db247e64783989125e3b66dbb258e086b08d6049fcb1bc3178f22b"
},
{
"name": "post",
"kind": "func",
"receiver": "Manager",
"file": "transport.go",
"sha256": "0c93f5e542efa601b46f7917ed226dc89d22c0a9a5b37e6a4b73d7134fab8d66"
},
{
"name": "reportState",
"kind": "func",
"receiver": "connectionPool",
"file": "transport.go",
"sha256": "b9d7b1bb926d9d38cbc04c5d08c7fe29acf8bc3534b193e5394b4a739ab49499"
},
{
"name": "snapshotState",
"kind": "func",
"receiver": "connectionPool",
"file": "transport.go",
"sha256": "d11c9e2197c8023946979487e53969babf01afa0773d0cdf7aa11286f95bd4b3"
}
]
}
@@ -1827,6 +1827,7 @@
## 运营看板与短信记录运营商筛选(2026-07-29)
- 运营看板“今日发送趋势”按 `Asia/Shanghai` 自然日固定返回 00:00 至 23:00 共 24 个小时桶,以折线图同时展示每小时业务短信提交总条数和最终状态为 `delivered` 的成功条数;无数据小时必须补零,不使用前端静态数据。
- `SmsMessageRecord.queuedAt` 为 PostgreSQL `timestamp without time zone` 且保存 UTC 时间,小时分桶必须先按 UTC 解释该字段,再转换为 `Asia/Shanghai` 提取小时;结果不得依赖 PostgreSQL 会话时区,不得把北京时间 09:00 的记录显示在 01:00。
- 运营看板“审核处理趋势”更名为“审核处理速度”。按企业认证、短信审核、模板、签名、引流信息五类展示北京时间当天已完成审核数量及平均处理时长;处理时长为同一审核事项本轮审核完成时间减本轮提交时间,无有效提交时间或出现负时长的记录不参与平均值。
- 签名通道发送质量明细的运营商概览固定按移动、联通、电信排列;未识别运营商如有数据排在三大运营商之后,数据库聚合返回顺序不得直接作为展示顺序。
- 运营端短信记录新增运营商筛选,选项为全部、移动、联通、电信、未识别。筛选必须由真实后端和 PostgreSQL 执行,并同时作用于分页总数、当前页和 CSV 导出;“未识别”包含空运营商及不属于三大运营商标准/兼容值的历史记录。
@@ -1836,3 +1837,36 @@
- 短信审核列表将“发送企业 / 企业应用”、“提交时间 / 审核来源”和“号码数量 / 状态”分别合并为三个上下分层的信息格,相关信息不得删除或改为仅在详情中展示。
- 短信内容列应设置为列表主要宽列,桌面端目标宽度不小于 440px;当可用宽度不足时由表格容器横向滚动,不得通过压缩内容列造成短信正文难以阅读。
- 号码数量继续使用真实审核任务关联短信记录数量,并保留打开真实号码分页列表的交互;本次仅调整展示布局,不改变审核查询、批量选择、通过或驳回流程。
## 号码发送频次风控(2026-07-30
- 系统内置并启用两条全局兜底规则:同一企业应用、同一手机号码在北京时间自然日内最多提交 10 条业务短信;在按北京时间时钟对齐的固定 5 分钟周期内最多提交 5 条业务短信。达到阈值的短信仍允许提交,下一条开始直接拒绝。
- 两条规则独立计数、独立命中;任一规则命中即直接拒绝该号码。首版处理动作固定为直接拒绝,不进入人工审核,也不提供放行后继续发送的自动动作。
- 隔离键固定为`applicationId + phoneNumber + ruleCode`。同一号码在不同企业应用下互不影响;同一企业的不同应用也分别计数。
- 计数单位为业务短信号码记录:一次任务向同一号码提交一条短信计 1 条,长短信分片和通道失败补发不重复计数。格式非法、黑名单命中或整个任务已被前置风控拒绝的号码不进入号码频次计数。
- 24 小时规则使用`Asia/Shanghai`自然日 00:00:00 至次日 00:00:005 分钟规则使用 00、05、10 等整 5 分钟对齐周期。进入下一周期时该周期计数自动从 0 开始,不采用命中时刻向后滚动的滑动窗口。
- 运营可分别为企业应用新增两条规则的个性化阈值;应用规则启用时覆盖同码全局兜底规则,未配置或停用时继续使用全局兜底。号码频控阈值只能是大于 0 的整数,周期、时区、对齐方式及直接拒绝动作首版不可修改。
- 命中时必须持久化企业、应用、号码、规则、阈值、触发值、周期起止、来源和触发时间。命中后的同周期提交继续拒绝,但不得重复生成相同的活跃触发记录。
- 风控规则页提供真实后端分页的号码频次触发记录,支持按当前应用范围、号码和拦截中/周期已到期/已人工解除状态查询。
- 运营可对单条触发记录执行“解除并清零”,必须填写原因并记录操作人、时间和审计日志。解除只清零该应用、号码、规则的当前计数,不删除历史记录,也不影响另一条频控规则;同周期再次超过阈值时生成新一代触发记录。
- 计数占用、首次命中记录及活跃命中关联必须由 PostgreSQL 原子完成,并能承受同一应用、同一号码的并发提交;不得使用进程内 Map、Redis 临时键、浏览器 localStorage、静态数据或 Mock 作为正式实现。
## 平台级号码频控白名单(2026-07-30)
- 运营端在风控规则页维护平台级号码频控白名单。处于启用状态的号码,在全平台所有企业及所有应用下均豁免`PHONE_FREQUENCY_24H``PHONE_FREQUENCY_5M`两类号码频控,包括企业应用个性化覆盖规则。
- 白名单不豁免号码格式校验、企业/应用黑名单、敏感词和内容审核、模板与签名审核、余额、应用日限额、路由、报备及其他风控规则;首版不提供企业级或应用级白名单。
- 白名单提供真实后端和数据库分页的增删改查,号码在平台内唯一,支持启用、停用、号码筛选和已删除历史查询。用途说明必填,备注选填;新增、修改、启停和删除均记录操作人、时间、修改前后内容及操作审计。
- 新增或恢复启用白名单时,清零该号码在所有企业应用及两类规则下的当前计数,并解除尚未到期的活跃命中;修改号码时同时清零旧号码和新号码;启停切换或删除时同样清零,确保号码退出白名单后从零开始重新计数。历史命中和白名单记录不得物理删除。
- 白名单有效期间的提交不写入号码频控状态、不增加计数、不产生号码频控命中。白名单写操作事务返回后发起的新请求必须遵循新状态;已经在写操作前进入频控事务的并发请求允许按其已读取的事务快照完成。
- 批量发送时白名单必须按号码集合分块查询,不得逐号码访问数据库;正式实现不得使用 Mock、静态数组或浏览器 localStorage。
## 客户端工作台与短信发送体验完善(2026-07-30)
- 客户端短信服务工作台的账户状态必须基于当前企业真实认证记录展示“已认证”或“未认证”,不得使用账户启停状态代替认证状态;企业主体展示真实企业名称。签名数量统计当前企业未删除、未禁用的真实签名。
- 模板状态和签名状态分别展示当前企业真实待审核数量并可进入对应菜单;“服务提醒”改为“批量任务”,展示当前企业来源为客户端且状态为`pending_review`的真实批量任务数,并可进入批量任务菜单。
- 客户端“今日发送趋势”复用真实 Dashboard 24 个北京时间小时桶,同时展示提交量和成功量;UTC 存储时间必须先按 UTC 解释再转换为`Asia/Shanghai`,不得依赖数据库或浏览器本地时区。
- 签名与引流信息页点击“重置”时,即使筛选条件已经为空,也必须回到第一页并重新请求真实后端,以获取最新签名审核、报备和引流信息状态。
- 运营端企业认证审核和短信模板审核首次打开及点击重置后,默认查询待审核状态。
- 短信发送页的字数和预计条数必须随编辑后的实际短信内容即时重新计算;单条短信不超过70个Unicode字符计1条,长短信按每67个字符计费,预计条数为单号码计费条数乘有效号码数。单价单位显示为“元/条”。
- 提交发送任务失败时使用页面中央弹窗展示真实后端错误;定时发送控件提供按北京时间计算的“今天”按钮,并以浅色背景标出北京时间当天。提交给后端的定时时间必须显式携带`+08:00`时区。
- 提交任务成功后弹窗展示真实任务编号和发送号码数。“继续发送短信”清空当前发送表单和导入内容;“查看任务进度”进入批量任务页面并按任务编号定位本次任务。
+535
View File
@@ -0,0 +1,535 @@
# `global.css` 渐进式拆分计划
更新日期:2026-07-31
适用仓库:CMPP 平台主仓库
计划编号:R12
当前状态:仅完成方案设计,暂不执行
> 本计划必须等当前工作区代码完成周末测试、问题修复和基线确认后再启动。
> 在此之前不得为了本计划移动 CSS、调整选择器、改变样式加载顺序或顺带修改页面。
## 1. 背景
R11 已完成基础样式、AppShell、通用组件、运营端共享样式和客户端共享样式的
本地拆分,但 R11 的完成不代表所有单页面样式已经从 `src/styles/global.css`
迁出。
截至 2026-07-31 的本地工作区快照:
- `src/styles/global.css` 约 9049 行;
- 页面专属样式和跨门户兼容样式仍然混合存在;
- 当前工作区还有大量尚未提交的 R1-R11 重构及业务修改;
- 当前代码尚待周末完成集中测试;
- 本计划未实施、未提交、未推送、未部署。
以上数据只表示编写本计划时的快照。正式执行 R12 前必须重新统计,不能直接把
本文记录视为届时事实。
## 2. 目标与非目标
### 2.1 目标
1. 按页面所有权逐步迁出 `global.css` 中的单页面样式。
2. 每个步骤形成一个可独立构建、测试、发布、观察和回滚的版本。
3. 保持现有页面视觉、交互、真实 API、数据库和业务行为不变。
4. 降低继续开发新页面和新功能时对全局样式的依赖。
5. 最终让 `global.css` 中每一组保留规则都有明确的全局或兼容用途。
### 2.2 非目标
1. 不以一次性清空 `global.css` 为目标。
2. 不以减少行数作为拆分成功的唯一标准。
3. 不在纯 CSS 拆分步骤中重做页面视觉设计。
4. 不在拆分时顺带修改业务功能、接口、文案或数据结构。
5. 不为了统一命名而一次性批量修改多个页面的 className。
6. 不把跨页面规则简单复制到多个页面文件中。
## 3. 启动前置条件
必须同时满足以下条件后,才能执行 R12:
1. 当前工作区代码已经完成用户计划的周末测试。
2. 测试中发现的 Bug 已经处理,或已经明确登记为与 CSS 拆分无关的遗留问题。
3. 本地工作区的修改归属已经确认,不会误覆盖其他会话的改动。
4. 已明确 R1-R11 及当前业务修改的提交、推送和部署状态。
5. 已重新执行并记录:
- `git status --short --branch`
- `git diff`
- `git fetch`
- 本地 `HEAD`
- `origin/main`
- 预生产 `.deployed-commit`
6. 已保存目标页面拆分前的桌面端和移动端视觉基线。
7. 已确认目标页面可以使用真实后端数据进行验收。
如果周末测试仍有未定位的布局、弹窗、表格或响应式问题,应先修复这些问题,再启动
CSS 迁移,避免把原有 Bug 错误归因给拆分。
## 4. 核心拆分原则
### 4.1 每一步只拆一个页面或一个紧密子域
低风险页面可以在一个发布版本中安排两到三个,但实际代码移动仍要保持独立步骤。
中高风险页面每个版本只处理一个页面或一个子页面。
### 4.2 按选择器所有权拆分,不按行数硬切
迁移前必须搜索选择器的全部引用。只有确认属于目标页面的规则才能迁移。
以下情况不得直接移动:
- 同时被运营端和客户端使用;
- 同时被两个以上业务页面使用;
- 选择器名称像页面专属,但实际由公共组件渲染;
- 逗号组合选择器中包含其他页面的分支;
- 媒体查询中混合了多个页面的响应式规则。
### 4.3 完整迁移一个样式族
迁移某个页面样式时,必须同时处理:
- 默认规则;
- hover、focus、active、disabled 等状态;
- 加载、空数据、错误和完成状态;
- 桌面端及全部响应式断点;
- 页面专属动画和 `@keyframes`
- 打印规则;
- 同一组件的弹窗、抽屉、表格和分页规则。
禁止只移动桌面样式,把移动端覆盖遗留在 `global.css`
### 4.4 保持级联顺序
页面 CSS 的导入位置必须保证迁移前后的覆盖顺序一致。迁移步骤中原则上不同时做:
- 选择器权重调整;
- className 重命名;
- `!important` 清理;
- CSS Layers 重排;
- 公共组件视觉改版。
如果发现迁移必须改变权重,应停止纯迁移,把权重治理拆成单独版本。
### 4.5 新增页面样式不得继续进入 `global.css`
R12 启动后建立强制约束:
- 新页面必须有自己的页面 CSS
- 已有页面的新专属样式写入该页面 CSS;
- 真正公共的样式进入对应的基础、壳层、组件、运营端或客户端共享文件;
- 暂时无法判定归属的规则必须写明使用方和保留原因。
## 5. 分阶段实施路线
### R12.0:建立拆分基线和所有权门禁
本步骤不移动生产 CSS。
工作内容:
1. 重新统计各样式文件行数和导入顺序。
2. 建立 `global.css` 选择器所有权清单。
3. 记录每个候选选择器在 React 源码中的引用。
4. 标记单页面、跨页面、跨门户、公共组件和疑似无引用规则。
5. 建立后续步骤使用的选择器归属检查脚本。
6. 保存关键页面视觉基线和构建产物中的 CSS 顺序。
完成标准:
- 能够明确识别已经迁出的选择器是否重新进入 `global.css`
- 能够识别页面 CSS 是否缺少对应的响应式规则;
- 不改变现有页面和生产代码行为。
### 第一阶段:低风险、前缀清晰的页面
#### R12.1:客户端短信发送明细
候选样式:
- `.send-detail-*`
- 对应媒体查询分支
- 仅由发送明细页面使用的状态规则
目标文件:
`src/apps/client/send-detail/ClientSendDetailPage.css`
这是建议的第一个实际迁移步骤,原因是选择器前缀清晰、页面以只读明细为主、
交互状态少、与其他页面耦合较低。
预计迁出规模:约 120-200 行,以正式执行时重新盘点为准。
#### R12.2:客户端上行短信
候选样式:
- `.uplink-*`
- 页面表格、详情和响应式规则
目标文件:
`src/apps/client/uplink/ClientUplinkMessagesPage.css`
#### R12.3:客户端应用管理
候选样式:
- `.sms-app-*`
- 应用卡片、状态、操作区和响应式规则
目标文件:
`src/apps/client/applications/ClientApplicationsPage.css`
#### R12.4:运营看板首页
候选样式:
- `.admin-dashboard-*`
- `.admin-workload-*`
- `.admin-alert-*`
目标文件:
`src/apps/admin/home/AdminHome.css`
第一阶段完成后,应确认拆分方法、检查脚本、加载顺序和视觉验收流程可靠,再进入
更复杂的客户端页面。
### 第二阶段:客户端中高风险页面
#### R12.5:批量任务页面
候选样式:
- `.batch-filter-*`
- `.batch-table-*`
- `.batch-task-*`
- `.batch-progress`
- `.batch-actions`
- `.batch-pagination`
进度条、操作区、分页以及所有响应式分支必须作为一个完整页面样式族迁移。
#### R12.6:客户端模板页面
只迁移模板列表页面实际拥有的样式,例如:
- `.template-toolbar`
- `.template-card-grid`
- `.template-card*`
- `.template-content`
- `.template-vars`
- `.template-card-footer`
以下规则不能因为名称相似而一起迁移:
- 短信发送页使用的 `.template-trigger`
- 短信发送页使用的 `.template-picker-*`
- 通用组件使用的弹窗标题和表单规则。
#### R12.7:客户端短信发送页面
候选样式族:
- `.sms-send-*`
- `.send-card`
- `.receiver-*`
- `.send-form-*`
- `.add-recipient`
- `.import-panel`
- `.send-tip`
- `.send-submit-*`
- `.preview-*`
- `.phone-preview`
- 页面专属模板选择器
本页面交互状态多,涉及号码录入、批量导入、模板选择、发送预览和移动端布局,
必须单独形成一个版本。
#### R12.8:企业认证页面
候选样式:
- `.enterprise-page`
- 企业认证表单和步骤状态
- `.enterprise-result*`
- 对应的全部响应式规则
该页面存在多状态切换,迁移时必须验证未认证、审核中、通过、驳回和重新提交等状态。
### 第三阶段:运营端企业和审核页面
#### R12.9:企业列表和查询区域
只处理企业列表、筛选条件、查询区域和列表卡片,不同时拆企业详情和编辑表单。
#### R12.10:企业详情
候选样式:
- `.admin-enterprise-detail`
- `.admin-enterprise-profile`
- 企业摘要和业务页签
- 企业应用展示区域
#### R12.11:企业新增和编辑表单
处理企业表单、营业执照、联系人和账户配置等页面专属样式。
#### R12.12:企业应用新增和编辑
候选样式:
- `.admin-app-form-*`
- 应用协议配置
- 路由和连接相关表单
- 页面专属开关和提示区域
此步骤涉及复杂表单,应与企业列表和详情分开。
#### R12.13:企业审核
迁移企业审核详情和页面专属布局,保留真正跨审核页面共享的表格、筛选、分页和
状态标志。
#### R12.14:短信、签名、模板和引流审核
优先按具体审核页面逐一迁移。只有确认多个审核页面的结构和视觉完全一致后,
才能把对应规则留在或迁入运营端共享样式。
### 第四阶段:通道和报备页面
这是 R12 风险最高的一组,不得合并成一次大迁移。
#### R12.15:通道组列表
只处理通道组列表、状态、基础操作和响应式布局。
#### R12.16:通道组表单及路由配置
处理通道组编辑、通道路由、优先级和相关动态表单。不得同时修改路由业务规则。
#### R12.17:通道报备列表和详情
处理通道报备列表、签名状态、详情和操作区域。
#### R12.18:待生成报备批次
处理“待生成资料”和“已生成批次”两个 Tab 的筛选、表格、分页和详情弹窗。
拆分时必须保持现有搜索条件宽度和统一按钮规范。
#### R12.19:报备资料导入、审核和预览
处理导入结果、逐行审核、勾选批量审核、整批审核、导出预览和状态修改等样式。
本步骤如果 diff 过大,应继续拆成:
1. 导入和解析结果;
2. 审核列表和批量操作;
3. 导出与预览。
### 第五阶段:统计及其他运营页面
#### R12.20:签名通道发送质量
独立迁移筛选条件、质量卡片、表格、明细弹窗和运营商概览,不与其他统计页面合并。
#### R12.21:下游投递记录
迁移查询、记录表格、详情和响应式布局。
#### R12.22:恢复状态管理
迁移筛选、状态、错误信息、操作区和详情弹窗。
#### R12.23:网关异常及相关记录
按实际页面引用拆分异常记录、协议日志和详情样式。
#### R12.24:充值管理
迁移充值列表、充值操作、凭证和页面专属弹窗。公共回执组件样式不得重复复制。
#### R12.25:运营端上行短信
与客户端上行短信页面分别确认所有权,不能仅因业务名称相同就共用页面专属规则。
#### R12.26:系统用户、操作日志和安全配置
这些页面可能与客户端系统页面共用 `.system-*` 规则。先迁移明确的页面专属规则,
跨门户规则留到第六阶段统一治理。
#### R12.27:引流资料及其他剩余页面
对未覆盖页面重新进行引用盘点,继续遵循“一页一步”的原则,不设置一次性清仓步骤。
### 第六阶段:跨门户兼容样式治理
在所有主要单页面样式完成迁移后,再处理同时被运营端和客户端使用的历史规则,例如:
- `.system-page`
- `.system-page-toolbar`
- `.system-filter-row`
- `.system-table-card`
- `.inline-actions`
- `.system-user-form`
- 其他经引用扫描确认的跨门户兼容类名
逐项采用以下处理方式之一:
1. 确认真正公共,迁入公共组件或公共布局样式;
2. 只有布局公共,抽取新的公共布局类;
3. 名称相同但实际表现不同,分别改为页面专属类;
4. 暂时不能确认,继续保留在 `global.css` 并注明使用方和原因。
跨门户样式必须最后处理,避免一次变化同时影响多个已拆页面。
### R12.28:最终残留审计
工作内容:
1. 删除经静态扫描和运行时验证确认无引用的规则。
2. 合并确认声明和作用域均等价的重复规则。
3. 检查响应式分支、关键帧、打印样式和浏览器兼容规则。
4. 为必须保留的规则记录用途、使用方和不能下沉的原因。
5. 启用“页面专属样式不得新增到 `global.css`”的持续门禁。
最终成功标准不是 `global.css` 变成零行,而是其剩余规则全部具有明确、可验证的
全局职责。
## 6. 风险分级和建议节奏
### 6.1 风险分级
低风险:
- 客户端发送明细;
- 客户端上行短信;
- 客户端应用管理;
- 运营看板首页。
中风险:
- 批量任务;
- 客户端模板;
- 审核页面;
- 签名通道发送质量;
- 充值和系统页面。
高风险:
- 客户端短信发送;
- 企业认证;
- 企业和应用复杂表单;
- 通道组路由;
- 通道报备和资料导入;
- 下游恢复类页面。
### 6.2 发布节奏
- 低风险页面:一个发布版本最多安排 2-3 个,但分别实施和验证。
- 中风险页面:一个发布版本只处理 1 个页面。
- 高风险页面:一个发布版本只处理 1 个页面或 1 个子页面。
- 不在同一版本中同时拆高风险页面和修改该页面业务功能。
- 每个版本至少稳定观察一个发布周期,再进入下一个高风险步骤。
预计整个计划约 28 个小步骤。步骤数量允许在 R12.0 重新盘点后调整,但不得通过
合并高风险页面来人为压缩版本数量。
## 7. 每一步的固定执行流程
### 7.1 开始前
1. 检查 Git 分支、差异、未跟踪文件和其他会话修改。
2. 记录目标页面当前 CSS 导入链。
3. 搜索候选选择器的全部源码引用。
4. 保存目标页面桌面端和移动端视觉基线。
5. 明确本步骤允许移动和禁止移动的选择器清单。
### 7.2 实施中
1. 新建或使用目标页面 CSS 文件。
2. 从稳定页面入口导入页面 CSS。
3. 迁移完整样式族和所有媒体查询分支。
4. 遇到跨页面的逗号选择器时先拆开规则,再迁移目标分支。
5. 不修改 API、数据库、业务判断、文案和用户操作流程。
6. 不清理与本步骤无关的历史 CSS。
### 7.3 本地门禁
至少执行:
- 目标选择器所有权检查;
- CSS 导入顺序检查;
- 前端 TypeScript 检查;
- Vite 生产构建;
- 已建立的 R0-R11 重构门禁;
- `git diff --check`
CSS 拆分原则上不影响后端,但在准备形成可发布版本时仍应执行项目既定的完整发布
门禁,包括 API、Prisma、Gateway 和依赖安全检查,防止把工作区中的其他修改漏测。
### 7.4 页面验收
使用真实后端和真实接口,至少检查:
- 1280px 及以上桌面端;
- 1024px
- 768px
- 375px 移动端;
- 正常数据;
- 空数据;
- 加载状态;
- 错误状态;
- 表格、分页、弹窗和抽屉;
- 浏览器控制台;
- 页面有无横向溢出。
不得使用 mock、静态数据或 `localStorage` 伪造验收结果。涉及生产环境时,不得发送
真实短信或修改真实通道、余额和连接状态。
### 7.5 记录和发布
1. 更新本计划的实际进度。
2. 同步更新相关测试用例和 `docs/testing-progress.md`
3. 记录迁移前后行数、选择器数量、目标文件和验证结果。
4. 未经明确授权不提交、不推送、不部署。
5. 获得部署授权后,继续遵守项目既定备份、精确提交打包和发布后检查流程。
## 8. 必须暂停拆分的情况
出现以下任一情况,应停止当前步骤并先诊断:
1. 迁移必须改变选择器权重才能保持视觉一致。
2. 一个候选样式被多个未纳入本步骤的页面使用。
3. 页面在迁移前已经存在无法解释的视觉差异。
4. 目标页面真实后端不可用,无法完成关键状态验收。
5. diff 已经大到无法逐段人工复核。
6. 必须同时修改业务逻辑才能继续迁移。
7. 发现其他会话正在修改相同页面或相同样式区段。
暂停后应把问题拆成单独 Bug 或更小的重构步骤,不能通过扩大当前版本范围继续推进。
## 9. 预期结果
计划完成后:
- 页面专属样式由对应页面目录维护;
- 公共样式按基础、壳层、组件、运营端、客户端和跨门户职责维护;
- 新增菜单和页面不再继续膨胀 `global.css`
- 修改一个页面时能够明确判断受影响范围;
- 每次 CSS 调整都有可执行的静态门禁和真实页面回归范围;
- `global.css` 即使仍有一定规模,也不再承担无法解释的页面样式集合职责。
## 10. 后续启动建议
周末现有代码测试完成后,按以下顺序启动:
1. 重新确认 Git、预生产版本和测试基线;
2. 执行 R12.0,不移动生产 CSS;
3. 评审 R12.0 生成的所有权清单;
4. 执行 R12.1 客户端短信发送明细页;
5. 单独完成构建、真实页面验收和发布观察;
6. 确认方法稳定后再继续 R12.2。
在用户明确要求启动前,本计划保持“待执行”状态。
+100
View File
@@ -0,0 +1,100 @@
# R0 渐进式拆分发布与回滚门禁
更新日期:2026-07-30
## 1. 单版本所有权
- 一个拆分版本只能指定一个“结构修改会话”。
- 其他会话可以查阅、测试和报告问题,但不得同时移动同一职责域的文件。
- 开始前记录:负责人、目标域、基线提交、允许修改的文件、明确不修改的文件。
- 发现重叠未提交修改时立即停止移动,先由修改所有者确认边界。
## 2. 开始前检查
- [ ] `git status --short --branch`
- [ ] `git diff`
- [ ] `git fetch`
- [ ] 分别核对 `HEAD``origin/main`
- [ ] 完整阅读 `docs/testing-progress.md` 最新记录
- [ ] 标记其他会话修改、未跟踪文件和构建产物
- [ ] 选择一个业务域,列出稳定门面、调用者、表、队列和副作用
- [ ] 运行目标域定向特征测试并保存基线结果
- [ ] 确认该版本不混入业务规则修改
- [ ] 确认回滚只需回到本版本前精确提交,不依赖手工修库
## 3. 实施中检查
- [ ] 原公开类、方法、导出名和控制器调用保持兼容
- [ ] 纯移动不同时重命名、格式化或改写逻辑
- [ ] 原事务仍由同一顶层用例持有
- [ ] 子服务接收同一 `Prisma.TransactionClient`
- [ ] 数据库锁顺序、唯一约束、幂等键未改变
- [ ] Redis Stream 名称、消费者组和 JSON 字段未改变
- [ ] CMPP Sequence_Id、Msg_Id、版本和分片规则未改变
- [ ] 错误码、中文提示、金额精度和上海时区口径未改变
- [ ] 新模块依赖单向,不新增 `forwardRef` 循环
- [ ] 每完成一个委托点即运行对应定向测试
## 4. 提交前检查
- [ ] `node tools/quality/verify-refactor-r0.mjs`
- [ ] `node tools/spike/validate-gateway-queue-contract.mjs`
- [ ] 目标域定向测试
- [ ] API 全量测试
- [ ] Prisma format、validate、generate 和 migrate status
- [ ] API TypeScript 正式构建
- [ ] 前端 TypeScript 与 Vite 生产构建
- [ ] Gateway `go test ./...``go vet ./...`
- [ ] 依赖安全门禁
- [ ] `git diff --check`
- [ ] 逐文件人工核对 diff,确认只有目标域
- [ ] 更新需求、测试用例和 `docs/testing-progress.md`
构建缓存、`outputs/` 和临时文件不能因为“提交全部代码”而混入提交。
## 5. 发布与观察
- [ ] 只使用精确 Git 提交制作发布包
- [ ] 部署前备份 PostgreSQL、运行源码和环境文件
- [ ] 校验本地和服务器发布包 SHA-256
- [ ] 只使用 `tools/deploy/production-deploy.sh`
- [ ] Gateway 先于 API 重启
- [ ] 检查 migration、服务、端口、health、Redis、Stream pending/lag
- [ ] 检查供应商通道和下游客户连接,不修改真实凭据或状态
- [ ] 检查 API/Gateway error 日志
- [ ] 不为重构验收发送、重投或补发真实短信
- [ ] 观察至少一个完整发布周期后再开始同一门面的下一阶段
## 6. 立即停止条件
出现任一情况,停止继续拆分并回到诊断:
- 测试数量减少但没有明确删除用例的依据;
- 同一输入的 API/队列/CMPP 契约发生变化;
- 事务被拆成多个独立提交;
- 账务重复、漏记或余额出现非预期变化;
- 并发测试出现重复提交、重复补发、重复 Deliver 或重复退款;
- Gateway 重连、ACK、分片或 Msg_Id 映射行为变化;
- 页面需要靠 mock、静态数据或 localStorage 才能展示;
- diff 同时跨越两个业务域且无法逐段人工复核。
## 7. 回滚记录模板
```text
版本:
目标域:
结构修改提交:
发布前提交:
数据库 migration:无 / 列表
发布前备份目录:
触发回滚的证据:
是否涉及业务数据修复:
回滚命令/发布包:
回滚后服务与端口:
回滚后 Redis Stream pending/lag
回滚后通道连接:
回滚后错误日志:
验证人和时间:
```
纯结构拆分原则上不新增 migration。若必须改 schema,应拆成独立业务版本,不与文件移动同批发布。
+144
View File
@@ -0,0 +1,144 @@
# R0 大文件职责与副作用索引
更新日期:2026-07-30
基线提交:`0af671b4ed4713912e703defd08791f164d4eb25`
## 1. 使用方式
本索引是后续拆分版本的行为地图,不是目标架构。开始任何 R1~R11 拆分前,必须:
1. 重新核对 Git 与部署基线,不能直接沿用本文提交号。
2. 找到目标方法所属的职责组、调用者、数据表和副作用。
3. 先运行该职责组的特征测试,再移动代码。
4. 保留原门面、公开方法、事务边界、幂等键和消息结构。
5. 如果实际代码与本文不一致,先更新索引再开始拆分。
## 2. 核心文件总览
| 文件 | 稳定门面 | 直接调用者 | 主要外部副作用 | 拆分优先级 |
|---|---|---|---|---|
| `api/src/send-chain/send-chain.service.ts` | `SendChainService` | Admin/Client SendChain Controller、GatewayEvents、RiskReview、Operations、OpenAPI | PostgreSQL、Redis Stream、Gateway 控制 API、账务与下游回执 | 最高 |
| `gateway/internal/inbound/server.go` | `inbound.Server` | Gateway 启动入口、控制面 | CMPP TCP、NestJS Gateway API、Redis 在线状态、ACK 定时器 | 最高 |
| `gateway/internal/upstream/manager.go` | `upstream.Manager` | Submit Worker、控制面 | 供应商 CMPP TCP、连接池、重连、回执和上行事件 | 最高 |
| `api/src/channels/channels.service.ts` | `ChannelsService` | Channels Controller、Report/SmsConfig 间接调用 | PostgreSQL、Gateway 连接控制、导入导出文件 | 高 |
| `api/src/sms-config/sms-config.service.ts` | `SmsConfigService` | Admin/Client SmsConfig Controller、GatewayEvents | PostgreSQL、Gateway 下游连接状态、审核日志 | 高 |
| `api/src/operations/operations.service.ts` | `OperationsService` | Admin/Client Operations Controller | PostgreSQL 聚合查询、CSV 导出、恢复控制 | 中高 |
| `src/api/adminApi.ts` | `adminApi` | 运营端页面和组件 | HTTP、文件上传下载、认证失败跳转 | 中高 |
| `api/src/report-materials/report-materials.service.ts` | `ReportMaterialsService` | ReportMaterials Controller | PostgreSQL、XLSX/CSV、MinIO/FileObject | 中高 |
| `src/styles/global.css` | 全局 class 名和 CSS 变量 | 全部页面 | 全局级联、响应式覆盖 | 高 |
## 3. SendChainService
### 3.1 公开职责组
| 职责组 | 公开入口(同组方法不得在一次拆分中漏项) | 主要表 | 队列/外部调用 | 不变量 |
|---|---|---|---|---|
| 客户批量发送 | 创建、预览导入、确认导入、取消、任务/号码分页 | `SmsBatchTask``SmsMessageRecord``SmsSendTask` | Redis 任务队列 | 去重、非法号码不计费、任务进度与真实记录一致 |
| HTTP/OpenAPI 发送 | API 请求受理、查询请求结果 | `SmsApiRequest``SmsMessageRecord` | Redis 任务队列 | 请求幂等、签名模板校验、同步错误不进入计费 |
| CMPP 入站 | 鉴权、Submit、长短信分片、重启恢复 | `CmppInboundLongMessage``SmsBatchTask``SmsMessageRecord` | 下游 SubmitResp/Deliver | 一个目标号码一条真实记录;原 `Msg_Id` 可恢复;冲突分片拒绝 |
| 审核恢复 | 审核通过/驳回、聚合任务展开 | `SmsSendTask``SmsMessageRecord` | Redis 任务队列、下游 Deliver | 每条消息只恢复一次;驳回必须释放冻结 |
| 路由与提交 | 入队、选择通道、创建提交记录 | `ChannelRouteRule``SmsChannel``SmsSubmitRecord` | `gateway.submit.commands` | 运营商/省份快照;仅走已报备通道;重试不重复扣费 |
| SubmitResult | 接收分片/聚合结果、提交异常重排 | `SmsSubmitRecord``SmsMessageRecord``GatewaySubmitDeadLetter` | Redis 重排 | 优先按 `submitId`;模糊匹配必须拒绝;相同幂等键恢复 |
| 最终回执 | 回执持久化、匹配、分片聚合、补发 | `UpstreamReceiptInbox``SmsReceiptRecord``SmsMessageSegmentAudit` | 重试提交、下游 Deliver | terminal 状态不可被旧事件降级;并发失败只产生一次补发 |
| 账务 | 冻结、扣费、释放、退款 | `SmsBillingRecord``AccountTransaction` | PostgreSQL 事务锁 | 同一业务键只记账一次;失败/拒绝路径释放或退款 |
| 下游投递 | 创建 Deliver、ACK、人工重排、超时扫描 | `CmppDownstreamDelivery``CmppDownstreamDeliveryAttempt` | Gateway control API、HTTP webhook | `Result=0` 且非零 `Msg_Id` 才是业务 ACK;并发重排只执行一次 |
| 上行短信 | 保存、候选匹配、人工认领 | `SmsUplinkMessage``SmsUplinkMatchCandidate` | 下游 Deliver/Webhook | 共享接入号歧义不得自动错配 |
| 恢复与扫描 | 定时任务、过期回执、长短信恢复、恢复状态 | 多表 | Redis/Gateway | 扫描必须可重复;抢占超时可恢复;不得覆盖已完成状态 |
### 3.2 事务、锁与幂等边界
- 顶层发送用例持有 Prisma 事务;未来子服务只能接收同一个 `TransactionClient`
- 定时任务、补发、下游人工重排使用数据库原子抢占;禁止改回“先查再写”。
- `SmsSubmitRecord``SmsBillingRecord``CmppDownstreamDelivery` 和队列消息之间的关联 ID 是跨进程恢复依据,不能只保存在内存。
- 最终回执以当前尝试和分片审计聚合;旧尝试不得覆盖新尝试的终态。
- 发送链拆分必须运行第 8 节中 SendChain、Billing、Gateway queue 和 Gateway protocol 四组门禁。
## 4. Gateway 入站 Server
| 职责组 | 当前入口/处理器 | 外部状态 | 不变量 |
|---|---|---|---|
| Bind 与鉴权 | CMPP 2.0/3.0 CONNECT、账号鉴权 | NestJS API、Redis presence | disabled 新提交与 receipt-draining 状态必须区分 |
| Submit | 报文归一化、长短信字段解析、调用 API、返回 SubmitResp | NestJS `/inbound/submit` | Sequence_Id 原样响应;API 结果与协议状态一致 |
| 会话与心跳 | ACTIVE_TEST、连接注册/移除 | Redis、API connection events | 心跳超时不保留伪在线连接 |
| 下游 Deliver | 选择会话、写报文、注册 ACK | 内存 ACK registry、API | CMPP 2.0/3.0 报文分别正确;非零 Msg_Id |
| ACK | DELIVER_RESP 匹配、成功/失败回调、超时 | ACK timer、API | 连接/Sequence_Id/Msg_Id 不得串线;超时只回调一次 |
| 恢复 | 账号在线状态与历史待投递恢复 | Redis recovery lock | 锁、退避和 stale owner 不得互相覆盖 |
| 协议日志 | 入站/出站报文安全日志 | API protocol log | 方向、命令、Sequence_Id 正确;不记录明文密码 |
## 5. Gateway 上游 Manager
| 职责组 | 当前入口/处理器 | 外部状态 | 不变量 |
|---|---|---|---|
| 连接池 | connect/disconnect、desired connections | 供应商 TCP、状态回调 | 连接数量与状态回调一致 |
| 重连 | supervisor、退避、鉴权失败分类 | timer、连接状态 | 网络退避封顶;鉴权失败慢速重试;人工停用不自动拉起 |
| Submit | 窗口、Sequence_Id、长短信分片 | CMPP TCP、tracker | 窗口不超限;每分片映射独立;结果可跨重启关联 |
| 回执 | DELIVER receipt 解析与映射 | API/Redis Stream | 通道、目标号码、Msg_Id 联合约束,歧义不误配 |
| 上行 | MO 解析与事件发布 | API/Redis Stream | 内容编码、源/目的号码和协议版本保持 |
| 心跳 | ACTIVE_TEST 和断线判定 | timer、连接池 | 心跳超时只触发一次连接丢失处理 |
## 6. 其余大服务
### ChannelsService
- 公开职责:通道/通道组 CRUD、组成员、路由规则、连接状态、通道测试、健康指标、报备字段、报备任务/记录、回执导入、删除治理。
- 主要表:`SmsChannel``SmsChannelGroup``SmsChannelGroupItem``ChannelRouteRule``CmppConnectionState``ChannelHealthMetric``ChannelReportField``ChannelSignatureReportTask/Record`
- 副作用:Gateway connect/disconnect、通道测试真实提交、报备文件导入导出。
- 禁区:连接控制与数据库状态不可只完成一侧;通道测试不得混入业务计费;删除前依赖检查必须保留。
### SmsConfigService
- 公开职责:应用、签名、模板、引流信息、通用资料字段、客户安全视图、下游连接事件与停用生命周期。
- 主要表:`SmsApplication``SmsSignature``SmsTemplate``SmsDrainageInfo``SignatureMaterial``SignatureReportMaterial``CmppDownstreamConnection/Delivery``AuditRecord`
- 副作用:审核/操作日志、Gateway 连接生命周期。
- 禁区:客户端响应必须继续使用专用安全选择字段;审核状态与通道报备状态不得混为一列。
### OperationsService
- 公开职责:短信/上行/任务分页与导出、运营看板、发送质量、签名通道质量、操作日志、死信、下游投递与恢复、分片审计、全链路追踪、对账。
- 主要表:短信、提交、回执、账务、连接、审计及企业配置相关读模型。
- 副作用:CSV 输出、下游恢复查询/操作;其余应保持只读。
- 禁区:分页总数必须来自数据库;上海时区边界不可依赖数据库会话时区;客户端查询不得泄露通道和内部路由。
### ReportMaterialsService
- 公开职责:官方模板、待生成资料分页/导出、导入配置、导入预览/提交、逐行/批量/整批审核、生成报备批次、批次导出和状态更新。
- 主要表:`ReportMaterialImportProfile/Batch/Item``ReportMaterialBatch/Item``ReportExportFile/Item`、签名/引流/通道报备表。
- 副作用:文件解析、导出文件、对象存储。
- 禁区:导入不得自动审核通过;逐行、勾选和整批审核使用同一状态机;批次生成必须幂等。
## 7. 前端门面与样式
### adminApi.ts
`adminApi` 继续作为稳定导出。其方法按以下域归档,R1 拆分时只能在内部委托,不批量修改页面 import:
- auth/users/roles/permissions
- tenants/applications/certification
- channels/channelGroups/routes/connections/tests
- signatures/templates/drainage/reportMaterials
- riskReview/blacklist/phoneFrequency
- operations/dashboard/messages/uplink/tracing
- reports/reconciliation/profit/quality
- billing/accounts/recharges
- files/audit/deletion governance
HTTP 基址、认证头、错误转换、下载和上传只能由 core 层统一实现;业务域文件不得各写一套。
### global.css
R3 前只允许新增带页面或组件命名空间的规则。拆分时按 token、基础组件、布局、页面域、响应式五层迁移;每批迁移后做桌面和窄屏截图对比。禁止一边迁移一边重新设计页面。
## 8. R0 固定特征测试矩阵
| 门禁 | 命令 | 覆盖 |
|---|---|---|
| 队列契约 | `node tools/spike/validate-gateway-queue-contract.mjs` | Redis Stream 四类消息 |
| R0 清单 | `node tools/quality/verify-refactor-r0.mjs` | 核心门面、契约样例、关键测试名称 |
| 发送链 | `npm --prefix api test -- --runInBand --forceExit send-chain.service.spec.ts` | 并发、幂等、路由、回执、下游 |
| 账务 | `npm --prefix api test -- --runInBand --forceExit billing.service.spec.ts` | 冻结、扣费、释放、退款、并发重放 |
| Gateway | `go test ./...``gateway` 目录) | CMPP、ACK、重连、队列和 tracker |
| Gateway 静态检查 | `go vet ./...``gateway` 目录) | Go 静态错误 |
| API 全量 | `npm --prefix api test -- --runInBand --forceExit` | NestJS 全量行为 |
| 构建 | `npm --prefix api run build``npm run build` | API/前端类型及生产产物 |
R0 本身不移动生产代码;后续版本若修改了上述不变量,必须先把它作为独立 Bug/需求处理,不得伪装为“纯拆分”。
+292
View File
@@ -2610,10 +2610,12 @@
1. 在客户端和运营端分别选择今日、近 7 天、近 30 天。
2. 查看发送趋势图和成功率趋势。
3. 与数据库或明细列表按时间范围聚合结果核对。
4. 写入 UTC `01:00``01:59`(北京时间 `09:00``09:59`)的 `SmsMessageRecord.queuedAt` 样本,并分别在 PostgreSQL 会话时区为 UTC 和 `Asia/Shanghai` 时核对小时桶。
- 预期结果:
- 今日使用平台配置时区,不错算跨日数据。
- 近 7 天和近 30 天边界包含/排除规则明确。
- 趋势图每个点位与明细聚合一致。
- UTC `01:00``01:59` 的样本只计入北京时间 `09:00` 小时桶,不计入 `01:00`;结果不随 PostgreSQL 会话时区变化。
### TC-BILLING-006 运营端人工充值闭环
@@ -4049,3 +4051,293 @@ npm run verify:phase8
| TC-SMS-AUDIT-LAYOUT-002 | 查看包含较长短信正文的审核任务 | 短信内容列宽不小于 440px,正文获得明显更大的展示空间,不被其他元信息列无意义挤压 |
| TC-SMS-AUDIT-LAYOUT-003 | 点击合并格中的“查看列表”并操作待审核任务 | 真实号码分页弹窗正常打开;详情、勾选、批量通过和驳回入口不受布局调整影响 |
| TC-SMS-AUDIT-LAYOUT-004 | 在窄窗口打开短信审核列表 | 表格保持信息格内部上下层级,宽度不足时允许容器横向滚动,不发生文字重叠或操作按钮遮挡 |
## 2026-07-30 号码发送频次风控用例
| 用例编号 | 场景 | 预期结果 |
|---|---|---|
| TC-PHONE-FREQ-001 | 同一应用、同一号码在同一北京时间自然日依次提交 11 条业务短信 | 前 10 条通过号码频控,第 11 条直接拒绝;触发记录保存阈值 10、触发值 11 和当日周期起止 |
| TC-PHONE-FREQ-002 | 同一应用、同一号码在固定 5 分钟周期依次提交 6 条,第 6 条同时未达到日阈值 | 前 5 条通过,第 6 条仅命中 5 分钟规则并直接拒绝;同周期继续提交仍拒绝且不重复生成活跃触发记录 |
| TC-PHONE-FREQ-003 | 在北京时间 12:04:59 提交至阈值,12:05:00 再提交;另在 23:59:59 达到日阈值后次日 00:00:00 提交 | 5 分钟计数在 12:05:00 进入新周期;日计数在次日 00:00:00 进入新周期,均不是从上次提交时刻滚动计算 |
| TC-PHONE-FREQ-004 | 同一号码分别在应用 A、应用 B 提交,或同一企业的两个应用提交 | 两个应用分别计数,一方命中不会拦截另一方 |
| TC-PHONE-FREQ-005 | 为应用 A 分别配置日阈值 3、5 分钟阈值 2,并保持应用 B 无覆盖 | 应用 A 各自使用个性化阈值;应用 B 继续使用全局 10 条/日和 5 条/5 分钟兜底 |
| TC-PHONE-FREQ-006 | 批量任务含一个已命中号码和一个未命中号码 | 只将命中号码保存为`submit_failed/PHONE_FREQUENCY_LIMIT`且金额为 0;未命中号码正常入队,计费、冻结和日配额只按可发送号码计算 |
| TC-PHONE-FREQ-007 | 发送长短信并发生多个上游分片及失败补发 | 初次业务号码提交只计 1 条;分片、重投和补发不增加号码频次计数 |
| TC-PHONE-FREQ-008 | 提交非法号码、黑名单号码,或任务先被内容/任务级风控整体拒绝 | 这些号码不占用号码频次;数据库状态计数不增加 |
| TC-PHONE-FREQ-009 | 多个并发请求以同一应用、同一号码冲击阈值 | PostgreSQL 原子计数不丢失、不重复放行;超过阈值的请求直接拒绝,并且同周期只有一条活跃触发记录 |
| TC-PHONE-FREQ-010 | 运营在触发记录填写原因后执行解除并清零 | 当前规则的活跃关联解除、计数清零并增加代次;历史命中保留操作人、时间和原因,另一条频控规则不受影响 |
| TC-PHONE-FREQ-011 | 人工解除后在原周期再次连续提交至超阈值 | 按清零后的计数重新计算,再次超阈值时生成同周期新一代触发记录,不与历史唯一键冲突 |
| TC-PHONE-FREQ-012 | 在触发记录页按应用范围、部分号码和拦截中/已到期/已解除筛选并翻页 | 条件、总数和目标页均由真实后端及 PostgreSQL 返回;刷新页面结果保持,不依赖 Mock 或 localStorage |
| TC-PHONE-FREQ-013 | 新增或编辑号码频控规则,尝试阈值 0、小数或动作“人工审核” | 后端拒绝非法配置;有效规则的动作始终为直接拒绝,周期固定为北京时间自然日或固定 5 分钟 |
## 2026-07-30 平台级号码频控白名单用例
| 用例编号 | 场景 | 预期结果 |
|---|---|---|
| TC-PHONE-WL-001 | 将一个已产生频控计数和活跃命中的号码新增为启用白名单 | 该号码在所有企业应用及两类频控规则下的计数清零,活跃命中标记为已解除,历史命中保留 |
| TC-PHONE-WL-002 | 启用白名单号码分别通过两个企业应用连续提交超过24小时和5分钟阈值 | 两个应用均不产生频控计数或命中,提交仍继续经过号码格式、黑名单、内容、余额及其他风控 |
| TC-PHONE-WL-003 | 停用或删除白名单后再次提交 | 停用/删除事务清零全部应用的旧状态;事务完成后的第一条业务短信从1开始计数 |
| TC-PHONE-WL-004 | 将白名单号码A修改为号码B | A、B在所有应用及两类规则下的状态均清零;B按白名单豁免,A恢复受频控约束 |
| TC-PHONE-WL-005 | 新增重复号码、非法号码或空用途说明 | 后端拒绝请求且不写入白名单、频控状态或审计成功记录 |
| TC-PHONE-WL-006 | 查询启用、停用和已删除白名单并翻页 | 后端数据库筛选和分页总数准确;默认列表排除已删除历史,指定已删除状态可查询 |
| TC-PHONE-WL-007 | 删除白名单但未填写删除原因 | 后端拒绝删除;原白名单状态和频控状态保持不变 |
| TC-PHONE-WL-008 | 一批大量号码中仅部分号码在白名单 | 后端分块批量查询白名单,无逐号码N+1查询;仅非白名单号码进入原子频控计数 |
## 2026-07-30 客户端工作台与短信发送体验用例
| 用例编号 | 场景 | 预期结果 |
|---|---|---|
| TC-CLIENT-HOME-001 | 当前企业存在已通过认证、3个有效签名 | 账户状态显示“已认证”,企业主体显示真实企业名称,签名数量显示3,不展示账户启停状态或“当前租户” |
| TC-CLIENT-HOME-002 | 当前企业不存在任何已通过认证 | 账户状态显示“未认证”,其他账户和企业数据仍正常展示 |
| TC-CLIENT-HOME-003 | 分别准备待审核模板、签名和客户端待审核批量任务 | 三个卡片分别显示各自真实数量;点击后进入模板、签名和批量任务菜单 |
| TC-CLIENT-HOME-004 | 当天多个北京时间小时存在短信记录 | 客户端趋势固定展示00:00~23:00提交量和成功量;UTC 01:00记录归入北京时间09:00 |
| TC-CLIENT-SIGNATURE-005 | 筛选条件为空时后台更新签名报备状态,再点击重置 | 页面回到第一页并重新请求后端,展示更新后的报备、审核和引流信息 |
| TC-ADMIN-AUDIT-006 | 首次打开或重置企业认证审核、模板审核页 | 默认筛选“待审核”,后端请求只返回对应待审核记录 |
| TC-CLIENT-SEND-007 | 选择模板后将正文分别编辑为70、71、134和135个Unicode字符 | 单号码预计计费条数依次为1、2、2、3;总预计条数随有效号码数同步变化 |
| TC-CLIENT-SEND-008 | 查看短信发送单价 | 单位显示“元/条”,不显示“元/人” |
| TC-CLIENT-SEND-009 | 后端返回企业账户余额不足或其他提交失败 | 页面中央错误弹窗展示真实错误信息,不只在页面顶部显示 |
| TC-CLIENT-SEND-010 | 打开定时发送日期控件 | 存在“今天”按钮,北京时间当天有浅色背景;选择今天后提交值显式携带`+08:00` |
| TC-CLIENT-SEND-011 | 成功提交真实任务 | 成功弹窗展示后端任务编号和号码数;继续发送可清空全部表单,查看任务进度可定位批量任务 |
## 2026-07-30 R0 渐进式拆分安全护栏用例
| 用例编号 | 场景 | 预期结果 |
|---|---|---|
| TC-REFACTOR-R0-001 | 执行 `node tools/quality/verify-refactor-r0.mjs` | 8 个稳定门面、4 组跨进程契约和 8 项关键特征测试均存在;任一项丢失时非零退出 |
| TC-REFACTOR-R0-002 | 执行 Gateway 队列契约校验 | SubmitCommand、SubmitResult、ReceiptEvent、UplinkEvent 四类真实消息样例全部通过 |
| TC-REFACTOR-R0-003 | 运行 SendChain 与 Billing 特征测试 | 并发抢占、重试、最终回执、下游重排、冻结/扣费/释放/退款和幂等重放行为保持 |
| TC-REFACTOR-R0-004 | 运行 Gateway 全量测试与 `go vet` | CMPP 2.0/3.0、SubmitResp、Deliver ACK、超时、自动重连和 tracker 行为保持 |
| TC-REFACTOR-R0-005 | 检查 R0 代码差异 | 不移动或修改任何生产代码;仅新增路线图、责任索引、门禁清单、契约清单和验证脚本 |
| TC-REFACTOR-R0-006 | 后续拆分开始前执行发布门禁 | 能明确目标域、唯一结构修改会话、稳定门面、事务、表、队列、副作用、停止条件和回滚依据 |
## 2026-07-31 R1 前端 API 兼容门面拆分用例
| 用例编号 | 场景 | 预期结果 |
|---|---|---|
| TC-REFACTOR-R1-001 | 执行 `node tools/quality/verify-admin-api-r1.mjs` | 183个运营端方法、60个客户端方法、7个会话方法和9个HTTP核心函数全部存在,拆分前后实现哈希一致 |
| TC-REFACTOR-R1-002 | 对全部前端源码执行 TypeScript 检查 | 现有页面继续从`@/api/adminApi`导入,类型和方法不丢失,无需批量修改页面 |
| TC-REFACTOR-R1-003 | 执行 Vite 生产构建 | 新领域模块全部进入生产依赖图,构建成功且没有循环依赖或重复导出错误 |
| TC-REFACTOR-R1-004 | 打开本地运营登录页并刷新验证码 | 页面非空、标题和表单正常;验证码真实API返回新算式;控制台无相关warning/error |
| TC-REFACTOR-R1-005 | 模拟或触发401、SESSION_LOCKED和RECENT_AUTHENTICATION_REQUIRED | 继续使用同一HTTP核心处理退出跳转、会话锁定和最近认证重试,不允许各业务域自行实现 |
| TC-REFACTOR-R1-006 | 检查文件上传、Blob导出和查询参数 | 文件大小校验、multipart、租户头、Blob响应及`all`/空值过滤规则与拆分前一致 |
| TC-REFACTOR-R1-007 | 运行R0门禁、API全量测试和Gateway全量测试 | R1没有改变后端、数据库、Redis Stream或CMPP协议行为 |
## 2026-07-31 R2 运营查询服务拆分用例
| 用例编号 | 场景 | 预期结果 |
|---|---|---|
| TC-REFACTOR-R2-001 | 执行`node tools/quality/verify-operations-r2.mjs` | 29个公开方法、3个私有方法、9个查询契约和36个辅助函数全部存在,拆分前后签名及实现哈希一致 |
| TC-REFACTOR-R2-002 | 控制器继续注入并调用`OperationsService` | 路由、参数、返回结构不变,控制器不直接依赖七个内部查询类 |
| TC-REFACTOR-R2-003 | 查询短信记录第一页5条 | PostgreSQL真实总数与分页items独立返回,客户端安全视图继续剔除通道成本、提交和内部路由信息 |
| TC-REFACTOR-R2-004 | 查询北京时间小时发送趋势 | UTC存储值先按UTC解释再转换为`Asia/Shanghai`,不受数据库会话时区影响 |
| TC-REFACTOR-R2-005 | 查询签名通道发送质量 | 分页、运营商固定顺序、业务短信条数和最终成功率口径保持 |
| TC-REFACTOR-R2-006 | 查询系统日志并导出CSV | 关键字、级别、模块、时间范围、CSV转义、时间格式和客户端企业隔离保持 |
| TC-REFACTOR-R2-007 | 查询下游投递、恢复状态和详情 | 告警窗口、分页、应用汇总、失败分类和导出字段保持,不触发重投 |
| TC-REFACTOR-R2-008 | 执行Operations定向及API全量测试 | 页面查询、真实数据库、客户端安全映射和下游恢复既有行为全部通过 |
## 2026-07-31 R3 短信配置兼容门面拆分用例
| 用例编号 | 场景 | 预期结果 |
|---|---|---|
| TC-REFACTOR-R3-001 | 执行`node tools/quality/verify-sms-config-r3.mjs` | 51个公开方法、21个内部方法、19个DTO/查询契约和27个辅助声明全部存在,领域归属正确,迁移前后实现一致 |
| TC-REFACTOR-R3-002 | 检查运营端、客户端和Gateway控制器导入 | 控制器继续只注入`SmsConfigService`DTO从独立`contracts`导入,不再从实现类文件导入 |
| TC-REFACTOR-R3-003 | 按当前企业查询应用、签名、引流信息和模板 | 继续读取真实PostgreSQL;客户端租户边界、分页和历史数据可见性与拆分前一致 |
| TC-REFACTOR-R3-004 | 创建或编辑应用并验证CMPP账号、接入号和路由配置 | CMPP账号与接入号唯一性、密码规范、路由规则事务和操作日志保持原行为 |
| TC-REFACTOR-R3-005 | 执行应用停用、72小时扫描、连接超时和下游断连测试 | 停用状态机、未决投递处理、Gateway断连调用、自动扫描和审计保持原行为 |
| TC-REFACTOR-R3-006 | 新建、编辑、提交及审核签名、引流信息和模板 | 报备字段快照、审核状态、审核人、驳回原因、操作日志及删除治理接口保持 |
| TC-REFACTOR-R3-007 | 执行短信配置与审核治理定向测试 | 既有68项测试全部通过,覆盖客户端租户边界、停用扫描、审核和报备资料校验 |
| TC-REFACTOR-R3-008 | 执行R0R3门禁、API全量、前端构建及Gateway全量测试 | 数据库schema、migration、Redis Stream、CMPP协议、页面API契约和其他业务行为不因R3改变 |
## 2026-07-31 R4 报备资料与企业签名页面拆分用例
| 用例编号 | 场景 | 预期结果 |
|---|---|---|
| TC-REFACTOR-R4-001 | 执行`node tools/quality/verify-report-materials-r4.mjs` | 12个公开方法、11个内部方法、10个契约和32个辅助函数完整存在,领域归属与迁移前实现一致 |
| TC-REFACTOR-R4-002 | 控制器和其他模块继续注入`ReportMaterialsService` | 路由、DTO、请求和响应不变;控制器DTO改从独立contracts导入,内部领域服务不暴露给调用方 |
| TC-REFACTOR-R4-003 | 查询待生成资料、导入配置、导入审核批次和已生成批次 | 真实PostgreSQL分页、关键字和时间筛选保持,不创建批次、文件或操作记录 |
| TC-REFACTOR-R4-004 | 分析并提交Excel导入、逐行或批量审核 | 公式防护、图片提取、字段映射、暂存、审核人、原快照和错误隔离保持 |
| TC-REFACTOR-R4-005 | 使用同一幂等键预检并生成报备批次 | 批次预检、事务认领、完成/失败记录、通道导出文件和任务轨迹保持幂等 |
| TC-REFACTOR-R4-006 | 执行`node tools/quality/verify-enterprise-signatures-r4.mjs` | 原20个函数、签名/引流表格JSX、8个真实API调用和25个页面状态保持,页面容器只负责查询和协调 |
| TC-REFACTOR-R4-007 | 在企业签名页查询、展开签名、编辑签名/引流资料并查看报备弹窗 | 组件拆分后筛选、分页、展开、上传、保存、删除治理及通道状态操作保持真实后端链路 |
| TC-REFACTOR-R4-008 | 执行报备资料定向测试、API全量、前端构建和Gateway测试 | 既有测试全部通过,数据库schema、migration、Redis Stream、CMPP协议和其他页面不因R4改变 |
## 2026-07-31 R5 通道服务兼容门面拆分用例
| 用例编号 | 场景 | 预期结果 |
| --- | --- | --- |
| TC-REFACTOR-R5-001 | 执行`node tools/quality/verify-channels-r5.mjs` | 37个公开方法、14个内部方法、17个契约和60个辅助声明完整存在,领域归属和迁移前实现一致 |
| TC-REFACTOR-R5-002 | 检查控制器、模块和既有测试调用 | 继续只依赖稳定`ChannelsService`DTO从独立contracts导入,路由、参数和响应结构不变 |
| TC-REFACTOR-R5-003 | 编辑名称、说明、成本等非连接参数 | 不调用Gateway断开/连接;只有连接参数实际变化且通道启用时才执行既有重连逻辑 |
| TC-REFACTOR-R5-004 | 执行通道连接、断开、状态同步和超时处理测试 | Gateway控制路径、Redis队列与Stream、定时器、慢重连和状态审计顺序保持 |
| TC-REFACTOR-R5-005 | 检查测试短信入口但不发送真实短信 | 手机号规范化、单次提交`maxAttempts=1`及结果口径保持;未获单独授权不得调用 |
| TC-REFACTOR-R5-006 | 查询和维护通道组、成员及路由规则 | 顺序、权重、主备、运营商/省份兼容性、补发和操作日志语义保持 |
| TC-REFACTOR-R5-007 | 查询报备字段、任务、导出、回执和记录 | 真实PostgreSQL分页、状态汇总、文件字段及历史记录保持,不因只读查询生成文件或写操作记录 |
| TC-REFACTOR-R5-008 | 执行Channels定向测试、API全量及R0~R5完整门禁 | 既有测试全部通过,数据库schema、migration、Redis Stream、Gateway、CMPP协议和其他业务不因R5改变 |
## 2026-07-31 R6 Gateway 入站服务拆分用例
| 用例编号 | 场景 | 预期结果 |
| --- | --- | --- |
| TC-REFACTOR-R6-001 | 执行`go run tools/quality/verify-inbound-r6.go` | 迁移前93个声明在9个领域文件中全部存在,文件归属和实现哈希一致,`server.go`保持稳定入口 |
| TC-REFACTOR-R6-002 | 使用CMPP 2.0、2.1和3.0账号登录 | 版本协商、AuthSource、密码校验、企业代码、最大连接数和连接状态回调保持 |
| TC-REFACTOR-R6-003 | 分别提交单号码、多号码、8位及16位UDH长短信 | 每个目标号码保留独立内部消息映射;客户端每次Submit只收到一次SubmitResp,内容解码和Msg_Id保持 |
| TC-REFACTOR-R6-004 | Submit业务拒绝或API失败 | 同步返回原错误Result,不生成待投递失败回执,不把SubmitResp误记为成功 |
| TC-REFACTOR-R6-005 | Submit成功后立即存在排队回执 | Submit屏障保证SubmitResp先写出,回执Deliver不得抢先;原始Sequence_Id和Msg_Id映射可用于恢复 |
| TC-REFACTOR-R6-006 | 下发回执或上行并收到CMPP_DELIVER_RESP | 按连接、Sequence_Id和Msg_Id精确确认;成功、拒绝、超时及协议日志回调口径保持 |
| TC-REFACTOR-R6-007 | 当前进程找不到消息会话 | 只按原始Submit映射恢复,不允许退化为任意同账号连接;不可恢复时返回既有失败分类 |
| TC-REFACTOR-R6-008 | 多Gateway实例同时扫描待恢复投递 | Redis presence、恢复锁、退避、waiting_connection及完成状态保持,不重复投递 |
| TC-REFACTOR-R6-009 | 执行入站定向、Gateway全量测试和`go vet ./...` | 入站32项及Gateway所有package通过,没有竞态表现、编译错误或静态检查问题 |
| TC-REFACTOR-R6-010 | 执行API全量、前后端构建及R0~R6门禁 | 既有381项API测试和全部门禁通过,数据库schema、migration、Redis Stream及其他业务不因R6改变 |
## 2026-07-31 R7 Gateway 上游管理拆分用例
| 用例编号 | 场景 | 预期结果 |
| --- | --- | --- |
| TC-REFACTOR-R7-001 | 执行`go run tools/quality/verify-upstream-r7.go` | 迁移前68个声明在9个领域文件中全部存在,接收者、文件归属和实现哈希一致,Manager入口保持 |
| TC-REFACTOR-R7-002 | 通过控制接口连接、重复连接及断开通道 | 连接池按通道唯一注册;配置变化才替换池;手工断开关闭stopCh并阻止后续自动重连 |
| TC-REFACTOR-R7-003 | 配置多物理连接和不同窗口大小并并发获取 | 轮询使用可用连接,每个连接独立占用和释放窗口,窗口满时等待且不突破Submit超时 |
| TC-REFACTOR-R7-004 | 供应商端点连接失败后恢复 | 临时网络错误按既有上限退避自动重连;鉴权失败使用5分钟慢重试;恢复后清零重连状态 |
| TC-REFACTOR-R7-005 | 心跳请求成功、响应不匹配或连续超时 | 只清除匹配Sequence_Id;超过阈值关闭连接、唤醒未决提交并进入重连状态机 |
| TC-REFACTOR-R7-006 | 分别向CMPP 2.0和3.0通道提交短信 | 使用对应Submit报文、企业代码、Src_Id、MsgFmt和接收号码;SubmitID及回调字段保持 |
| TC-REFACTOR-R7-007 | 提交UCS2长短信并逐分片返回不同结果 | 拆分、UDH、分片顺序、逐片回调、首Sequence_Id/Msg_Id及聚合停止条件保持 |
| TC-REFACTOR-R7-008 | 收到状态报告、普通上行及乱序长上行 | 回执状态映射、Submit tracker关联、内容解码、长上行组装和API事件保持 |
| TC-REFACTOR-R7-009 | 记录Submit和Deliver协议日志 | 只记录既有安全字段、方向、结果和长度,不泄露密码或完整敏感内容 |
| TC-REFACTOR-R7-010 | 执行上游定向、Gateway全量测试和`go vet ./...` | 上游18项及Gateway全部package通过,连接、重连、窗口、心跳和回执行为不变 |
| TC-REFACTOR-R7-011 | 执行API全量、前后端构建及R0~R7门禁 | 既有381项API测试和全部门禁通过,数据库、Redis Stream、通道配置及业务规则不因R7改变 |
## 2026-07-31 R8 发送链纯逻辑拆分用例
| 用例编号 | 场景 | 预期结果 |
| --- | --- | --- |
| TC-REFACTOR-R8-001 | 执行`node tools/quality/verify-send-chain-r8.mjs` | 24个DTO/事件/队列契约和64个迁移纯声明实现哈希一致;98个编排方法及数据库、队列、重试和分片审计副作用仍由`SendChainService`持有 |
| TC-REFACTOR-R8-002 | 检查运营端、客户端和Gateway事件控制器 | 路由、参数和响应保持;控制器继续注入`SendChainService`DTO改从独立contracts导入 |
| TC-REFACTOR-R8-003 | 给定已按数据库优先级排序的省内和全国通道候选 | 过滤排除、未报备、运营商不兼容及不可连接通道后,优先选择匹配省份,省内不可用时使用全国兜底 |
| TC-REFACTOR-R8-004 | 分片审计尚未收齐、全部成功、存在明确失败或全部为未知 | 未收齐不产生最终成功;全部预期分片成功才成功;任一明确失败优先;收齐但无明确成功/失败时保持未知口径 |
| TC-REFACTOR-R8-005 | 比较上游端点并重复生成回执事件键 | 账号、主机、端口、协议和CMPP版本全部相同才视为同一端点;相同回执输入稳定生成相同事件键 |
| TC-REFACTOR-R8-006 | 运行纯逻辑与既有SendChain定向测试 | 省内/全国选择、分片最终状态、端点身份和事件键新增8项测试通过;既有104项发送链特征测试保持 |
| TC-REFACTOR-R8-007 | 对真实本地PostgreSQL执行只读核验 | 使用真实短信、分片审计和通道连接数据调用纯函数;无可用分片样本时明确记为不适用,不用mock或造数冒充通过 |
| TC-REFACTOR-R8-008 | 执行API全量、前后端构建、Gateway检查及R0~R8门禁 | 389项API测试和全部门禁通过;不改变schema、migration、事务范围、查询、日志字段、队列消息、CMPP协议或业务数据 |
## 2026-07-31 R9 发送入口与提交编排拆分用例
| 用例编号 | 场景 | 预期结果 |
| --- | --- | --- |
| TC-REFACTOR-R9-001 | 执行`node tools/quality/verify-send-chain-r9.mjs` | 45个迁移方法在五个职责文件中的实现哈希保持,`SendChainService`98个稳定方法及内部兼容门面逐项委托 |
| TC-REFACTOR-R9-002 | 创建客户端批量任务或确认号码文件导入 | 非法、重复及黑名单号码先被剔除且不计频控;剩余号码按企业应用隔离执行任务风控、号码频控、日限额和余额预占 |
| TC-REFACTOR-R9-003 | 通过HTTP API提交模板短信 | 模板、签名、变量、企业和应用校验保持;每个号码独立消息记录,仍进入同一批量入口,不形成静态或旁路实现 |
| TC-REFACTOR-R9-004 | CMPP单号码、多号码和长短信入站 | 每个目标号码独立内部记录;同一业务号码只计一次频控和日限额,分片不重复计数;原SubmitResp和Msg_Id恢复语义保持 |
| TC-REFACTOR-R9-005 | 审核通过或拒绝待审核任务 | 通过时恢复消息并按内部批次逐一入队;拒绝时释放未扣预占并生成既有平台失败回执;不重复处理已完成任务 |
| TC-REFACTOR-R9-006 | 两个调度扫描器并发认领到期任务或恢复陈旧认领 | PostgreSQL条件更新保证只冻结和入队一次;入队失败保持可恢复状态,不丢失零资费任务 |
| TC-REFACTOR-R9-007 | Worker处理排队消息并发布Gateway提交 | 通道路由、报备校验、限速、Submit记录事务、BullMQ命令、Redis Stream消息和日志字段保持原顺序及内容 |
| TC-REFACTOR-R9-008 | 替换稳定门面的入队、调度、限速或队列方法后调用上层入口 | 新实现的内部跨方法调用仍经过稳定门面,既有测试缝和可观察边界不被绕过 |
| TC-REFACTOR-R9-009 | 检查R10事故高风险方法归属 | Gateway结果、分片提交/回执、最终聚合、补发、退款和下游投递仍保留在`SendChainService`R9不得提前迁移 |
| TC-REFACTOR-R9-010 | 对真实本地PostgreSQL调用任务查询和导入预检 | 使用真实服务与黑名单查询;任务、短信、频控状态和账户流水调用前后不变,不发送或创建短信 |
| TC-REFACTOR-R9-011 | 执行SendChain定向、API全量、前后端构建、Gateway及R0R9门禁 | 112项定向和389项API测试通过;schema、migration、Redis契约、CMPP协议及其他业务不因R9改变 |
## 2026-07-31 R10 发送完成链编排拆分用例
| 用例编号 | 场景 | 预期结果 |
| --- | --- | --- |
| TC-REFACTOR-R10-001 | 执行`node tools/quality/verify-send-chain-r10.mjs` | 41个迁移方法在七个职责文件中的实现哈希保持;内部完成链门面和`SendChainService`98个稳定方法逐项委托 |
| TC-REFACTOR-R10-002 | Gateway逐分片返回提交成功、拒绝或异常 | 每个预期分片只形成对应审计;提交结果按既有聚合规则更新,不把SubmitResp误认为最终送达 |
| TC-REFACTOR-R10-003 | 重复接收相同上游回执事件 | 稳定事件键和数据库唯一约束保证收件箱、分片审计与最终回执幂等,不重复扣费或投递 |
| TC-REFACTOR-R10-004 | 当前补发尝试和迟到旧尝试分别返回回执 | 只有当前尝试能够推进最终状态;迟到旧尝试保留历史但不得覆盖当前结果 |
| TC-REFACTOR-R10-005 | 分片未收齐、全部成功、明确失败或全部未知 | 未收齐不提前成功;全部成功才最终成功;明确失败优先;未知按既有超时和失败口径处理 |
| TC-REFACTOR-R10-006 | 两个执行者并发抢占同一失败短信补发 | 来源提交唯一关系、事务条件更新和P2002唯一冲突处理保证最多创建一个新提交尝试 |
| TC-REFACTOR-R10-007 | 重复执行成功扣费、失败退款或预占释放 | 账务使用原稳定幂等键,同一业务事件只产生一次账户流水,余额和预占不重复变化 |
| TC-REFACTOR-R10-008 | 创建、认领、发送并ACK最终CMPP/HTTP回执 | 每短信只有一条最终回执语义;下游去重、attempt记录、ACK确认、超时恢复和失败分类保持 |
| TC-REFACTOR-R10-009 | 人工重排失败下游投递或恢复陈旧认领 | 使用稳定重排键和原状态条件,已完成或正由其他执行者处理的记录不得重复投递 |
| TC-REFACTOR-R10-010 | 执行回执超时扫描 | 仅处理满足既有时间和状态条件的当前记录;扫描并发保护和终态聚合保持 |
| TC-REFACTOR-R10-011 | 检查七个完成链领域的持久化操作 | 不存在删除历史事故记录的`deleteMany`路径;提交、回执、attempt、死信和账务历史继续保留 |
| TC-REFACTOR-R10-012 | 对真实本地PostgreSQL查询R10八类表 | 查询前后计数完全一致;无分片或attempt样本时如实记为0,不造数、不发短信、不触发补发或重投 |
| TC-REFACTOR-R10-013 | 执行SendChain定向、API全量、前后端构建、Gateway及R0R10门禁 | 112项定向和389项API测试通过;schema、migration、事务语义、Redis契约、CMPP协议及其他业务不因R10改变 |
## 2026-07-31 R11 页面域与专属样式拆分用例
| 用例编号 | 场景 | 预期结果 |
| --- | --- | --- |
| TC-REFACTOR-R11-001 | 执行`node tools/quality/verify-admin-channels-r11.mjs` | 稳定页面入口不超过300行;五个聚焦模块、真实API调用、交互文案和页面CSS归属完整 |
| TC-REFACTOR-R11-002 | 打开运营端短信通道管理页 | 页面使用真实API返回通道、连接状态和质量数据;标题、筛选区、表头、行操作和分页正常渲染 |
| TC-REFACTOR-R11-003 | 输入通道名称后查询并执行重置 | 查询向真实后端传递筛选条件,列表和总数同步更新;重置恢复全部筛选和真实列表 |
| TC-REFACTOR-R11-004 | 打开编辑通道弹窗后取消 | 原通道名称、运营商、单价、地区、CMPP和心跳参数正常回填;取消不调用保存接口 |
| TC-REFACTOR-R11-005 | 打开连接日志并筛选 | 真实连接状态和日志数据正常展示;关键词只过滤当前结果,不改变通道或连接状态 |
| TC-REFACTOR-R11-006 | 检查发送测试弹窗但不提交 | 手机号、短信内容、接入号、计费条数和结果区域保持;未获授权不得点击最终发送按钮 |
| TC-REFACTOR-R11-007 | 检查复制、启停、删除和添加入口但不确认 | 所有既有入口和确认提示保持;页面拆分不会旁路原API或自动执行写操作 |
| TC-REFACTOR-R11-008 | 检查`global.css``admin.css`与页面CSS | 通道页专属选择器只存在于`AdminChannelsPage.css`;共享`.channel-confirm`由admin层托管,移动端连接摘要规则保持 |
| TC-REFACTOR-R11-009 | 在默认桌面与375×812视口检查页面 | 页面非空、无框架错误覆盖、控制台无相关warning/error;窄屏继续使用既有横向表格浏览方式 |
| TC-REFACTOR-R11-010 | 执行前端生产构建、API/Gateway全量及R0~R11门禁 | 真实后端契约、数据库、Redis Stream、Gateway和CMPP协议不因前端结构迁移改变 |
| TC-REFACTOR-R11-011 | 执行`node tools/quality/verify-admin-sms-task-progress-r11.mjs` | 稳定页面入口不超过220行;六个聚焦模块、真实任务/号码/终止API、交互文案和页面CSS归属完整 |
| TC-REFACTOR-R11-012 | 打开运营端短信任务进度页 | 页面使用真实API返回客户批量任务、企业和应用筛选项;批次号、企业应用、提交时间、号码数、进度、状态和分页正常渲染 |
| TC-REFACTOR-R11-013 | 输入不存在的发送批次号查询,再重置并查询 | 不存在条件返回真实空列表;重置清空全部条件,再次查询恢复真实任务和总数 |
| TC-REFACTOR-R11-014 | 打开真实任务详情 | 提交、发送、计费和成功率指标以及模板、进度、运营商和省份聚合保持原口径,不在前端伪造数据 |
| TC-REFACTOR-R11-015 | 打开号码列表并按部分手机号查询 | 调用真实批次号码分页接口;手机号、归属地、运营商和短信状态与后端一致,筛选后总数同步变化 |
| TC-REFACTOR-R11-016 | 打开终止确认后取消 | 确认文案和已提交部分提示保持;取消不调用终止接口、不改变任务状态 |
| TC-REFACTOR-R11-017 | 检查`global.css``admin.css`与短信任务页面CSS | 页面详情、运营商卡片和移动端专属选择器只存在于页面CSS;报备/下游等运营页面共用的筛选、表格、标识和卡片选择器由admin层托管 |
| TC-REFACTOR-R11-018 | 在默认桌面与375×812视口检查短信任务页面 | 页面、详情弹窗和窄屏卡片均非空且无框架错误覆盖;控制台无warning/error,长表格保持既有可浏览方式 |
| TC-REFACTOR-R11-019 | 执行前端生产构建、API/Gateway全量及全部R0R11门禁 | 389项API测试、Prisma/API构建、Gateway测试/vet和依赖门禁通过;短信、任务、数据库和协议行为不因页面结构迁移改变 |
| TC-REFACTOR-R11-020 | 执行`node tools/quality/verify-admin-sms-records-r11.mjs` | 稳定页面入口不超过220行;四个聚焦模块、五个真实API调用、交互文案、专属与共享CSS归属完整 |
| TC-REFACTOR-R11-021 | 打开运营端短信记录页 | 默认日期范围、企业/应用/运营商/状态选项、内容与通道筛选、后端导出入口、记录列表和分页正常渲染 |
| TC-REFACTOR-R11-022 | 清空默认日期并查询全部真实记录 | 后端返回实际记录与总数,前端不使用静态数组;超过25条时真实分页总页数和上下页状态正确 |
| TC-REFACTOR-R11-023 | 输入完整或部分手机号查询 | 查询参数传给真实记录API,结果、总数和分页同步收窄;不存在的号码显示真实空状态 |
| TC-REFACTOR-R11-024 | 展开运营商筛选 | 固定提供全部、移动、联通、电信、未识别,选择后使用后端`carrier`条件查询 |
| TC-REFACTOR-R11-025 | 打开真实记录的发送详情 | 最终/提交/回执状态、号码归属、接入号、短信内容、通道尝试及回执时间/码与后端数据一致 |
| TC-REFACTOR-R11-026 | 查看有分片与无分片的详情 | 分片审计调用真实接口;有数据按时间、分片序号和ID排序,无数据明确显示暂无分片审计,不造数 |
| TC-REFACTOR-R11-027 | 检查后端CSV导出边界 | 导出继续调用`exportOperationMessages`并使用当前筛选条件,不退化为仅导出当前页的浏览器静态数据 |
| TC-REFACTOR-R11-028 | 检查`global.css``components.css`与短信记录页面CSS | 页面列表、详情、路由、分片和响应式选择器只存在于页面CSS;共享弹窗标题和空状态由components托管,弱化文本样式仍在global |
| TC-REFACTOR-R11-029 | 在默认桌面与375×812视口检查短信记录页面 | 筛选区、记录卡片、详情弹窗和分页非空且无框架错误覆盖;控制台无相关warning/error,窄屏字段不重叠 |
| TC-REFACTOR-R11-030 | 执行前端生产构建、API/Gateway全量及全部R0R11门禁 | 389项API测试、Prisma/API构建、Gateway测试/vet和依赖门禁通过;短信记录、回执和协议行为不因页面拆分改变 |
| TC-REFACTOR-R11-031 | 执行`node tools/quality/verify-admin-enterprise-applications-r11.mjs` | 稳定页面入口不超过300行;六个聚焦模块、六类真实API调用、交互文案、筛选状态分层和页面CSS归属完整 |
| TC-REFACTOR-R11-032 | 打开运营端企业应用管理页 | 页面使用真实分页API返回应用、企业、今日发送、到达率、单价、客户连接状态和应用状态,不使用静态数组 |
| TC-REFACTOR-R11-033 | 输入不存在的企业或应用名称查询,再重置 | 查询条件传给真实后端,列表和总数同步变为空;重置恢复全部条件、第一页和真实应用列表 |
| TC-REFACTOR-R11-034 | 点击添加应用并取消 | 弹窗通过真实企业接口加载未删除企业;未选择企业时下一步禁用,取消不导航、不创建应用 |
| TC-REFACTOR-R11-035 | 打开CMPP连接详情 | 当前连接数、配置连接数、AppID、连接状态和真实已连接会话保持;无会话时显示真实空状态 |
| TC-REFACTOR-R11-036 | 打开CMPP或HTTP参数弹窗后关闭 | 参数由真实详情接口返回;标题、企业/应用上下文和复制入口保持,关闭不修改接口凭据或应用配置 |
| TC-REFACTOR-R11-037 | 打开启用、停用或删除确认后取消 | 停用先调用真实影响预检;等待清算与强制停用文案、未决项统计和确认边界保持,取消不调用状态变更接口 |
| TC-REFACTOR-R11-038 | 检查短信/彩信页签 | 短信应用显示真实表格与分页;彩信继续明确为后端能力待确认,不用mock或静态数据伪造功能 |
| TC-REFACTOR-R11-039 | 检查`global.css``admin.css``components.css``shell.css`与企业应用页面CSS | 筛选、连接、参数和新增提示专属选择器只存在于页面CSS;共享筛选/确认由admin托管,弹窗标题/表单布局由components托管,section布局由shell托管 |
| TC-REFACTOR-R11-040 | 在默认桌面与375×812视口检查企业应用页面 | 页面、筛选、横向表格和安全只读弹窗非空且无框架错误覆盖;控制台无相关warning/error |
| TC-REFACTOR-R11-041 | 执行前端生产构建、API/Gateway全量及全部R0R11门禁 | 389项API测试、Prisma/API构建、Gateway测试/vet和依赖门禁通过;企业应用、连接、数据库和协议行为不因页面拆分改变 |
| TC-REFACTOR-R11-042 | 执行`node tools/quality/verify-foundation-styles-r11.mjs` | 76个设计令牌、13组reset/base规则、逐规则声明哈希、选择器所有权和当前`tokens → reset → shell → global → admin → client → components → AppRoutes`依赖顺序完整 |
| TC-REFACTOR-R11-043 | 检查`tokens.css``reset.css``global.css`职责 | tokens只保留`:root`设计令牌;reset只含元素级基础规则;原global不再重复拥有这些规则,AppShell、组件及页面类未在本步骤迁移 |
| TC-REFACTOR-R11-044 | 执行前端TypeScript及Vite生产构建并检查产物CSS位置 | 新增reset入口进入生产CSS依赖图,实际产物按tokens、reset、global、components/页面依赖顺序拼接;CSS总体体积和既有单chunk提示无异常增长 |
| TC-REFACTOR-R11-045 | 打开已登录运营端代表页面 | 页面背景、字体、标题、链接、按钮、输入框、下拉框、禁用态、表格和弹窗保持,真实API数据正常渲染 |
| TC-REFACTOR-R11-046 | 打开客户端登录页 | Logo、标题、说明、账号/密码/验证码输入、登录按钮和链接保持;不提交登录表单、不改变会话 |
| TC-REFACTOR-R11-047 | 使用键盘聚焦可交互控件 | `:focus-visible`继续显示令牌化焦点环;普通焦点不出现浏览器默认outline,禁用控件仍为不可操作光标 |
| TC-REFACTOR-R11-048 | 在默认桌面与375×812视口检查运营端和客户端代表页面 | 页面非空、无框架错误覆盖或页面级横向溢出,排版和控件没有因reset加载顺序产生跳变;控制台无相关warning/error |
| TC-REFACTOR-R11-049 | 执行API/Gateway全量、Prisma、安全门禁、全部R0~R11结构门禁和`git diff --check` | 389项API测试、API构建、Gateway测试/vet及全部门禁通过;数据库、Redis、CMPP和业务行为不因基础CSS迁移改变 |
| TC-REFACTOR-R11-050 | 执行`node tools/quality/verify-app-shell-styles-r11.mjs` | 118组壳层规则、44个壳层类、九组通用布局选择器、三类响应式/动效边界和样式所有权完整 |
| TC-REFACTOR-R11-051 | 检查`main.tsx`及生产产物CSS | 依赖顺序为`tokens → reset → shell → global → admin → client → components → AppRoutes`,壳层代表规则位于各页面域和components之前 |
| TC-REFACTOR-R11-052 | 检查`global.css``shell.css`和组件样式职责 | AppShell和通用布局原语只由shell托管;在第六步时复用的`.icon-button`、页签、表格、表单和弹窗尚未迁移,第七步迁移后由components托管,页面域样式仍不越界 |
| TC-REFACTOR-R11-053 | 在已登录运营端桌面宽屏点击收起/展开导航 | 主区列宽在标准侧栏和76px折叠栏间切换;完整/紧凑Logo、菜单图标和活动态正常,无内容遮挡 |
| TC-REFACTOR-R11-054 | 在已登录运营端打开并关闭通知及用户菜单 | 弹层定位、层级、计数和空状态保持;只读开关弹层不触发退出、审核、配置或其他写操作 |
| TC-REFACTOR-R11-055 | 在375×812视口打开并关闭移动导航 | 顶栏显示移动入口,侧栏以抽屉和遮罩呈现;关闭按钮/遮罩可收起,页面无横向溢出 |
| TC-REFACTOR-R11-056 | 在系统减少动画偏好下检查侧栏 | 侧栏过渡被关闭,布局和可操作性不变 |
| TC-REFACTOR-R11-057 | 无可用运营端登录态或遇到验证码 | 不伪造会话、不读取浏览器存储、不绕过验证码;将真实点击验收标记为受阻并保留代码级结果 |
| TC-REFACTOR-R11-058 | 执行前端生产构建、API/Gateway全量、Prisma、安全门禁、全部R0~R11结构门禁和`git diff --check` | 29个API套件/389项测试、API构建、Gateway测试/vet及全部门禁通过;数据库、Redis、CMPP和业务行为不因壳层CSS迁移改变 |
| TC-REFACTOR-R11-059 | 执行`node tools/quality/verify-shared-components-r11.mjs` | 259组规则、291个选择器、14组通用类族、桌面/780px所有权和Button/Input/Select/Table/Modal真实绑定完整 |
| TC-REFACTOR-R11-060 | 检查`global.css``components.css`职责 | 纯通用表格、表单、弹窗、页签、图标按钮和表格辅助类只由components托管;页面域复合选择器不被误迁 |
| TC-REFACTOR-R11-061 | 检查组件级联和入口加载顺序 | 兼容规则位于规范组件规则之前,响应式规则位于对应桌面规则之后;最终`tokens → reset → shell → global → admin → client → components → AppRoutes`顺序完整 |
| TC-REFACTOR-R11-062 | 在已登录运营端打开代表性表格并检查空/有数据状态 | 真实后端数据、表头、行、操作区、分页和空状态保持;移动端卡片标签和字段值不重叠 |
| TC-REFACTOR-R11-063 | 打开并关闭普通、宽版和XL代表弹窗 | 遮罩、标题、关闭按钮、正文滚动、页脚操作和宽度保持;仅打开/取消不调用写接口 |
| TC-REFACTOR-R11-064 | 检查代表性表单、单选、页签和图标按钮 | 输入、选择、双列表单、单选行、活动页签、图标按钮及焦点/禁用/悬停状态保持 |
| TC-REFACTOR-R11-065 | 在375×812视口检查表格、表单和弹窗 | 表格使用既有移动卡片布局,表单双列改为单列,弹窗不超出视口,操作按钮可见且页面无横向溢出 |
| TC-REFACTOR-R11-066 | 在PostgreSQL停止但API/Redis仍运行时用有效运营会话恢复 | 会话中间件查用户时应暴露数据库连接异常;当前实现会返回500,不能误归因为前端会话拆分,后续可单独评估health与错误映射增强 |
| TC-REFACTOR-R11-067 | 恢复PostgreSQL后检查会话边界 | 真实Prisma用户查询恢复;无cookie访问`/api/admin/auth/session`返回401,运营端跳转登录页而非500;不得绕过验证码伪造登录态 |
| TC-REFACTOR-R11-068 | 执行前端生产构建、API/Gateway全量、Prisma、安全门禁、全部R0~R11结构门禁和`git diff --check` | 29个API套件/389项测试、API构建、Gateway测试/vet及全部门禁通过;业务、数据库、Redis、Gateway和CMPP行为不因通用组件CSS迁移改变 |
| TC-REFACTOR-R11-069 | 执行`node tools/quality/verify-admin-shared-styles-r11.mjs` | 117组规则、141个选择器、11项跨页面使用下限、admin/client所有权和780px/360px响应式边界完整 |
| TC-REFACTOR-R11-070 | 检查`main.tsx`及生产CSS依赖图 | 最终加载顺序为`tokens → reset → shell → global → admin → client → components → AppRoutes`admin/client域位于global之后、通用组件之前 |
| TC-REFACTOR-R11-071 | 检查`global.css``admin.css`所有权 | 纯admin共享选择器只由admin托管;global只保留带单页面上下文的覆盖规则,client源码不引用admin所有权类 |
| TC-REFACTOR-R11-072 | 打开审核中心的企业、短信、模板、签名和引流审核页 | 审核筛选卡、响应式网格、查询/重置操作和审核操作布局保持,真实后端数据与原API不变 |
| TC-REFACTOR-R11-073 | 打开任务进度、报备记录及下游记录代表页面 | 共用筛选区、任务表格卡、批次标识、企业信息、分页和详情入口保持,真实分页与筛选参数不变 |
| TC-REFACTOR-R11-074 | 打开全局黑名单、企业黑名单和敏感词页面 | 安全页标题、筛选、表单、表格及移动端布局保持;只读验收不新增、删除或导入数据 |
| TC-REFACTOR-R11-075 | 打开用户、号段和引流字段等系统管理代表页面 | 系统工具栏、表格卡、弹窗双列表单和操作区保持;打开后取消,不执行创建、编辑或删除 |
| TC-REFACTOR-R11-076 | 打开质量、利润和对账统计页 | 三类统计筛选网格及查询按钮在桌面和780px下保持,仍调用真实统计接口,不使用静态数据 |
| TC-REFACTOR-R11-077 | 在375×812视口检查审核、任务、安全和系统代表页面 | 筛选区转为单列或既有紧凑布局,按钮宽度、表格/卡片和弹窗不发生页面级横向溢出 |
| TC-REFACTOR-R11-078 | 执行前端生产构建、API/Gateway全量、Prisma、安全门禁、全部R0~R11结构门禁和`git diff --check` | 29个API套件/389项测试、API构建、Gateway测试/vet及全部门禁通过;业务、数据库、Redis、Gateway和CMPP行为不因admin共享CSS迁移改变 |
| TC-REFACTOR-R11-079 | 执行`node tools/quality/verify-client-shared-styles-r11.mjs` | client唯一共享规则、两页面使用下限、三组跨门户兼容边界和五类单页面保留边界完整 |
| TC-REFACTOR-R11-080 | 核对client/admin源码类引用 | `.eyebrow`至少由客户端首页和账单页使用且运营端不引用;没有为了扩大迁移量而错误处理单页面类 |
| TC-REFACTOR-R11-081 | 检查`global.css``client.css`所有权 | 纯`.eyebrow`声明只由client托管;`.overview-hero .eyebrow`页面覆盖继续留在global |
| TC-REFACTOR-R11-082 | 检查跨门户兼容类 | `.sms-send-title``.system-page-toolbar``.system-table-card`继续留在global,客户端与运营端系统日志页面均不丢失样式 |
| TC-REFACTOR-R11-083 | 打开客户端首页和账户账单页 | eyebrow颜色、字号、字重和间距保持;真实首页与账单API数据正常渲染 |
| TC-REFACTOR-R11-084 | 打开签名、发送、企业认证、发送详情和模板代表页面 | 各单页面样式仍由原global规则托管,页面结构、真实接口和交互不因第九步改变 |
| TC-REFACTOR-R11-085 | 在375×812视口检查首页、账单及一个单页面代表 | 标题、卡片、表格和操作区无新增横向溢出,控制台无相关warning/error |
| TC-REFACTOR-R11-086 | 执行前端生产构建、API/Gateway全量、Prisma、安全门禁、全部R0~R11结构门禁和`git diff --check` | 29个API套件/389项测试、API构建、Gateway测试/vet及全部门禁通过;R11九步完成且业务行为不因client共享CSS迁移改变 |
+292
View File
@@ -2748,3 +2748,295 @@ git diff --check
- 部署后使用真实 Prisma Client 和 PostgreSQL 只读执行新路径:运营看板返回 00:00~23:00 共 24 个小时桶和企业认证、短信审核、模板、签名、引流信息 5 类审核速度;短信记录运营商筛选真实计数为移动 630、联通 145、电信 138、未识别 87。共享号码路由服务并发识别 3 次只加载 1 次运营商规则,真实号码和未知号码各用 1 次号段查询,均返回预期结果。
- 尝试受保护 HTTP 验证时,部署管理员凭据文件的 `password=unchanged` 标记被误当成密码提交一次并返回 401;未继续猜测或绕过认证。随后使用部署自带 `ensure-production-admin.mjs` 将该部署管理员失败计数恢复为 0,确认未锁定。发布后 API/Gateway error 级 journal 和 panic/fatal/unhandled/Prisma 关键错误匹配均为 0。
- 本次未发送、重投或补发真实短信,未修改供应商通道凭据或启停状态、企业余额、客户连接和短信业务数据。
## 2026-07-29 运营看板今日发送趋势小时分桶时区修复(本地未提交)
- 预生产只读核验确认“01:00 提交 128 条”并非真实凌晨发送:对应 `SmsMessageRecord.queuedAt` 存储值为 UTC `2026-07-29 01:19:41``01:50:42`,正确北京时间为 `09:19:41``09:50:42`
- 根因是 `queuedAt` 在 PostgreSQL 中为 `timestamp without time zone` 并按 UTC 保存,原聚合 SQL 直接执行 `queuedAt AT TIME ZONE 'Asia/Shanghai'`,把 UTC 墙上时间错误解释为上海本地时间,小时桶整体提前 8 小时且受数据库会话时区影响。
- 小时分桶改为先用 `AT TIME ZONE 'UTC'` 将存储值解释为 UTC,再用 `AT TIME ZONE 'Asia/Shanghai'` 转为北京时间后提取小时;新增 SQL 结构回归断言,并在需求和 `TC-DASHBOARD-007` 中明确 UTC 存储及会话时区无关性。
- Node.js v24.14.0 下 Operations 定向 1 suite / 26 tests 全部通过,API TypeScript 正式构建通过。预生产真实 PostgreSQL 只读执行修正后的等价 SQL,在会话时区分别设置为 UTC 和 `Asia/Shanghai` 时,128 条记录均稳定归入北京时间 `09:00`,未落入 `01:00`
- 本轮按用户要求仅保留本地修改,不提交、不推送、不部署;既有构建缓存、`outputs/`、空文件 `=``tsconfig.tsbuildinfo` 继续原样保留。
## 2026-07-30 号码发送频次风控(本地未提交)
- 按用户确认口径新增两条全局兜底:北京时间自然日 10 条、固定 5 分钟 5 条;隔离键为企业应用、号码和规则,两条规则独立覆盖与命中,首版统一直接拒绝。
- 新增`PhoneFrequencyState`实时状态和`PhoneFrequencyHit`历史触发模型及 migration `20260730093000_add_phone_frequency_controls`。计数通过 PostgreSQL `INSERT ... ON CONFLICT DO UPDATE ... RETURNING`原子占用;大批量号码按 1000 条分块写入但保持同一数据库事务,避免 PostgreSQL 参数数量上限。
- 客户端批量、公开 HTTP 和 CMPP 单号码入口已接入同一频控服务。非法/黑名单号码和任务级已拒绝记录不计数;命中号码按业务短信记录直接失败且金额为 0,未命中号码继续发送,长短信分片与通道补发不重复计数。
- 风控规则页新增两类规则定义,应用级阈值可分别覆盖全局规则,后端强制正整数阈值和直接拒绝动作;新增真实触发记录分页、号码/状态/应用范围查询及“解除并清零”操作。解除原因必填,保留历史触发记录并写操作审计。
- Prisma format、validate、generate通过;API TypeScript正式构建和前端 TypeScript/Vite生产构建通过。新增频控服务 1 suite / 2 tests、发送链 1 suite / 104 tests、原风控 1 suite / 15 tests均通过;API 全量 28 suites / 380 tests全部通过。发送链及全量测试需沿用项目既有`--forceExit`开放句柄处理,首次未带该参数运行在工具时限内未自行退出,未将超时计为通过。
- 本地真实 PostgreSQL 已应用全部 77 条 migration,其中包含`20260730093000_add_phone_frequency_controls`。6 个同应用同号码并发占用的结果为 5 个放行、1 个拒绝,状态计数 6、活跃命中 1 条;后续提交继续拒绝且计数冻结为 6。人工解除后计数归零、代次从 0 增至 1,同周期再次越线成功生成新代次命中;日规则与 5 分钟规则独立生效。验证使用专用测试号码,状态、命中和操作日志均已清理。
- 本地 API 关闭发送 Worker 后连接真实 PostgreSQL 启动成功,Vite production preview 可正常渲染且控制台无错误;访问风控规则目标路由被真实鉴权跳转至图形验证码登录页。`codex_local_admin`在本地数据库中复核为 active、平台管理员、失败次数 0 且未锁定,但本轮未请求用户授权代解验证码,因此未把登录页冒充规则页视觉和解除弹窗交互验收。Vite dev 模式另出现既有`cookie.parse`导出不兼容白屏,改用成功生产构建的 preview 后消失,未修改依赖。
- 验收启动的本地 API、Vite dev/preview 和 PostgreSQL 已停止;原先已运行的 Redis 保持不变。当前仍缺登录后规则页桌面/窄屏视觉和解除弹窗交互验收,未提前宣称该项通过。
- 本轮按用户要求保持本地未提交、未推送、未部署。另一会话既有的运营看板小时分桶时区修复及其文档修改继续保留,不归因于本需求;构建缓存、`outputs/`、空文件`=``tsconfig.tsbuildinfo`继续原样保留。
## 2026-07-30 平台级号码频控白名单(本地未提交)
- 按用户确认口径新增平台级号码白名单:启用号码在全平台所有企业应用下均豁免24小时和5分钟号码频控,其他号码校验、黑名单、内容审核、余额、路由及其他风控不受影响。
- 新增`PhoneFrequencyWhitelist`模型及 migration `20260730114500_add_phone_frequency_whitelist`,号码全平台唯一,记录启用/停用/软删除状态、用途说明、备注、创建人、最后操作人和时间;创建人、更新人及状态时间均建立相应索引。
- 后端提供真实数据库分页、状态/号码/关键字/更新时间查询及新增、修改、停用和软删除接口。批量发送在频控事务内按1000个号码分块读取启用白名单,不使用逐号码查询、Mock、静态数据或localStorage。
- 新增/恢复启用、改号、启停和删除会在同一事务中清零相关号码在所有应用和两类规则下的当前状态,并解除活跃命中;白名单及频控命中历史均保留,所有写操作写入运营审计。
- 运营端风控规则页新增“平台级号码频控白名单”区域,提供号码/状态查询、真实分页、新增、编辑、启停和填写原因后删除,页面明确说明仅豁免两类号码频控及跨应用生效范围。
- Prisma format、validate、generate通过;API TypeScript正式构建、前端TypeScript检查及Vite v8.0.16生产构建通过。号码频控服务定向1 suite / 3 tests、API全量28 suites / 381 tests全部通过;全量Jest仅保留项目既有`--forceExit`开放句柄提示,Vite仅保留既有约1.99MB单chunk提示。
- 本地真实PostgreSQL已应用全部78条migration。专用验收号码先在应用A形成24小时计数6和5分钟计数6/活跃命中1条;新增启用白名单后两类状态均归零且活跃命中被解除;在应用B连续占用12次未产生任何频控状态;删除白名单后应用B两类计数均从1重新开始。白名单、状态、命中和审计验收数据均已清理。
- 本地API以关闭发送Worker、扫描任务和通道重连的安全配置连接真实PostgreSQL运行,`/api/health`返回HTTP 200;前端production preview的目标路由返回HTTP 200且控制台无warning/error。应用内浏览器无既有登录会话,真实鉴权将目标路由跳转至图形验证码登录页,未获本轮授权代解验证码,因此未把登录页冒充白名单区域的登录后视觉验收。
- 本地API继续监听3000,前端production preview继续监听4173PostgreSQL和Redis分别继续监听5432、6379,供用户本地查看。当前按用户要求保持未提交、未推送、未部署;另一会话的运营看板小时分桶修改继续保留且不归因于本需求,构建缓存、`outputs/`、空文件`=``tsconfig.tsbuildinfo`继续原样保留。
## 2026-07-30 客户端工作台与短信发送体验完善(本地未提交)
- 客户端 Dashboard 新增真实企业概览:企业名称来自`Tenant`,认证状态按是否存在已通过`EnterpriseCertification`判定,签名数量排除已删除和已禁用签名,待审核批量任务独立统计当前企业`sourceType=client/status=pending_review``SmsBatchTask`。这些独立查询与原 Dashboard 聚合并行执行。
- 工作台账户状态改为已认证/未认证,企业主体展示企业名称,默认签名改为签名数量;快捷操作移除“真实”字样。模板、签名、批量任务卡片分别展示真实待审核数量并可进入对应菜单。
- 客户端今日发送趋势改为消费后端00:00~23:00共24个北京时间小时桶;继续包含另一会话尚未提交的 UTC 存储时间到上海时区双重转换修复,不将其归因于本需求。
- 签名与引流信息页的“重置”增加刷新代次,即使筛选条件已经为空也会重新请求真实签名工作区;运营端企业认证审核和短信模板审核的初始及重置状态改为待审核。
- 短信发送预计条数改为70字符内1条、长短信每67个Unicode字符一条,并随正文和有效号码数即时计算;单价单位改为元/条。提交失败使用中央弹窗,提交成功弹窗展示真实任务编号和号码数,可清空表单继续发送或携带任务编号进入批量任务页。
- 定时发送日期控件新增按`Asia/Shanghai`计算的“今天”按钮和当天浅色标识,提交时把页面选择值显式规范为`+08:00`;不依赖用户浏览器或服务器默认时区解释业务时间。
- Operations 定向1 suite / 26 tests、API全量28 suites / 381 tests全部通过;API TypeScript正式构建、前端TypeScript检查和Vite v8.0.16生产构建通过,2442个模块完成转换。Jest仅保留项目既有`--forceExit`开放句柄提示,Vite仅保留既有约2.00MB单chunk提示,`git diff --check`通过。
- 本地真实PostgreSQL只读执行企业名称、已通过认证、有效签名和待审核客户端批量任务等价查询成功;样本同时覆盖已认证和未认证企业,未写入或修改认证、签名、任务和短信数据。
- 本地API health和production preview均HTTP 200,浏览器加载前端无框架错误覆盖层且控制台无warning/error;目标客户端路由被真实鉴权跳转到图形验证码登录页。未获授权处理验证码,因此未把登录页当作工作台、短信发送、日期控件和成功/失败弹窗的登录后视觉及交互验收。
- 本轮未提交发送任务、未发送真实短信,也未修改企业余额、通道、客户连接或预生产数据。
- 本轮按用户要求仅保留本地修改,不提交、不推送、不部署。号码频控、平台白名单及其migration、发送链、风控页面和文档是另一会话既有修改,继续完整保留且不归因于本需求。
## 2026-07-30 R0 渐进式拆分安全护栏(本地未提交)
- R0 已按“先锁定行为、不移动生产代码”的范围完成。新增大文件职责与副作用索引,覆盖 `SendChainService`、Gateway 入站/上游、Channels、SmsConfig、Operations、ReportMaterials、`adminApi` 和全局样式,并记录直接调用者、主要数据库表、队列/外部副作用、事务与幂等不变量。
- 新增单版本唯一结构修改会话规则、开始前/实施中/提交前/发布观察清单、立即停止条件和回滚记录模板。后续 R1~R11 每个版本仍需重新核对 Git 与部署事实,不能把本轮基线提交视为永久事实。
- 新增机器可执行的 `tools/quality/verify-refactor-r0.mjs``docs/contracts/refactoring-r0-manifest.json`,固定 8 个稳定门面、Redis Stream 四类契约样例、CMPP 2.0/3.0 报文、Gateway ACK/重连以及发送链和账务并发幂等测试入口。R0 门禁和现有队列契约校验均通过。
- Node.js v24.16.0 下 API 全量 28 suites / 381 tests 全部通过;API TypeScript 正式构建、前端 TypeScript 与 Vite v8.0.16 生产构建、Prisma format/validate/generate、Gateway `go test ./...``go vet ./...`、依赖安全门禁和 `git diff --check` 全部通过。Jest 仅保留项目既有 `--forceExit` 开放句柄提示,Vite 仅保留既有约 2.00MB 单 chunk 提示。
- R0 没有新增或修改业务接口、数据库 schema、migration、Redis Stream 消息或 CMPP 行为,没有启动新服务、写数据库或发送短信。当前工作区既有号码频控/白名单、客户端体验、运营看板等其他修改及构建产物均完整保留,不归因于 R0。
- 本轮按用户要求仅保留本地未提交修改,不提交、不推送、不部署。
## 2026-07-31 R1 前端 API 兼容门面拆分(本地未提交)
- 按路线图完成 R1.1~R1.5。原`src/api/adminApi.ts`从2292行缩减为19行稳定兼容门面;现有页面仍统一从该文件导入,不批量修改73处调用位置。
- 通用HTTP、错误解析、401退出、`SESSION_LOCKED`、最近认证、租户请求头、Blob、multipart和查询参数逻辑移动到`src/api/core/httpClient.ts`;函数体与拆分前逐项一致。运营端按身份与企业、通道与报备、运营查询、审核风控账务、文件上传拆成五个领域对象;客户端API和会话API独立。
- 104个公开类型按common、identity-config、channels-reports、operations、governance五个领域拆分并由统一barrel重导出。最大业务API文件194行,最大类型文件580行;没有新增循环运行时依赖,跨领域引用均为type-only import。
- 新增`docs/contracts/admin-api-r1-methods.json``tools/quality/verify-admin-api-r1.mjs`。门禁确认183个运营端方法、60个客户端方法、7个会话方法及9个HTTP核心函数的实现哈希与拆分前一致,同时确认`adminApi``clientApi``portalSessionApi``fileDownloadUrl`稳定导出仍存在;R0门禁继续通过。
- Node.js v24.16.0下前端TypeScript检查及Vite v8.0.16生产构建通过,2456个模块完成转换;API全量28 suites / 381 tests、API TypeScript正式构建、Gateway`go test ./...``go vet ./...`、依赖安全门禁和`git diff --check`全部通过。Jest仅保留既有`--forceExit`开放句柄提示,Vite仅保留既有约2.00MB单chunk提示。
- 应用内浏览器访问`http://localhost:4173/#/admin/login`,页面标题为“聆界短信管理平台”,登录表单和验证码正常渲染;点击验证码后真实算式发生变化,控制台无warning/error且无框架错误覆盖。未获授权求解验证码和登录,因此登录后关键菜单真实API冒烟仍未执行,未将登录页验证冒充该项通过。
- R1只移动前端API与类型代码,没有修改URL、HTTP方法、请求体、返回类型、页面交互、后端、数据库schema、migration、Redis Stream或CMPP协议;没有写数据库或发送短信。工作区中既有号码频控/白名单、客户端体验、运营看板及其他会话产物继续完整保留,不归因于R1。
- 本轮按用户要求仅保留本地修改,不提交、不推送、不部署。
## 2026-07-31 R2 运营查询服务兼容门面拆分(本地未提交)
- 按路线图完成R2。`api/src/operations/operations.service.ts`从2368行缩减为150行稳定门面,运营端和客户端控制器继续只注入`OperationsService`,29个公开方法的名称、参数、异步标记和返回推断保持不变。
- 原实现按短信记录与CSV、上行与监控、运营看板、发送/签名质量、系统日志、下游投递恢复、追踪对账七个领域迁移;3个私有方法随唯一调用域移动。查询契约独立到`operations.contracts.ts`,36个查询构造、时区、CSV、安全视图和响应汇总函数集中到`operations.helpers.ts`
- 新增`docs/contracts/operations-r2-methods.json``tools/quality/verify-operations-r2.mjs`。R2门禁确认29个公开方法、3个私有方法、9个查询契约和36个辅助函数与拆分前实现哈希一致;SQL、Prisma查询参数、分页、CSV、上海时区和客户端安全映射未改写。
- Operations定向1 suite / 26 tests、API全量28 suites / 381 tests全部通过;Prisma format/validate/generate、API TypeScript正式构建、前端TypeScript与Vite v8.0.16生产构建、Gateway`go test ./...``go vet ./...`、依赖安全门禁和`git diff --check`全部通过。Jest仅保留既有`--forceExit`开放句柄提示,Vite仅保留既有约2.00MB单chunk及本次构建解析耗时提示。
- 真实本地PostgreSQL只读调用拆分后的服务:短信总数56、第一页5条;签名质量和恢复状态当前均为0条;客户端看板返回真实企业“测试客户A”、未认证、有效签名0和待审核任务0。首次只读验证误用了Tenant不存在的`deletedAt`字段,Prisma在SQL执行前拒绝,修正为当前schema字段后通过;全程未写数据库。
- R2没有修改控制器、路由、数据库schema、migration、Redis Stream、Gateway或CMPP协议,没有触发下游重投、文件导出落库或短信发送。当前工作区既有号码频控/白名单、客户端体验、R0/R1及其他会话产物继续完整保留,不归因于R2。
- 本轮按用户要求仅保留本地修改,不提交、不推送、不部署。
## 2026-07-31 R3 短信配置兼容门面拆分(本地未提交)
- 按路线图完成R3。`api/src/sms-config/sms-config.service.ts`从2268行缩减为约244行稳定门面,运营端、客户端、Gateway事件和报备资料服务继续依赖`SmsConfigService`;51个公开方法名称、参数、异步标记和返回推断保持不变。路线图中的“第一阶段”表示保留统一门面,不表示短信配置只拆了一部分。
- 原实现按应用配置与接入参数、应用停用生命周期和下游连接、签名、引流信息、模板、审核记录与动作、共享报备资料校验七个领域迁移。21个内部方法随职责移动;既有私有停用扫描测试入口由门面继续委托生命周期服务,未复制业务实现。
- 19个DTO和查询类型移到`sms-config.contracts.ts`,运营端、客户端和Gateway控制器不再从实现类文件导入DTO。27个规范化、CMPP参数、模板变量及报备值辅助声明集中到`sms-config.helpers.ts``SmsConfigModule`仍只注册并导出稳定门面,不扩大NestJS provider图。
- 新增`docs/contracts/sms-config-r3-methods.json``tools/quality/verify-sms-config-r3.mjs`。R3门禁确认51个公开方法、21个内部方法、19个契约和27个辅助声明领域归属正确,迁移前后方法体在受控依赖委托还原后完全一致;R0、R1、R2门禁继续通过。
- Node.js v24.14.0下短信配置与审核治理定向2 suites / 68 tests、API全量28 suites / 381 tests全部通过;Prisma format/validate/generate、API TypeScript正式构建、前端TypeScript和Vite v8.0.16生产构建、Gateway`go test ./...``go vet ./...`、依赖安全门禁和`git diff --check`通过。Jest只保留既有`--forceExit`开放句柄提示,Vite只保留既有约2.00MB单chunk提示。
- 真实本地PostgreSQL只读调用拆分后的门面成功:读取真实应用并确认租户匹配,应用报备字段当前0条、引流信息0条、模板1条、签名审核记录0条。第一次只读校验脚本按错误的对象结构读取报备字段长度而抛出TypeError,修正为当前数组响应后通过;两次均未执行写操作。
- R3没有修改控制器路由、请求/响应DTO内容、数据库schema、migration、Redis Stream、Gateway或CMPP协议,没有调用创建、编辑、审核、停用、下游重投或短信发送路径。现有号码频控/白名单、客户端体验、R0~R2和其他工作区修改继续完整保留,不归因于R3。
- 本轮按用户要求仅保留本地修改,不提交、不推送、不部署。
## 2026-07-31 R4 报备资料与企业签名页面拆分(本地未提交)
- 按路线图完成R4后端全部边界。`api/src/report-materials/report-materials.service.ts`从1134行缩减为82行稳定门面,12个公开方法的名称、参数、异步标记和返回推断保持;11个内部方法按官方模板与导出、导入解析映射、暂存与审核、待生成查询、批次预检生成、通道文件导出、幂等操作记录七个领域迁移。
- 10个DTO、查询和内部数据类型移到`report-materials.contracts.ts`,32个工作簿安全、字段映射、分页、日期、文件和导出辅助函数移到`report-materials.helpers.ts`。控制器DTO不再从实现类文件导入,模块和其他调用方仍只依赖稳定门面。
- 前端遵守“一个版本只拆一个大页面”,选择`AdminEnterpriseSignaturesPage.tsx`,从884行缩减为238行页面容器。类型、纯展示辅助、动态报备资料、签名编辑、引流编辑、报备状态弹窗和签名/引流表格拆为7个文件,最大132行;页面容器继续统一维护筛选、分页、加载、保存和删除协调。
- 新增`docs/contracts/report-materials-r4-methods.json``docs/contracts/admin-enterprise-signatures-r4.json``tools/quality/verify-report-materials-r4.mjs``tools/quality/verify-enterprise-signatures-r4.mjs`。后端门禁确认12个公开方法、11个内部方法、10个契约和32个辅助函数实现一致;前端门禁确认20个移出函数、表格JSX、8个真实API调用和25个页面状态保持。
- Node.js v24.14.0下报备资料定向1 suite / 10 tests、API全量28 suites / 381 tests全部通过;Prisma format/validate/generate、API TypeScript正式构建、前端TypeScript和Vite v8.0.16生产构建、Gateway`go test ./...``go vet ./...`、依赖安全门禁通过。Jest只保留既有`--forceExit`开放句柄提示,Vite只保留既有约2.00MB单chunk提示。
- 真实本地PostgreSQL只读调用拆分后门面成功:待生成资料、导入审核批次和已生成批次当前均0条,导入映射配置0条;未调用模板生成、文件上传、导入提交、审核、批次生成、幂等认领或通道导出,没有写数据库或对象存储。
- 应用内浏览器访问`http://localhost:4173/#/admin/enterprise-signatures`,真实鉴权将失效会话跳转运营登录页;页面标题、非空DOM、登录提示和表单正常,控制台无warning/error,点击验证码后算式从`25 + 1`变为`36 + 9`。当前浏览器运行时不支持页面或元素截图命令,未切换到未授权的Playwright回退;没有求解验证码或把登录页当成企业签名主体的登录后视觉验收。
- R4没有修改数据库schema、migration、Redis Stream、Gateway、CMPP协议或其他大页面,没有发送短信、生成报备文件或修改业务数据。号码频控/白名单、客户端体验、R0~R3和其他工作区修改继续完整保留,不归因于R4。
- 本轮按用户要求仅保留本地修改,不提交、不推送、不部署。
## 2026-07-31 R5 通道服务兼容门面拆分(本地未提交)
- 按路线图完整拆分R5七个领域。`api/src/channels/channels.service.ts`从2572行缩减为204行稳定门面,控制器、模块和既有测试继续依赖同一入口;37个公开方法的名称、参数、异步标记和返回推断保持不变。
- 原实现按通道配置与状态、连接/重连与Gateway控制、测试短信、通道组与路由、报备字段/任务/回执/记录、通道复制、删除入口七个领域迁移。连接服务统一持有定时器、Redis客户端、Gateway请求和队列副作用;配置服务仅在既有连接参数变化条件满足时委托重连;既有私有Gateway重启恢复测试入口由门面继续委托。
- 17个DTO和查询契约移到`channels.contracts.ts`,控制器不再从实现类文件导入DTO;60个共享常量、类型和纯辅助声明移到`channels.helpers.ts``ChannelsModule`仍只注册并导出稳定门面,没有扩大NestJS provider图。
- 新增`docs/contracts/channels-r5-methods.json``tools/quality/verify-channels-r5.mjs`。门禁确认37个公开方法、14个内部方法、17个契约和60个辅助声明领域归属正确,并锁定连接参数重连条件、Gateway连接/断开路径、定时器、Redis队列和Stream、测试号码规范化及单次提交语义。首次生成版本因统一缩进改变模板字符串内SQL空白,被门禁在`listReportTasks`处拒绝;改为只缩进方法首行后,迁移实现哈希全部一致。
- Channels定向测试首次有1项失败,原因是稳定门面遗漏既有私有`reconnectActiveChannelsAfterGatewayRestart`测试缝;补回纯委托入口后1 suite / 41 tests全部通过。API全量28 suites / 381 tests全部通过;Prisma format/validate/generate、API TypeScript正式构建、前端TypeScript和Vite v8.0.16生产构建、Gateway`go test ./...``go vet ./...`及依赖安全门禁通过。Jest只保留项目既有`--forceExit`开放句柄提示,Vite只保留既有约2.00MB单chunk提示。
- 真实本地PostgreSQL只读调用拆分后门面成功:通道分页返回5/5条、通道组2条、路由规则1条、报备任务1/1条,连接、连接日志、报备字段和报备记录查询均正常完成。验证未调用`onModuleInit`、重连、状态同步、创建、编辑、复制、删除、测试短信、报备导出或其他写路径。
- R5没有修改数据库schema、migration、控制器路由、Redis Stream契约、Gateway或CMPP协议,没有发送真实短信,也没有修改真实通道账号、密码、启停状态或连接。号码频控/白名单、客户端体验、R0~R4及其他工作区修改继续完整保留,不归因于R5。
- 本轮按用户要求仅保留本地修改,不提交、不推送、不部署。
## 2026-07-31 R6 Gateway 入站服务拆分(本地未提交)
- 按路线图在`gateway/internal/inbound`同一Go package内完整拆分R6。原`server.go`从1671行缩减为37行稳定启动入口;`Server.ListenAndServe``DisconnectAccount``PushReceiptWithResult``PushUplinkWithResult`等公开入口、`cmd/gateway`及控制服务调用方式保持不变。
- 原实现按登录认证、Submit与报文转换、下游会话注册、回执/上行Deliver、ACK追踪与SubmitResp顺序屏障、待投递恢复扫描、协议日志、共享HTTP传输八个职责迁移到9个聚焦文件。现有`presence.go``recovery.go`保持原样;没有跨package改接口或形成新的运行时依赖。
- 新增`docs/contracts/inbound-r6-declarations.json``tools/quality/verify-inbound-r6.go`。门禁逐项确认迁移前93个声明的文件归属和实现哈希一致,并锁定稳定启动入口、控制服务三个调用入口及12项关键协议测试。SubmitResp先于排队回执、会话唯一所有权、原始Msg_Id恢复和多实例恢复锁等复杂边界补充了原因注释,没有改写实现。
- 入站定向测试32项全部通过;Gateway`go test ./... -count=1`全部package通过,`go vet ./...`通过。`go test -race ./internal/inbound`因当前Windows Go环境`CGO_ENABLED=0`而在执行测试前拒绝启动,未将竞态检测记为通过,也未为本轮临时安装C工具链。
- API全量28 suites / 381 tests全部通过;API TypeScript正式构建、Prisma format/validate/generate、前端TypeScript和Vite v8.0.16生产构建、依赖安全门禁及R0~R6全部结构门禁通过。Vite只保留既有约2.00MB单chunk提示,Jest只保留既有`--forceExit`开放句柄提示。
- 第一次API全量命令误在仓库根目录直接启动Jest,没有加载`api`目录的TypeScript配置,28个suite均在解析阶段退出且0项测试执行;回到正确`api`工作目录后381项全部通过,该误调用不属于产品失败。
- Gateway测试覆盖真实本地TCP监听及CMPP 2.0/3.0登录、单/多号码、长短信、SubmitResp顺序、Deliver ACK、ACK超时、连接关闭与恢复锁。额外的独立本地Gateway进程冒烟命令被当前执行策略在启动前拦截,因此没有把它记录为通过;本轮没有连接预生产CMPP端口。
- R6没有修改CMPP报文、HTTP回调内容、Redis键、数据库schema、migration、队列或业务规则,没有发送短信、触发补发/重投、登录真实下游账号,也没有修改通道、余额或客户连接。号码频控/白名单、客户端体验、R0~R5及其他工作区修改继续完整保留,不归因于R6。
- 本轮按用户要求仅保留本地修改,不提交、不推送、不部署。
## 2026-07-31 R7 Gateway 上游管理拆分(本地未提交)
- 按路线图在`gateway/internal/upstream`同一Go package内完整拆分R7。原`manager.go`从1495行缩减为198行稳定管理入口;`Manager.Submit``ConnectChannel``DisconnectChannel``ConnectionState`等公开契约,以及`cmd/gateway`、控制服务和Submit Worker调用方式保持不变。
- 原实现按Manager与连接池注册、连接池生命周期、物理连接与读循环、重连状态机、窗口/心跳、Submit与分片、回执/上行Deliver、协议日志、ConnectionState与API回调九个职责迁移。既有`long_message.go`已独立承担长短信拆分和上行组装,本轮保持原样。
- 新增`docs/contracts/upstream-r7-declarations.json``tools/quality/verify-upstream-r7.go`。门禁按接收者类型分别确认迁移前68个声明的文件归属和实现哈希一致,避免混淆连接池与物理连接的同名方法;同时锁定Manager稳定入口、控制服务调用、既有长短信函数及15项关键状态机测试。
- 为慢鉴权重连、手工断开停止条件、每连接窗口所有权、长短信逐分片结果、未决提交唤醒和回执tracker等复杂边界补充原因注释,未修改业务实现、常量或时序。
- 上游定向测试18项全部通过;其中本地重连集成测试使用真实TCP监听模拟供应商端点,先确认连接失败,再启动端点并验证自动恢复连接。Gateway`go test ./... -count=1`全部package通过,`go vet ./...`通过;没有连接任何真实供应商通道。
- API全量28 suites / 381 tests全部通过;API TypeScript正式构建、Prisma format/validate/generate、前端TypeScript和Vite v8.0.16生产构建、依赖安全门禁及R0~R7全部结构门禁通过。Vite只保留既有约2.00MB单chunk提示,Jest只保留既有`--forceExit`开放句柄提示。
- R7没有修改连接数、窗口、心跳、重连延迟、鉴权失败分类、长短信分片、回执状态、HTTP回调、CMPP协议、Redis Stream、数据库schema或migration,没有发送短信、触发补发/重投,也没有修改通道凭据、启停状态、余额或客户连接。号码频控/白名单、客户端体验、R0~R6及其他工作区修改继续完整保留,不归因于R7。
- 本轮按用户要求仅保留本地修改,不提交、不推送、不部署。
## 2026-07-31 R8 发送链纯逻辑拆分(本地未提交)
- 按路线图完成R8。`api/src/send-chain/send-chain.service.ts`从5345行缩减为4578行;24个DTO、Gateway事件和队列契约迁移到`send-chain.contracts.ts`,64个既有常量、状态/错误映射、号码/资源判定、模板/签名/引流分类及事件键等纯声明迁移到`send-chain.helpers.ts`
- `SendChainService`仍保留98个数据库事务、队列发布、Gateway调用和顶层编排方法。通道候选选择、通道可发送性、分片最终状态聚合、上游端点身份比较和回执事件键生成改为显式纯函数;既有数据库查询、事务范围、日志字段、幂等键、队列消息及调用顺序未改变。
- 为省内优先/全国兜底、排除或未报备通道、分片未收齐、全部成功、明确失败优先、上游端点身份和稳定回执事件键新增8项纯逻辑测试。纯逻辑与既有SendChain定向2 suites / 112 tests全部通过,其中既有104项特征测试保持。
- 新增`docs/contracts/send-chain-r8-pure-logic.json``tools/quality/verify-send-chain-r8.mjs`。门禁逐项锁定24个契约与64个迁移声明的实现哈希,确认98个编排方法以及数据库事务、队列、补发和分片审计副作用仍在原服务;R0~R8全部结构门禁继续通过。
- Node.js v24.16.0下API全量29 suites / 389 tests全部通过;Prisma format/validate/generate、API TypeScript正式构建、前端TypeScript和Vite v8.0.16生产构建、Gateway`go test ./... -count=1``go vet ./...`、依赖安全门禁和`git diff --check`全部通过。Jest只保留项目既有`--forceExit`开放句柄提示,Vite只保留既有约2.00MB单chunk提示。
- 真实本地运行态只读核验:API health返回HTTP 200PostgreSQL与Redis端口监听,Redis返回PONG;数据库现有56条短信记录、0条分片审计,因此真实分片聚合样本记为不适用,没有造数冒充通过。使用真实5条通道记录调用可发送性纯函数,当前2条active、0条满足本地连接可发送条件;未调用模块初始化、重连、状态同步或任何写路径。
- R8没有修改数据库schema、migration、控制器路由、Redis Stream、Gateway、CMPP协议或业务规则,没有发送短信、触发补发/重投,也没有修改通道账号、密码、启停状态、余额或客户连接。号码频控/白名单、客户端体验、R0~R7及其他工作区修改继续完整保留,不归因于R8。
- 本轮按用户要求仅保留本地修改,不提交、不推送、不部署;R9、R10再分别拆入口/提交和回执/补发/下游投递编排。
## 2026-07-31 R9 发送入口与提交编排拆分(本地未提交)
- 按路线图完成R9五类入口。`api/src/send-chain/send-chain.service.ts`从R8的4578行缩减为2983行,98个稳定方法继续供控制器、Open API、审核中心和其他模块调用;`send-submission.service.ts`为305行内部兼容门面。
- 45个方法按批量/HTTP入口、CMPP入站、审核续发、定时调度和Gateway提交拆到五个实现文件,行数分别为552、840、109、160和491。没有把最初1939行的单一提交域文件作为终点,避免只移动大文件而不形成职责边界。
- 迁移方法体保持原实现;内部跨方法调用返回`SendChainService`稳定门面,再经内部兼容门面分派,以保留既有覆盖点和测试可观察性。日志上下文继续是`SendChainService`,没有改变控制器路由、公开参数、响应或NestJS provider边界。
- 新增`docs/contracts/send-chain-r9-submission.json``tools/quality/verify-send-chain-r9.mjs`。门禁锁定45个方法体哈希、五个领域归属、双层门面委托和Worker/事务/回调/Redis Stream副作用;确认Gateway结果、回执、补发、退款及下游投递仍留在R10边界。R0~R9全部结构门禁通过。
- 第一次定向测试为97/112通过,15项失败均源于新域内部直接互调,导致既有测试替换稳定门面的`enqueueBatchTask`、调度、队列和限速方法时无法观察内部调用;改为跨方法调用统一返回稳定门面后,2 suites / 112 tests全部通过。该问题在本地门禁阶段发现,没有进入提交或部署。
- Node.js v24.14.0下API全量29 suites / 389 tests全部通过;Prisma format/validate/generate、API TypeScript正式构建、前端TypeScript和Vite v8.0.16生产构建、Gateway`go test ./... -count=1``go vet ./...`、依赖安全门禁和`git diff --check`全部通过。Jest仅保留既有`--forceExit`提示,Vite仅保留既有约2.00MB单chunk提示。
- 真实本地后端只读核验使用实际`SendChainService`、Prisma/PostgreSQL和现有任务:拆分后的任务查询成功;号码导入预检通过真实企业/全局黑名单查询,3行数据返回1条有效、2条错误。调用前后批量任务1条、短信56条、频控状态0条、账户流水3条完全不变。API health HTTP 200PostgreSQL/Redis端口监听,Redis返回PONG。
- R9没有调用创建任务、确认导入、HTTP/CMPP真实提交、审核动作、定时调度、Worker或Gateway发布,没有发送短信、触发补发/重投,也没有修改schema、migration、队列消息、通道、余额或客户连接。号码频控/白名单、客户端体验、R0~R8及其他工作区修改继续完整保留,不归因于R9。
- 本轮按用户要求仅保留本地修改,不提交、不推送、不部署;R10再处理Gateway结果、分片回执、最终聚合、补发、退款和下游投递。
## 2026-07-31 R10 发送完成链编排拆分(本地未提交)
- 按路线图完成R10八项边界。`api/src/send-chain/send-chain.service.ts`从R9的2983行缩减为878行,98个稳定方法继续供控制器、Open API、Gateway事件和其他模块调用;`send-completion.service.ts`为323行内部兼容门面。
- 41个方法按Gateway提交结果与分片提交审计、上游回执收件箱/分片回执/最终聚合、失败补发、扣费退款与预占释放、下游最终状态、CMPP/HTTP最终回执投递、回执超时扫描七个领域迁移,领域文件分别为390、593、359、142、510、489和104行。
- 迁移方法体保持原实现;内部跨领域调用返回`SendChainService`稳定门面,再经完成链兼容门面分派,保留R9提交域依赖方向、既有测试替换点和调用可观察性。日志上下文继续使用`SendChainService`NestJS模块仍只注册稳定门面。
- 新增`docs/contracts/send-chain-r10-completion.json``tools/quality/verify-send-chain-r10.mjs`。门禁锁定41个方法体哈希、七个领域归属、双层门面委托和98个稳定方法,并检查来源提交唯一补发关系、P2002唯一冲突、当前尝试判定、分片聚合、账务幂等键、最终回执键、下游去重/ACK/人工重排键及历史记录不删除。为适配R10物理归属,R8门禁改为在全部`send-*.service.ts`实现中检查既有副作用不变量。
- 第一次API TypeScript构建发现完成链门面包装方法可见性及迁移领域的少量显式导入缺失;补齐公开委托和`UplinkMatchCandidateInput`、超时/规范化辅助导入后正式构建通过。问题在本地编译门禁发现,没有进入提交或部署。
- SendChain定向2 suites / 112 tests、API全量29 suites / 389 tests全部通过;Prisma format/validate/generate、API TypeScript正式构建、前端TypeScript和Vite v8.0.16生产构建、Gateway`go test ./... -count=1``go vet ./...`、依赖安全门禁、R0~R10全部结构门禁及`git diff --check`通过。Jest仅保留既有`--forceExit`提示,Vite仅保留既有约2.00MB单chunk与插件耗时提示。
- 真实本地运行态只读核验:API `/api/health`返回正常,3000、5432、6379端口监听,Redis返回PONG。真实PostgreSQL查询前后均为提交记录61、分片审计0、回执53、下游投递2、下游attempt 0、上游回执收件箱0、Gateway提交死信0、账户流水3,最新提交、回执和下游投递路径均可读,前后计数完全一致。当前没有真实分片审计和下游attempt样本,因此对应数据态验证记为不适用,不造数冒充通过。
- R10没有调用模块初始化、Gateway结果写入、回执入箱、补发抢占、扣费、退款、预占释放、最终回执创建、下游认领、ACK、人工重排或超时扫描,没有发送短信、重试、补发或重投,也没有修改数据库schema、migration、Redis Stream、CMPP协议、通道、余额或客户连接。号码频控/白名单、客户端体验、R0~R9和其他工作区修改继续完整保留,不归因于R10。
- 本轮按用户要求仅保留本地修改,不提交、不推送、不部署。
## 2026-07-31 R11 通道管理页面与专属样式拆分(本地未提交)
- 按路线图“每次只迁移一个页面域”执行R11第一页面域,选择剩余最大页面`AdminChannelsPage.tsx`,从782行缩减为197行稳定协调层。类型、纯映射、表格、编辑弹窗、测试短信弹窗和连接日志弹窗拆入`src/apps/admin/channels/`,各TypeScript文件为51153行。
- 页面继续直接调用真实`adminApi`:列表分页、发送质量、连接状态、创建/编辑、启停、复制、连接日志和测试短信接口均保留;没有引入barrel、mock、静态数据或localStorage。React组件不在页面函数内部定义,查询和写操作仍由页面统一协调。
- 将通道列表、质量指标、编辑表单、测试结果和连接日志的467行专属样式迁入`AdminChannelsPage.css``global.css`从12270行缩减为11800行;共享给通道组的`.channel-confirm`保留全局,375px下连接摘要规则随页面迁移。`main.tsx`的tokens/global/components加载顺序未变。
- 新增`docs/contracts/admin-channels-r11.json``tools/quality/verify-admin-channels-r11.mjs`,门禁确认198行稳定入口、五个聚焦模块、全部真实API调用、八个交互入口和页面样式归属。第一次门禁用`.sms-channel-`宽前缀误匹配仍属通道组的`.sms-channel-group-*`,改为逐项页面选择器后通过;不是产品故障。
- 前端TypeScript检查通过。本地应用内浏览器使用真实运营账号登录,真实API返回5条通道;按`Smoke`查询得到1条,重置恢复5条。编辑弹窗正常回填业务信息、单价、地区和CMPP参数,点击取消未保存;连接日志弹窗正常加载真实连接状态/日志并提供关键词筛选。
- 默认桌面和375×812视口页面均非空、无框架错误覆盖,控制台无warning/error。桌面列表、筛选、质量指标和操作按钮布局正常;窄屏保持既有横向表格浏览方式。浏览器运行时截图通过Tab截图接口获取,未写入仓库。
- 前端TypeScript和Vite v8.0.16生产构建通过,2468个模块完成转换;API全量29 suites / 389 tests全部通过;Prisma format/validate/generate、API TypeScript正式构建、Gateway`go test ./... -count=1``go vet ./...`、依赖安全门禁、R0~R11全部结构门禁及`git diff --check`通过。Vite仅保留既有约2.00MB单chunk提示,Jest使用项目既有的`--forceExit`验收口径并保留开放句柄提示。
- 第一次并行Gateway全量测试中`TestInboundServerAuthenticatesAndSubmits`因模拟API服务提前关闭而失败;该用例单独重跑通过,随后Gateway全量及vet通过,未修改Gateway代码。两次直接执行未带`--forceExit`的API全量命令在测试完成后留下Jest进程并达到超时,确认并只终止本轮创建的两个全量Jest进程后,按既有`--forceExit`口径重跑,389项在21.381秒全部通过;未终止其他会话长期存在的定向Jest进程。
- 验证没有点击编辑确认、添加确认、复制确认、启停确认、删除确认或测试短信最终发送,没有修改通道账号、密码、启停状态、连接或任何业务数据;没有发送短信。
- 本轮按用户要求仅保留本地修改,不提交、不推送、不部署。其他剩余大页面及专属样式必须继续按独立小版本迁移,不在本次R11中批量处理。
## 2026-07-31 R11 短信任务进度页面与专属样式拆分(本地未提交)
- 按路线图“每次只迁移一个页面域”执行R11第二页面域。`AdminSmsTaskProgressPage.tsx`从657行缩减为163行稳定协调层,只保留真实任务查询、企业/应用筛选项加载、选中状态和终止操作;纯任务映射、筛选区、主表、详情弹窗、真实号码分页弹窗和终止确认拆入`src/apps/admin/sms-task-progress/`,各TypeScript文件为28170行。
- 页面继续直接使用真实`adminApi`:任务分页、企业与应用选项、批次号码分页和终止接口均保留;任务状态归一化、提交/成功/失败计数、计费条数、运营商/省份聚合、进度和成功率公式保持原实现。未引入barrel、mock、静态数据或localStorage,也未把组件定义嵌回页面函数。
- 将详情标题、指标、任务详情、运营商卡片和移动端详情布局共273行页面专属样式迁入`AdminSmsTaskProgressPage.css``global.css`从11800行缩减为11527行。报备、下游记录等页面仍使用的`.admin-task-filter``.admin-task-table-card``.admin-task-id``.admin-task-enterprise``.admin-task-card``.batch-progress`保留全局。
- 新增`docs/contracts/admin-sms-task-progress-r11.json``tools/quality/verify-admin-sms-task-progress-r11.mjs`,门禁确认164行文本入口、六个聚焦模块、全部真实API边界、十一项交互文案、专属/共享样式归属和375px详情布局。入口物理行数为163,门禁按末尾换行计为164,均低于220行上限。
- 本地应用内浏览器使用已存在的真实运营账号会话,解锁后真实API返回1条客户批量任务`BT-1783075838138-a886dd56`。不存在批次号查询返回真实空列表,重置再查询恢复1条;详情展示2个号码、2条计费、中国移动2个和未识别省份2个;号码列表真实返回`13800138000``13900139000`,按`138`查询后返回1条。
- 默认桌面详情弹窗和375×812窄屏列表均非空、无框架错误覆盖,控制台0条warning/error;手机端筛选区、查询/重置按钮和任务卡片正常显示。终止确认弹窗的风险提示正常,验收只点击取消,没有调用确认终止。
- Node.js v24.14.0下前端TypeScript和Vite v8.0.16生产构建通过,2475个模块完成转换;API全量29 suites / 389 tests全部通过;Prisma format/validate/generate、API TypeScript正式构建、Gateway`go test ./... -count=1``go vet ./...`、依赖安全门禁、R0~R11全部结构门禁及`git diff --check`通过。Vite仅保留既有约2.00MB单chunk提示,Jest使用既有`--forceExit`口径并保留开放句柄提示。
- 首次前端构建由系统旧Node.js v14.17.4执行,Vite因不支持`??=`语法产生未处理Promise警告但错误返回0;未将其计为通过,切换到Node.js v24.14.0后重新构建并看到实际产物。第一次并行回归中的系统npm 6不支持`npm exec`,Prisma子任务未启动;随后改用项目本地Prisma可执行文件完整补跑并通过,属于工具链编排问题,不是产品代码失败。
- 本轮没有发送短信、创建或终止任务、触发补发/重投,也没有修改数据库、Redis Stream、Gateway、通道、余额或客户连接。R0~R11第一页面域、号码频控/白名单、运营看板和其他工作区修改继续完整保留,不归因于本步骤。
- 按用户要求继续仅保留本地修改,不提交、不推送、不部署。R11当前完成2个页面域;其余页面和共享CSS域继续按独立小步骤推进。
## 2026-07-31 R11 短信记录页面与专属样式拆分(本地未提交)
- 按路线图“每次只迁移一个页面域”执行R11第三页面域。`AdminSmsRecordsPage.tsx`从640行缩减为195行稳定协调层,仅保留真实记录分页、企业/应用筛选项、分片审计、后端CSV导出和选中详情状态;时间/状态/运营商/路由映射、筛选区、记录卡片与分页、发送详情弹窗拆入`src/apps/admin/sms-records/`,各TypeScript文件为33219行。
- 五个真实`adminApi`调用保持:`listOperationMessages``listTenants``listEnterpriseApplicationOptions``listMessageSegmentAudits``exportOperationMessages`。默认昨日到今日、提交失败覆盖、平台失败回执说明、运营端测试说明、通道尝试排序、发送接入号拼接和分片审计排序均保持原实现;没有引入barrel、mock、静态列表或localStorage。
- 将短信记录筛选、卡片、状态、详情、通道路由、分片审计和900px/780px响应式规则迁入433行`AdminSmsRecordsPage.css``global.css`从11527行缩减为11098行。多个运营页面共享的`.template-modal-title``.muted``.ui-table__empty`保留全局。
- 新增`docs/contracts/admin-sms-records-r11.json``tools/quality/verify-admin-sms-records-r11.mjs`,门禁确认196行文本入口、四个聚焦模块、五个真实API边界、十五项交互文案、专属/共享样式归属和两级响应式规则。入口物理行数为195,门禁按末尾换行计196,低于220行上限。
- 本地应用内浏览器访问真实运营端和本地API:默认2026-07-30至2026-07-31返回0条,清空日期后真实返回56条、3页。按手机号`13900000054`查询收窄为1条;运营商下拉保留全部、移动、联通、电信、未识别五项;翻到第2页后仍显示真实总数56和3页分页。
- 真实详情`LOCAL-SIGSTAT-20260728-054`展示发送成功、accepted、delivered、上海/中国联通、发送接入号10690000、两次通道尝试和对应UNDELIV/DELIVRD回执;真实分片接口返回0条,页面明确显示“暂无分片审计”,未造数冒充覆盖。现有56条为本地数据库已存在的统计演示数据,本步骤没有执行演示数据脚本或写入任何记录。
- 默认桌面列表/详情和375×812记录卡片均非空、无框架错误覆盖,控制台0条warning/error;窄屏企业应用、状态、时间、内容、号码、计费、通道和详情入口未重叠。浏览器运行时截图未写入仓库。
- Node.js v24.14.0下前端TypeScript和Vite v8.0.16生产构建通过,2480个模块完成转换;API全量29 suites / 389 tests全部通过;Prisma format/validate/generate、API TypeScript正式构建、依赖安全门禁和R0~R11全部结构门禁通过。Vite仅保留既有约2.00MB单chunk提示,Jest使用既有`--forceExit`口径并保留开放句柄提示。
- 第一次并行Gateway全量测试中`TestSubmitResponsePrecedesQueuedFailureReceipt`因等待模拟失败回执超时而失败,日志同时显示模拟API连接被提前关闭。本步骤未修改Gateway;该用例定向重跑通过,随后Gateway`go test ./... -count=1``go vet ./...`全量通过,按既有时序型测试波动记录而不掩盖。
- 验收没有点击导出下载、发送、补发、重投或任何写操作,没有修改数据库、Redis Stream、Gateway、通道、余额或客户连接。R0~R11前两个页面域及其他工作区修改继续完整保留,不归因于本步骤。
- 按用户要求继续仅保留本地修改,不提交、不推送、不部署。R11当前完成3个页面域;其余页面和共享CSS域继续按独立小步骤推进。
## 2026-07-31 R11 企业应用管理页面与专属样式拆分(本地未提交)
- 按路线图“每次只迁移一个页面域”执行R11第四页面域。`AdminEnterpriseApplicationsPage.tsx`从616行缩减为273行稳定协调层,仅保留真实应用分页、企业选项、查询草稿/已应用条件、生命周期操作、参数详情和弹窗选中状态;筛选区、主表、生命周期弹窗、CMPP/HTTP参数弹窗、连接详情及纯映射拆入`src/apps/admin/enterprise-applications/`,各TypeScript文件为50164行。
- 六类真实`adminApi`调用继续由页面协调:应用分页、企业列表、状态变更、停用影响预检、CMPP参数和HTTP参数。分页、查询后回第一页、重置、停用等待/强制模式、启用、删除、CMPP/HTTP能力禁用规则和参数加载时序保持原实现;没有引入barrel、mock、静态数据或localStorage。
- 将企业应用筛选、连接状态、操作区、连接详情、参数详情、新增应用提示和响应式规则迁入222行`AdminEnterpriseApplicationsPage.css``global.css`从11098行缩减为10881行。共享筛选、确认文案、弹窗标题、堆叠和表单布局继续保留全局。
- 窄屏视觉初检发现页面CSS后加载可能覆盖原全局780px筛选单列规则;在页面CSS显式恢复该规则并加入结构门禁。修正后375×812视口实测页面宽度375px、文档滚动宽度375px,筛选区单列、两个输入均未造成页面级横向溢出。这是拆分阶段发现并修复的样式加载顺序风险,未进入提交或部署。
- 新增`docs/contracts/admin-enterprise-applications-r11.json``tools/quality/verify-admin-enterprise-applications-r11.mjs`,门禁确认274行文本入口、六个聚焦模块、六类真实API边界、十六项交互文案、专属/共享样式归属、查询状态分层以及780px、900px、520px响应式规则。R0~R11全部结构门禁和依赖安全门禁通过。
- 本地应用内浏览器使用既有真实运营账号会话,真实应用分页返回2条。不存在企业名称查询显示真实空状态,重置恢复2条;新增应用弹窗由真实企业接口加载并保持未选择时“下一步”禁用,随后取消。
- 对真实`Smoke SMS App`只读打开连接详情,显示当前连接0、配置连接1、离线及无已连接会话;CMPP参数通过真实详情接口成功打开后直接关闭,未读取、复制或记录敏感参数。停用影响预检返回2项未清算义务,弹窗展示等待/强制停用边界,验收只点击取消,没有调用状态变更。
- 默认桌面与375×812窄屏页面均非空、无框架错误覆盖;桌面筛选、页签、真实表格和横向滚动正常,窄屏筛选单列及记录卡片正常。控制台0条warning/error,桌面和窄屏截图写入系统临时目录,未写入仓库。
- Node.js v24环境下前端TypeScript和Vite v8.0.16生产构建通过,2487个模块完成转换;API全量29 suites / 389 tests全部通过;Prisma format/validate/generate、API TypeScript正式构建、Gateway`go test ./... -count=1``go vet ./...`、依赖安全门禁、R0~R11全部结构门禁和`git diff --check`通过。Vite仅保留既有约2.00MB单chunk提示,Jest使用既有`--forceExit`口径并保留开放句柄提示。
- 本轮没有创建、编辑、启停或删除企业应用,没有复制接口参数、发送短信、触发补发/重投,也没有修改数据库业务数据、Redis Stream、Gateway、通道、余额或客户连接。R0~R11前三个页面域、号码频控/白名单和其他工作区修改继续完整保留,不归因于本步骤。
- 按用户要求继续仅保留本地修改,不提交、不推送、不部署。R11当前完成4个页面域;剩余5个页面/共享CSS域步骤继续按独立小版本推进。
## 2026-07-31 R11 tokens与reset基础样式域拆分(本地未提交)
- 按既定9步计划执行R11第5步,范围严格限定为“tokens和reset”。现有97行`tokens.css`继续作为唯一设计令牌入口,76个颜色、排版、间距、形状、阴影、布局和组件基础变量未改名、未改值;新增84行`reset.css`,从`global.css`迁出13组通配符、文档、链接、表单控件、禁用态、焦点和标题基础规则。
- `main.tsx`将基础样式依赖顺序固定为`tokens.css → reset.css → global.css → components.css → AppRoutes``global.css`从10881行缩减为10801行;AppShell、通用组件、admin/client共享域、响应式页面规则及单页面样式均未在本步骤迁移,避免一次改变多个级联边界。
- 第一次生产产物位置检查发现,仅在`AppRoutes`之后书写四个CSS导入不足以约束打包依赖图,组件CSS会先于reset/global进入产物。将`AppRoutes`导入移到四层CSS之后并重建,最终产物关键位置为tokens 76、reset 1969、global 3030、components 33841、页面样式219684,确认实际拼接顺序与目标一致。该风险在本地门禁阶段发现并修复,没有进入提交或部署。
- 新增`docs/contracts/foundation-styles-r11.json``tools/quality/verify-foundation-styles-r11.mjs`。门禁锁定76个令牌、13组reset/base规则逐规则声明哈希、reset选择器白名单、原`global.css`所有权清理和四层确定性加载顺序;R0~R11全部结构门禁及依赖安全门禁通过。
- Node.js v24环境下前端TypeScript与Vite v8.0.16生产构建通过,2488个模块完成转换,产物CSS约237.03kB、gzip约34.91kB;只保留既有约2.00MB单chunk及一次插件耗时提示,没有新增CSS错误。
- 本地应用内浏览器在最终依赖顺序调整后重新完整验收。使用真实运营会话打开企业应用管理页,真实API继续返回2条应用。页面URL和标题正确,非空且无框架错误覆盖;背景、14px基础字号、21px行高、字体族、链接无下划线、按钮/禁用态光标和输入继承字体的计算样式均符合原令牌。
- 键盘聚焦输入控件时继续得到`rgba(37, 99, 235, 0.18) 0 0 0 3px`焦点环,浏览器默认outline保持关闭。新增应用弹窗正常打开,“下一步”在未选择企业时保持禁用,随后只点击取消,没有创建或修改应用。
- 客户端登录页在未提交表单的情况下完成只读验收:Logo、标题、说明、账号、密码、图形验证码和登录按钮正常,未刷新验证码、未登录。运营端和客户端在默认桌面及375×812视口均无页面级横向溢出,控制台均为0条warning/error;四张截图写入系统临时目录,未写入仓库。
- API全量29 suites / 389 tests全部通过;Prisma format/validate/generate、API TypeScript正式构建、Gateway`go test ./... -count=1``go vet ./...`、依赖安全门禁、R0~R11全部结构门禁和`git diff --check`通过。Jest使用既有`--forceExit`口径并保留开放句柄提示。
- 本步骤没有修改React业务组件、API、数据库schema或migration,没有登录客户端、创建/编辑/启停/删除应用、发送短信、触发补发/重投,也没有修改Redis Stream、Gateway、通道、余额或客户连接。R0~R11前四步及其他工作区修改继续完整保留,不归因于本步骤。
- 按用户要求继续仅保留本地修改,不提交、不推送、不部署。R11当前完成5/9;下一步为AppShell与通用布局基础域,剩余4步继续独立推进。
## 2026-07-31 R11 AppShell与通用布局基础域拆分(本地未提交)
- 按既定9步计划执行R11第6步,范围严格限定为`AppShell`和通用页面布局。新增811行`src/styles/shell.css`,从`global.css`迁出侧栏、折叠导航、顶栏、通知/用户菜单、移动端抽屉/遮罩、减少动画规则,以及`.page-content``.page-stack``.page-heading``.page-heading__actions``.page-actions``.surface``.section-stack``.section-heading`九组布局原语;`global.css`从10801行缩减为10001行。
- `.icon-button`仍被企业应用表单和用户页面复用,继续保留`global.css``.ui-tabs__tab`及通用表格、表单、弹窗样式也未提前迁移。混合的`.page-actions, .table-actions`规则按选择器拆开但声明保持一致,没有修改React业务组件、选择器权重、业务文案、API或交互逻辑。
- `main.tsx`加载顺序更新为`tokens.css → reset.css → shell.css → global.css → components.css → AppRoutes`。Node.js v24.14.0下Vite v8.1.5生产构建通过,2530个模块完成转换,产物CSS 237.11kB、gzip 34.75kBtokens、reset、shell、global和components代表标记依次位于76、1971、3030、15675和36609,只保留既有约2.00MB单chunk及插件耗时提示。
- 新增`docs/contracts/app-shell-styles-r11.json``tools/quality/verify-app-shell-styles-r11.mjs`,门禁锁定118组规则、44个当前/兼容壳层类、九组共享布局选择器、桌面折叠、781px边界、780px移动抽屉和减少动画规则。基础样式契约同步加入`shell.css`加载层;企业应用契约同步确认`.section-stack`改由`shell.css`托管。全部15个R0~R11结构/行为门禁和依赖安全门禁通过。
- Prisma format、validate、generate和API TypeScript正式构建通过;API全量29 suites / 389 tests全部通过。默认Jest命令在断言结束后因既有开放句柄未退出,本次终止的仅为本轮15:44创建的npm/Jest进程,未触碰2026-07-30遗留的其他会话进程;随后按既有`--forceExit`口径获得全量通过并保留开放句柄提示。Gateway`go test ./... -count=1``go vet ./...`通过。
- 本地前端`http://127.0.0.1:4173/`和API`/api/health`均HTTP 200。应用内浏览器访问企业应用页时恢复运营会话返回`Internal server error`并跳转登录页,Chrome也没有已登录运营端标签;遵守验证码边界,没有填写或提交登录表单、读取/伪造浏览器存储。因此桌面展开/折叠、通知/用户菜单和375×812移动抽屉的真实点击验收本轮受阻,需在可用登录态下补测,不能写成已通过。
- 本步骤没有创建、编辑、启停或删除业务数据,没有发送短信、触发补发/重投,也没有修改数据库业务数据、Redis Stream、Gateway、通道、余额或客户连接。R0~R11前五步、号码频控/白名单和其他工作区修改继续完整保留,不归因于本步骤。
- 按用户要求继续仅保留本地修改,不提交、不推送、不部署。R11第6步代码与文档完成,当前实施进度6/9;下一步为通用表格、表单和弹窗域,真实AppShell点击验收仍列为待补风险。
## 2026-07-31 运营端恢复会话500诊断与R11通用组件样式域拆分(本地未提交)
- 恢复运营会话500已按真实基础设施链路定位。无cookie直接访问API与Vite代理的`/api/admin/auth/session`均正常返回401,验证码接口返回200;Redis返回PONG且存在有效运营会话,但当时本地PostgreSQL 5432未监听。有效会话通过Redis校验后执行`prisma.user.findUnique`,真实Prisma请求以`ECONNREFUSED`失败,Nest因而返回500`/api/health`仍为200是因为当前health未执行数据库查询。根因是本地PostgreSQL停止/崩溃而API、Redis仍运行,不是前端恢复会话或R11拆分逻辑缺陷。
- `logs/postgres.log`记录此前进程以Windows异常`0xC0000142`终止,随后完成自动恢复。使用`tools/start-local.ps1 -SkipMigrate -SkipApi -SkipWeb`仅恢复本地PostgreSQL、Redis和MinIO,没有执行migration,也没有重启API或前端;启动脚本遗留的等待进程已精确停止,基础服务继续运行。恢复后5432、6379、9000、9001、3000、4173均监听,真实Prisma查询返回`codex_local_admin`及其active/sessionVersion/角色数据,API health返回200,无cookie会话接口返回401。
- 按既定9步计划执行R11第7步,范围严格限定为“通用表格、表单和弹窗”。从`global.css`迁出52组规则、57个选择器,包括通用`.ui-table*``.ui-modal*``.form-grid*``.radio-row``.table-actions`、表格文本辅助类、`.icon-button``.ui-tabs__tab`、XL弹窗及780px移动端规则;`global.css`从10001行缩减为9660行,`components.css`从1333行增加为1694行。页面域复合选择器继续留在原层,没有修改React业务组件、API、文案、数据口径或写操作。
- 为保持原级联结果,迁入的旧兼容规则位于现有规范组件规则之前,响应式规则位于对应桌面规则之后;`main.tsx``tokens → reset → shell → global → components → AppRoutes`顺序不变。新增`docs/contracts/shared-components-r11.json``tools/quality/verify-shared-components-r11.mjs`,锁定259组规则、291个选择器、14组通用类族、桌面/780px所有权和五类真实UI组件绑定;短信记录及企业应用旧契约同步更新为components所有权。全部15个R0R11结构门禁通过。
- Node.js v24.14.0下前端TypeScript和Vite v8.1.5生产构建通过,2530个模块完成转换,CSS 237.11kBgzip 34.70kB)、JS 2003.23kBgzip 596.71kB),仅保留既有大chunk提示。Prisma format/validate/generate、API TypeScript正式构建、29 suites / 389 tests、Gateway`go test ./... -count=1``go vet ./...`、依赖安全门禁均通过;Jest继续使用既有`--forceExit`口径并保留开放句柄提示。
- 应用内浏览器确认数据库恢复后访问企业应用页不再显示`Internal server error`,而是正常跳转运营端登录页并提示“请先登录”,控制台无warning/error;Edge没有已登录运营端标签。遵守验证码边界,没有自动求解验证码、读取浏览器存储、伪造cookie或绕过登录。因此第6步AppShell交互及第7步登录后桌面/375px表格、表单、弹窗点击验收仍待可用登录态补做,不能表述为已通过。
- 本步骤没有创建、编辑、启停或删除业务数据,没有发送短信、触发补发/重投,也没有修改数据库业务数据、Redis Stream、Gateway、通道、余额或客户连接。R0~R11前六步、号码频控/白名单和其他工作区修改继续完整保留,不归因于本步骤。
- 按用户要求继续仅保留本地修改,不提交、不推送、不部署。R11当前完成7/9;下一步为admin共享样式域,client共享域和单页面样式继续独立推进。
## 2026-07-31 R11 admin共享样式域拆分(本地未提交)
- 按既定9步计划执行R11第8步,范围严格限定为运营端跨页面共享样式。以“至少被两个`src/apps/admin`源码文件复用、且`src/apps/client`不依赖”为主要判定,再按同一共享模式补齐变体和响应式规则;没有迁移client域或业务逻辑。
- 新增678行`src/styles/admin.css`,从`global.css`迁出117组规则、141个选择器,覆盖审核筛选、任务/报备记录、安全页、系统管理、质量/利润/对账筛选、跨页面确认与表单提示、下游明细和通道字段配置等运营端共享模式;`global.css`从9660行缩减为9056行。
- `.report-task-detail .admin-task-card``.gateway-exception-page .report-task-table-card > .ui-pagination`两个带单页面上下文的覆盖规则继续留在`global.css`,没有因类名命中而误迁。`ui-*`只作为admin所有者的后代上下文,客户端源码不引用admin所有权类。
- `main.tsx`加载顺序更新为`tokens → reset → shell → global → admin → components → AppRoutes`。前端TypeScript和Vite v8.1.5生产构建通过,2531个模块完成转换,CSS 237.70kBgzip 34.79kB)、JS 2003.23kBgzip 596.71kB),仅保留既有大chunk提示。
- 新增`docs/contracts/admin-shared-styles-r11.json``tools/quality/verify-admin-shared-styles-r11.mjs`,门禁锁定117组规则、141个选择器、11项跨页面使用下限、admin/client所有权、纯共享规则不得残留global以及780px/360px响应式边界;通道、企业应用、短信任务进度和foundation旧契约同步到新的样式归属与加载顺序。
- Prisma format/validate/generate、API TypeScript正式构建、29 suites / 389 tests、Gateway`go test ./... -count=1``go vet ./...`、依赖安全门禁、全部17个R0~R11结构门禁和`git diff --check`通过。Jest继续使用既有`--forceExit`口径并保留开放句柄提示。
- 应用内浏览器访问真实本地运营端短信审核路由时,因无可复用运营端登录态正常跳转登录页;未求解验证码或伪造会话。运行时生产CSS已包含`.admin-task-filter``.admin-report-filter-grid`规则,页面宽度与1280px视口一致,控制台0条warning/error。登录后的审核、任务、安全、系统及统计代表页面与375px交互验收仍待有效登录态补做,不能表述为已通过。
- 本步骤没有修改React业务组件、API、数据库schema或migration,没有创建、编辑、启停、删除、导入或导出业务数据,没有发送短信、触发补发/重投,也没有修改Redis Stream、Gateway、通道、余额或客户连接。R0~R11前七步、号码频控/白名单和其他工作区修改继续完整保留,不归因于本步骤。
- 按用户要求继续仅保留本地修改,不提交、不推送、不部署。R11当前完成8/9;下一步为client共享样式域,单页面覆盖规则继续保留原所有权。
## 2026-07-31 R11 client共享样式域拆分(本地未提交)
- 按既定9步计划执行R11第9步,范围严格限定为client跨页面共享样式。静态引用盘点覆盖`global.css`和全部admin/client TypeScript源码;真正满足“至少两个client文件使用且admin完全不依赖”的全局类只有`.eyebrow`,由`ClientHome.tsx``ClientBillingPage.tsx`使用。
- 新增8行`src/styles/client.css`并迁移`.eyebrow`一组规则,`global.css`从9056行缩减为9049行。客户端首页专属的`.overview-hero .eyebrow`覆盖继续留在global,没有把单页面上下文误判为共享。
- `.sms-send-title``.system-page-toolbar``.system-table-card`虽然分别被9、3、2个客户端文件使用,但运营端系统日志页也真实依赖,因此继续作为跨门户兼容样式留在global。签名、发送、企业认证、发送详情和模板等代表性单页面样式也继续保留原所有权,没有为扩大改动而批量迁移。
- `main.tsx`最终加载顺序为`tokens → reset → shell → global → admin → client → components → AppRoutes`。新增`docs/contracts/client-shared-styles-r11.json``tools/quality/verify-client-shared-styles-r11.mjs`,锁定唯一client所有权规则、两页面使用下限、三组跨门户兼容边界和五类单页面保留边界;foundation契约同步加入client层。
- Node.js v24.14.0下前端TypeScript和Vite v8.1.5生产构建通过,2532个模块完成转换,CSS 237.70kBgzip 34.79kB)、JS 2003.23kBgzip 596.71kB),与第8步产物体积一致,仅保留既有大chunk提示。全部18个R0~R11结构门禁通过。
- Prisma format/validate/generate、API TypeScript正式构建、29 suites / 389 tests、Gateway`go test ./... -count=1``go vet ./...`、依赖安全门禁和`git diff --check`全部通过。Jest继续使用既有`--forceExit`口径并保留开放句柄提示。
- 应用内浏览器访问真实本地客户端首页路由时,因无可复用客户端登录态正常跳转登录页;未求解验证码或伪造会话。运行时生产CSS确认纯`.eyebrow``.overview-hero .eyebrow`页面覆盖及`.sms-send-title`跨门户规则均存在,默认1280px和375×812视口均无页面级横向溢出,控制台0条warning/error。登录后的首页、账单和代表单页面验收仍待有效登录态补做,不能表述为已通过。
- 本步骤没有修改React业务组件、API、数据库schema或migration,没有创建、编辑、删除或导出业务数据,没有发送短信、触发补发/重投,也没有修改Redis Stream、Gateway、通道、余额或客户连接。R0~R11前八步、号码频控/白名单和其他工作区修改继续完整保留,不归因于本步骤。
- 按用户要求继续仅保留本地修改,不提交、不推送、不部署。R11既定九步当前完成9/9;这表示本轮计划范围完成,不代表剩余单页面CSS已被一次性清空,后续应另立小版本继续。
## 2026-07-31 工作区业务功能与R0-R11汇总提交门禁
- 用户已明确授权提交并推送当前工作区全部有效代码,但不部署。提交范围包括号码频次风控和平台级白名单、运营看板与短信记录改进、客户端发送体验、R0-R11渐进式拆分、两条新migration、结构契约、测试脚本、需求/测试/进度文档以及后续`global.css`拆分计划。
- 提交前重新执行`git fetch --prune`,本地分支为`main``HEAD``origin/main`均为`0af671b4ed4713912e703defd08791f164d4eb25`,没有远端分叉。工作区未发现相较前次停止时新增的未知业务修改。
- 使用Node.js v24.14.0执行Prisma format、validate、generate和migrate status;本地PostgreSQL仅恢复服务用于只读状态检查,没有执行migration或写入业务数据。源码目录共78条migration,本地数据库schema up to date。
- API全量测试首次因本地Redis未运行出现1 suite/3项队列等待超时;启动本地Redis并确认`PONG`后,原命令复跑为29 suites / 389 tests全部通过。没有修改或放宽测试来绕过失败,Jest继续使用既有`--forceExit`口径。
- API TypeScript正式构建、前端TypeScript与Vite生产构建通过;前端2532个模块完成转换,CSS 237.70kBgzip 34.79kB)、JS 2003.23kBgzip 596.71kB),仅保留既有大chunk提示。
- 19个Node结构门禁以及R6/R7两个Go结构门禁全部通过;Gateway`go test ./... -count=1``go vet ./...`、依赖缓解安全门禁和Git差异检查通过。
- `api/tsconfig.build.tsbuildinfo`、根目录`tsconfig.tsbuildinfo``outputs/`和空文件`=`继续作为构建缓存或临时产物保留在本地,不纳入提交、不删除、不错误归因。未发送、重投或补发真实短信,未修改真实通道账号、密码、启停状态、企业余额或客户连接,本轮明确不部署。