# 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/<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, 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`.
