# Candidate architecture `app/` is the behavior-preserving modular source tree accepted by the user on 2026-08-01. The original `webapp/` runtime remains the deployment rollback baseline until an explicitly approved switch. `next/` is a rejected, frozen implementation and is not a source for this directory. 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. ## Runtime path ```text browser -> frontend/shared/api.js -> backend HTTP transport and feature HTTP mixins -> feature services -> repositories / DataGateway / LLMGateway -> SQLite / market providers / model providers background scheduler -> backend/jobs -> the same feature services and repositories ``` ## Source ownership - `server.py` is the stable command/import facade. Runtime composition lives in `backend/application.py` and `backend/bootstrap/`. - `backend/bootstrap/` owns process configuration, dependency construction, startup, and shared input/display-format contracts. It does not own feature behavior. - `backend/http/` owns common authentication, request IDs, JSON/NDJSON responses, static delivery, streaming connection lifecycle, and error normalization. Feature-specific transport handlers live beside their feature. Exact POST endpoints that only delegate to one of those handlers use the explicit maps in `backend/application.py`; endpoints with path parameters, body handling, or special error semantics remain visible control flow in `RequestHandler`. - `backend/features//` 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, display-versus-calculation eligibility, and shared numeric normalization policies. - `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, provider transport, streaming rules, and call audit. Feature agents only prepare messages and interpret feature-specific results. - `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. 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. Canonical backend modules must import other canonical modules directly rather than routing through these aliases. The remaining `api_access` import in `backend/application.py` and preserved lazy `sentiment_engine` import in the screener repository are registered transition boundaries; the root `database.py` remains the documented schema/composition anchor. ## Non-negotiable maintenance rules 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. The authoritative migration constraints and handoff procedure are in `../docs/migration/原版保真迁移总纲.md` and `../docs/migration/人工维护与本地切换指南.md`.