refactor: establish standalone application boundary
This commit is contained in:
+131
-32
@@ -1,9 +1,8 @@
|
||||
# Candidate architecture
|
||||
# Application 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.
|
||||
`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
|
||||
@@ -26,57 +25,157 @@ background scheduler
|
||||
|
||||
## Source ownership
|
||||
|
||||
- `server.py` is the stable command/import facade. Runtime composition lives in
|
||||
`backend/application.py` and `backend/bootstrap/`.
|
||||
- `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.
|
||||
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`.
|
||||
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/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.
|
||||
- `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
|
||||
model interpretation belong to `readings.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.
|
||||
|
||||
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.
|
||||
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 requests go through `frontend/shared/api.js`; provider calls go through the data
|
||||
boundary; model calls go through `backend/llm/`.
|
||||
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 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.
|
||||
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.
|
||||
|
||||
The authoritative migration constraints and handoff procedure are in
|
||||
`../docs/migration/原版保真迁移总纲.md` and
|
||||
`../docs/migration/人工维护与本地切换指南.md`.
|
||||
Current maintenance rules are in `AGENTS.md` and
|
||||
`docs/maintenance/人工维护指南.md`. Historical migration constraints and evidence remain under
|
||||
`docs/migration/` for audit only.
|
||||
|
||||
Reference in New Issue
Block a user