migration: close candidate maintenance audit

This commit is contained in:
leefer
2026-07-31 21:24:37 +08:00
parent faac60b1a6
commit 406118bba6
17 changed files with 844 additions and 120 deletions
+59 -29
View File
@@ -1,40 +1,70 @@
# Architecture
# Candidate architecture
The normative governance contract is documented in
`docs/governance/architecture-standard.md`. This file describes the currently deployed
shape; the standard defines the target boundaries and the rules applied during migration.
`app/` is the behavior-preserving modular candidate. The original `webapp/` runtime remains
the product and visual baseline until manual acceptance. `next/` is a rejected, frozen
implementation and is not a source for this directory.
The application intentionally keeps a small deployment footprint: one Python process, one
SQLite database, and a build-free browser client. The internal boundaries are nevertheless
explicit so new features do not bypass account isolation or data-quality rules.
The application deliberately remains a modular monolith: one Python process, one SQLite WAL
database, and a build-free HTML/CSS/JavaScript client. The migration changed source ownership
and imports, not the technology stack or observable product behavior.
## Backend boundaries
## Runtime path
- `server.py`: application services and HTTP request/response wiring.
- `api_access.py`: the single authorization policy for authenticated, member, and admin APIs.
- `app_config.py`: runtime paths, local environment loading, and shared input validation.
- `database.py`: SQLite schema, migrations, and persistence operations.
- `tushare_client.py` and `realtime_aggregator.py`: external market-data adapters.
- `sentiment_engine.py`, `screener.py`, and `heaven_engine.py`: deterministic domain logic.
- `mentor_agent.py`, `heaven_agent.py`, and `llm_strategy.py`: bounded LLM adapters.
```text
browser
-> frontend/shared/api.js
-> backend HTTP transport and feature HTTP mixins
-> feature services
-> repositories / DataGateway / LLMGateway
-> SQLite / market providers / model providers
## Data ownership
background scheduler
-> backend/jobs
-> the same feature services and repositories
```
Public market snapshots, stock factors, built-in strategies, limit-up reasons, seat aliases,
and sector-element mappings are shared. Only administrators can modify shared knowledge.
## Source ownership
Watchlists, review notes, custom strategies, screener runs, mentor conversations, birth data,
alerts, trading journals, and assistant conversations are owned by a user ID and must be
queried with that ID. LLM features additionally require active membership.
- `server.py` is the stable command/import facade. Runtime composition lives in
`backend/application.py` and `backend/bootstrap/`.
- `backend/http/` owns common authentication, request IDs, responses, static delivery, and
error normalization. Feature-specific transport handlers live beside their feature.
- `backend/features/<feature>/` owns the mechanically moved service, repository, HTTP, agent,
or deterministic calculation code for that product area.
- `backend/data/` owns provider construction, source policy, provenance, units, freshness,
coverage, and display-versus-calculation eligibility.
- `backend/database/` owns connection management, ordered migrations, and narrow repository
adapters. Root `database.py` remains the legacy schema/composition anchor and combines the
feature repository mixins; do not add feature queries to it.
- `backend/jobs/` owns job definitions, locks, retries, idempotency, and persisted run state.
- `backend/llm/` owns model selection, membership/quota checks, fallback, streaming rules,
and call audit. Feature agents only prepare context and provider payloads.
- `frontend/shared/` is the only browser API/state/Shell/component boundary.
- `frontend/pages/` owns page-local behavior. The original runtime was split mechanically;
source markers and preservation tests prove that the pieces reassemble to the audited
original, apart from explicitly registered trial retirements.
- `frontend/styles/`, `frontend/shared/tokens.css`, and the Wentian page stylesheet preserve
the approved cascade and light/dark/mobile behavior.
- `config/` is the versioned registry for pages, features, APIs, datasets, quality rules,
jobs, and the generated candidate architecture inventory.
## Data integrity
Root modules such as `screener.py`, `tushare_client.py`, and `mentor_agent.py` are compatibility
aliases to canonical modules. They contain no second implementation and remain only because
the original public import surface is part of the preservation contract.
Production reads never synthesize market prices. A failed live request may use the latest real
snapshot at or before the requested date. When no real snapshot exists, the API reports that
the data is unavailable. Demo builders remain test fixtures only.
## Non-negotiable maintenance rules
## Change contract
1. Preserve account ownership in every user-private query and test it with two accounts.
2. Browser requests go through `frontend/shared/api.js`; provider calls go through the data
boundary; model calls go through `backend/llm/`.
3. Calculation datasets fail closed when required source, date, unit, freshness, or coverage
evidence is missing. Display fallbacks do not silently enter calculations.
4. Do not implement logic in both a root compatibility module and a canonical module.
5. Do not remove compatibility or uncertain code without reference scanning, old/new
differential evidence, browser checks, and manual acceptance.
6. Run `python tools/verify_baseline.py` for every change and add `--e2e` when runtime or
frontend behavior can be affected.
New endpoints must be added to `api_access.required_role` when they need member or admin
access. New user-owned tables must include `user_id`, an ownership index, and cross-account
tests. API payload compatibility is protected by the Python and Playwright suites.
The authoritative migration constraints and handoff procedure are in
`../docs/migration/原版保真迁移总纲.md` and
`../docs/migration/人工维护与本地切换指南.md`.