7.7 KiB
Center 摘要内部网络入口设计
设计结论
摘要历史读取不再是 public history route 的认证分支。一个 Node 进程内运行两个独立 Fastify listener:public app 继续在 7878 服务全部既有能力;internal summary app 固定在 0.0.0.0:7777,只注册 history GET。Docker 的 trade-message-center-summary internal network 及成员资格成为 summary 的唯一权限边界。
Internet / extension / Mind page
|
host publish :7878
|
Center public Fastify app
Cookie + Mind page authorization, WebSocket, normal HTTP
Mind container -- trade-message-center-summary (internal Docker network)
|
http://trade-message-center:7777
|
Center internal summary Fastify app
history GET only; no Cookie/Bearer/header authorization or Mind callback
|
shared OneTalk read service -> Bright PostgreSQL
The two containers must run on the same Docker daemon. The network prevents Docker port publication for 7777; it is not encryption, mTLS, or a defence against another member container, a Docker-socket holder, or host root.
Listener and runtime ownership
- Keep the existing
createAppas the public application factory. Its read routes retain the complete Cookie/Mind reader and must no longer branch to summary authorization whenAuthorization,X-Mind-Purpose, orX-Mind-Workspace-Idappears. - Add a dedicated internal app factory that registers only the existing history route constant and a handler which invokes the canonical
OneTalkReadService.readHistory. It registers neither WebSocket, CORS/origin guards, extension-download routes, list/detail routes, nor generic Mind authorization. - Add a runtime composition boundary that creates one
DatabaseConnection, one read repository/service, and one cutover policy, injects the shared read service into both apps, starts publicconfig.host:config.portand internal0.0.0.0:7777, and owns ordered shutdown. Close the internal app before the public app so the public app's existing database-close hook remains the one close owner. - Failure to bind either listener closes both apps and fails process startup. No port fallback, disabled internal route, or default-to-public behavior is allowed.
- Preserve the current read-service facts: only
channelAccountIdis needed for a history query, opaque cursors remain bound to account/conversation/window/asOf, summary mode still requires both time boundaries and keepshistory_incompleteplusRetry-After: 30.
Internal HTTP contract
Mind calls the same history path on the private port to minimize path migration:
GET http://trade-message-center:7777/api/bright/onetalk/accounts/:channelAccountId/conversations/:conversationId/messages?fromSentAtMs=:inclusiveEpochMs&toSentAtMs=:exclusiveEpochMs&cursor=:opaqueCursor&limit=:1to100
- The internal listener itself selects summary mode. It ignores no authorization claim because it reads none:
Authorization, Cookie,X-Mind-Purpose, andX-Mind-Workspace-Idare not request-contract fields and the Mind document tells callers to omit them. - A successful internal response contains
conversationId, semanticmessages, andpage; it has noscope,workspaceId,mindUserId, binding, authorization version, or authorization diagnostics.channelAccountIdandconversationIdare the request path identity, not a returned authorization claim. - Input/database/history errors keep the existing stable response shape.
auth_required,scope_mismatch,authorization_rejected, andauthorization_unavailableare not internal-summary outcomes. - The public route ignores the former summary headers and only executes the existing Cookie/Mind page authorization path. Therefore an unauthenticated public request cannot reach a summary read through
7878.
ONETALK_SUMMARY_READ_PURPOSE remains only as a server-domain signal between the internal HTTP handler and OneTalkReadService; move it out of the shared summary-authorization contract so it cannot be interpreted as an external header contract.
Removed and preserved boundaries
Remove the summary-specific shared contract and export, credential predicate, summary reader/callback client, TRADE_MESSAGE_CENTER_SUMMARY_READ_TOKEN config/env/release secret flow, workspace/purpose headers, callback diagnostics, response-scope union, and their tests. Update the prior summary-authorization server spec instead of leaving it as active guidance.
Do not remove MIND_AUTH_BASE_URL, its generic reader, Cookie authorization, WebSocket authorization, CORS for the public app, public 7878, or any history/repository/cursor/projection behavior. No migration or Mind database access is introduced.
Docker release contract
- The deploy workflow uses the fixed named network
trade-message-center-summary. Before each start or restore, it verifies that an existing network isInternal=true, or creates it withdocker network create --internal. - Center starts on the named non-internal
trade-message-center-publicbridge network for its published7878endpoint and outbound generic Mind authorization calls. It must not remain on Docker's default bridge, where other default-bridge members could reach every listening port by container IP. Afterdocker run --network trade-message-center-public --publish 7878:7878, the workflow attaches it totrade-message-center-summary; it must not publish7777. - Docker's automatic alias for the existing container name
trade-message-centeris the internal DNS target. The Mind owner attaches its container to the same named network and calls the URL above. - The Dockerfile documents both container ports with
EXPOSE 7878 7777, butEXPOSEis not an exposure control. The existing health check stays on127.0.0.1:$PORT/healthand covers the public app; internal request smoke verification is a deployment check. - Network creation/attachment failure fails release and follows the existing image/env rollback path. The network is not removed on rollback because it is shared with Mind. Rolling back Center after Mind changes back to
7777requires coordinated Mind rollback or its traffic will fail; document this explicitly.
Documentation and external handoff
Create docs/onetalk-summary-internal-api.md as the handoff document for Mind. It will contain the exact URL/path/query, request/response/error rules, network name, docker network connect example, no-port-publication rule, verification commands, shared-daemon precondition, and the deliberate loss of workspace/conversation authorization. Update docs/bright-conversation-list-api.md so its public summary-header section no longer contradicts the internal contract and links to the new document.
Mind code/deployment changes are not part of this task. A live Mind-to-Center container request is external validation, not evidence obtainable from Center unit tests.
Test and rollback boundaries
- Unit and HTTP-injection tests prove the private handler is summary mode without credentials, validates windows, returns no scope, and preserves cursor/history gates. Public regression tests prove Bearer/workspace/purpose inputs do not select an unauthenticated route and that Cookie/WS behavior is unchanged.
- Runtime tests use ephemeral ports through the new runtime composition seam to prove both listener lifecycles and bind failure cleanup without depending on host port
7777. - Static checks prove summary credentials/callback modules and active config/release references are gone; archived task evidence is excluded from this deletion check.
- Docker daemon access is currently unavailable locally, so
docker network inspect,docker port, and container-to-container HTTP are explicitly external deployment verification.