# Application architecture

`app/` is the standalone, behavior-preserving modular source tree accepted by the user on
2026-08-01. It is the only production source boundary and must not read or import a parent
checkout, a retired baseline, or a failed implementation.

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. `backend/application.py` is the narrow
  composition root for `DashboardService`, `RequestHandler`, and the process-wide service
  instance; dependency construction remains in `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. `backend/http/dispatch.py` owns only public
  versus authenticated guard order, named POST dispatch, feature-route traversal, static
  fallback, and final 404 responses. Exact POST maps live there; endpoint parsing, response
  fields, and feature-specific exceptions belong to `backend/features/<feature>/routes.py`.
- `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/data/providers/tushare_client.py` is the stable public `TushareClient` facade and
  owns only its dataclass fields and shared cache state. Tushare HTTP transport belongs to
  `tushare_transport.py`; market overview and realtime breadth belong to
  `tushare_dashboard.py`; indices belong to `tushare_indices.py`; Shenwan membership and
  industry snapshots belong to `tushare_industries.py`; generic sector snapshots belong to
  `tushare_sectors.py`; hot-money and dragon-tiger data belong to
  `tushare_dragon_tiger.py`; stock detail and intraday data belong to `tushare_stocks.py`;
  trading-calendar, daily, and limit-list access belong to `tushare_daily.py`; small shared
  deterministic conversions belong to `tushare_helpers.py`.
- `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/jobs/service.py` is the application-facing owner of scheduler start/stop, manual
  refresh submission, and periodic refresh coordination. `backend/jobs/refresh.py` owns
  whether a dashboard payload is a usable refresh result versus a failed job, and whether
  after-hours official catch-up is due.
- `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/index.html` owns only the login layer, application Shell, overview strip, status
  bar, global dialogs, and the single page-fragment mount point. `frontend/bootstrap.js`
  loads the registered page fragments before the unchanged application runtime starts.
- `frontend/pages.config.js` is the only runtime owner of page-fragment paths and script
  execution order. Do not add page scripts directly to `index.html` or create another loader.
- `frontend/app.js` is only the browser startup coordinator: initialize controls, resolve the
  initial route, start the authenticated application, and invoke registered binding owners.
  It must not own feature event handlers, dashboard rendering, account/admin behavior, theme
  behavior, table behavior, or application state definitions.
- `frontend/shared/` is the only browser data-API/state/Shell/component boundary. Within it,
  `context.js` owns application state and DOM handles, `application.js` owns API/Shell/page
  lifecycle composition, `feedback.js` owns common feedback and motion, `dashboard.js` owns
  market-dashboard refresh and date coordination, `session.js` owns authentication/account
  access, `admin.js` owns system administration, `theme.js` owns theme switching, and
  `table.js` owns generic table behavior. The Bootstrap fetch is limited to registered
  same-origin static HTML fragments.
- `frontend/pages/` owns page-local markup, behavior, and styles through `page.html`,
  `page.js`, and `foundation.css`. Each feature registers its own one-time control binder with
  the page runtime; feature selectors and event handlers must not be added to `app.js`. The
  original DOM and runtime were split mechanically during migration. Current maintenance is
  governed by the runtime registry, unique symbol owners, DOM/API contracts, JavaScript syntax
  checks, and Playwright behavior rather than embedded historical source ranges.
- `frontend/pages/market/` owns cross-page market presentation through narrow runtime modules:
  `breadth.js`, `charts.js`, `entity-detail.js`, `stock-detail.js`, `preview.js`, `search.js`,
  and `bindings.js`. `runtime.js` is retired; do not recreate a combined market runtime or a
  compatibility loader. `pages.config.js` is the sole owner of their execution order.
- `backend/features/screener/engine.py` is the stable screener compatibility facade only.
  Screener declarations belong to `catalog.py`; external factor synchronization belongs to
  `data_sync.py`; deterministic technical and statistical helpers belong to `indicators.py`;
  factor construction belongs to `factors.py`; formula validation, scoring, and local strategy
  compilation belong to `formula.py`; market-phase identification belongs to `regime.py`;
  screening execution and result persistence belong to `selection.py`; historical evaluation
  belongs to `backtest.py`.
- `backend/features/heaven/service.py` is the stable Wentian service facade only. Manual
  six-line input validation and safety gates belong to `manual.py`; trend setup, market mode,
  source disclosure, and quality checks belong to `trend.py`; stock, index, and sector context
  collection belongs to `market_context.py`; personal fields, hexagrams, saved readings, and
  interpretation orchestration belong to `readings.py`; deterministic Jing Fang Na Jia, eight
  palaces, six relatives, self/response, six spirits, calendar relations, and hidden spirits
  belong to `six_yao.py`; source-traceable Wentian knowledge retrieval and the only LLM-bound
  context projection belong to `knowledge.py`; prompt construction and answer validation remain
  in `agent.py`. These owners cooperate through the composed service object and do not duplicate
  or delegate method bodies through the facade.
- Application-facing system credentials, data/LLM status, and administrator settings belong
  to `backend/features/system/service.py`; account-context delegation belongs to
  `backend/features/accounts/application.py`. They are composed into `DashboardService` and
  must not return to the composition root.
- `backend/features/market/insights.py` is the stable public `MarketInsightsService` facade
  only. Shared construction, trading context, stock master access, and concept parsing belong
  to `insights_context.py`; auction scoring and candidate construction belong to
  `insights_auction_scoring.py`; auction session, amount history, watchlist enrichment, and
  live snapshots belong to `insights_auction_data.py`; auction result orchestration belongs to
  `insights_auction.py`; theme library/detail behavior belongs to `insights_themes.py`; and hot
  ranking behavior belongs to `insights_popularity.py`.
- `frontend/shared/tokens.css` owns global design semantics. Shared foundations live in
  `frontend/shared/*.css` and `frontend/shared/components/*.css`; page foundations live beside
  their page in `frontend/pages/<feature>/foundation.css`. These 22 files replace the retired
  `frontend/styles/styles.css`, four historical refinement layers, and the former Wentian
  page stylesheet. Production loads only this canonical stack: every selector/context pair has
  one owner, shared roots stay in shared files, and page-scoped rules stay beside their page.
- `config/` is the versioned registry for pages, features, APIs, datasets, quality rules,
  jobs, and the generated candidate architecture inventory.

The source root has four Python entry modules only: `server.py` starts and exports the process
surface, `database.py` remains the documented schema/composition anchor, `api_access.py` owns
the route-access registry entry, and `sync_data.py` is the manual synchronization command.
The 19 migration-only import aliases were retired after all internal and test consumers moved
to canonical `backend/` owners. Do not recreate root-level feature import shims.

Generated local artifacts belong under `runtime/`: server output in `runtime/logs`, Python
cache in `runtime/cache`, and browser artifacts in `runtime/test-results`. Docker continues to
emit logs through its configured logging driver instead of writing into the source tree.

## Non-negotiable maintenance rules

1. Preserve account ownership in every user-private query and test it with two accounts.
2. Browser business-data requests go through `frontend/shared/api.js`; only
   `frontend/bootstrap.js` may fetch registered static page fragments. 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 create root-level feature compatibility modules; import the canonical `backend/`
   owner directly.
5. Do not remove 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.
7. Do not recreate late-loading `legacy.css`, `override.css`, `fix.css`, or page-wide patch
   layers. Change the canonical shared or page owner and keep the CSS ownership tests green.
8. Do not put `workspace-view` roots back into `frontend/index.html`. Add or change page DOM
   only in its registered `frontend/pages/<feature>/page.html`, without introducing a second
   fragment or runtime-script registry.
9. Do not add feature selectors, feature event listeners, shared state declarations, or
   shared service implementations to `frontend/app.js`; extend the existing unique owner and
   keep the startup-entry boundary tests green.
10. Do not merge market charts, previews, search, stock details, entity details, breadth, and
    event binding back into one runtime file. Keep each definition in its registered owner and
    keep the market runtime ownership test green.
11. Do not merge screener catalogs, data synchronization, indicators, factor construction,
    formulas, regime detection, selection, and backtesting back into one engine. Keep
    `backend/features/screener/engine.py` as a compatibility facade and preserve one canonical
    owner for each responsibility.
12. Do not merge Tushare transport, dashboard, indices, Shenwan industries, sectors,
    dragon-tiger data, stock detail, and daily-market access back into one client. Keep
    `backend/data/providers/tushare_client.py` as the single public class facade, and do not
    duplicate provider method bodies in that facade or another compatibility module.
13. Do not merge Wentian manual validation, trend orchestration, market-context collection,
    and reading/LLM behavior back into one service. Keep
    `backend/features/heaven/service.py` as a method-free composition facade and preserve one
    canonical owner for every Wentian service method.
14. Do not merge auction scoring, auction data preparation, auction orchestration, themes,
    popularity, and shared insight context back into one market-insights service. Keep
    `backend/features/market/insights.py` as a method-free public facade and preserve one
    canonical owner for every market-insight method.
15. Do not put feature route bodies, system settings behavior, account delegation, or job
    lifecycle methods back into `backend/application.py`. Keep it as a composition root; keep
    common HTTP guard/404 behavior in `backend/http/dispatch.py`; and keep endpoint-specific
    parsing and responses in the corresponding `backend/features/<feature>/routes.py`.
16. Do not add preservation source-range markers, copied historical CSS fragments, or a tool
    that reconstructs the retired monolithic frontend. Historical maps remain evidence only;
    current owners and behavior tests are the maintenance boundary.

Current maintenance rules are in `AGENTS.md` and
`docs/maintenance/人工维护指南.md`. Historical migration constraints and evidence remain under
`docs/migration/` for audit only.
