Source Layer Analysis
This analysis records runtime boundaries at HEAD 1f10eef0234f37cd81bd5b11b35d8c2c93b4bc99. The server is one Spring Boot process; the repository contains four separately built web-facing frontends and one Tauri desktop shell.
Runtime Modules And State
| Module | Responsibility | Persistent or Runtime State |
|---|---|---|
Spring Boot API (server/) | Hosts REST resources, clinic use cases, integrations, and lifecycle jobs. | MySQL by default or SQLite in demo mode; Caffeine cache and in-process SDK/ticket state; local ads, WeChat materials, and print-template files. |
Admin console (web/) | Ant Design Pro console for clinical, billing, operations, content, and WeChat administration. | JWT, selected theme, and table preferences in browser storage; runtime page state in React memory. |
Mini program (app/) | Taro mini program for booking and verified card lookup. | Booking session, card summary, and OpenID-related state in platform storage or component memory. |
Customer kiosk (kiosk/) | Self-service catalog and order entry. | Catalog/order state only in React memory; persistence is delegated to the API. |
Lobby display (tablet/) | Rotates media and plays call notifications. | Media manifest/catalog and call state in memory; IndexedDB precache for offline playback. |
Desktop shell (desktop/) | Loads the admin URL and exposes scanner/printer bridge commands. | JSON config under the OS app-config directory; active scanner/ESC-POS connection state in memory; temporary print files on disk. |
Docs site (docs/) | Builds the bilingual documentation and consistency checks. | Build-time static assets; no application state. |
Call Surface
- Admin console pages call generated clients under
web/src/services/ant-design-pro, which use Umi request; login stores a JWT in browser storage. - Mini program and both public kiosks call REST with platform/browser
fetch/request; desktop shell does not proxy business requests—the embedded admin page calls the API directly. - Tauri IPC connects only the local webview to scanner, ESC/POS, print, config, and autostart commands.
- The server calls WeChat via RestTemplate/Java HttpClient/WxJava and receives callbacks as HTTP; it reads/writes configured local file roots for media and print templates.
- There is no Redis, queue, or RPC fabric. The process-local cache is Caffeine; durable state is relational plus selected files.
Layers
1. Request orchestration
Spring Security and multipart limits admit or reject traffic; JWT authentication, method security, and static/media routing are configured here. Implementation lives in server/src/main/java/com/sinomed/config; configuration schema is server/src/main/resources/application.yml; the external contract is generated by Springdoc/Knife4j rather than a hand-maintained protocol file.
2. Resource controllers
Thirty controllers translate resource requests into services. API scope is assembled by Springdoc from com.sinomed.controller; no controller-specific protocol file exists. User-facing labels remain in frontend locale or page code, not controller annotations.
3. Application services
Interfaces in server/src/main/java/com/sinomed/service define clinic use cases; service/impl provides transactions and orchestration. Large WxOfficialAccountService also owns callbacks, credential/device state, material files, and outbound calls, so it belongs to this layer while showing a split candidate in todo.md.
4. Persistence
JPA auditing and repositories form the relational boundary. server/init/init.sql is operational bootstrap, while runtime schema mainly comes from JPA ddl-auto=update; test/bootstrap SQL is not a runtime protocol contract.
5. Clinical reference
Herb/formula/acupoint/template dictionaries and safety checks are reference data and rule evaluation. Their schema lives with JPA entities; admin-facing wording lives in web locales/pages.
6. Clinical operations
Customer, appointment, call, treatment, prescription, review, attendance, and order workflows live here. Each controller/service family is the concrete unit; there is no separate workflow DSL or dedicated protocol file.
7. Financial settlement
Card, recharge, order, commission, settlement, reconciliation, and refund flows maintain audit logs and money-state transitions.
8. Channel integration
Kiosk endpoints, mini-program login, official-account callback processing, WxJava provider instances, and credential encryption live here. application.yml is the channel configuration schema; XML callback parsing and token sealing are implementation-owned protocol behavior, not an independent wire-format file.
9. Content and peripherals
Ads catalog/schedules/media serving live server-side; tablet playback consumes the playlist API. Desktop shell local config, print templates, scanner, and ESC/POS are device-bound capabilities; templates are protocol artifacts, while button copy lives in desktop/ui/index.html.
10. Interaction runtimes
The web, app, kiosk, tablet, and desktop UI targets are independent deployables. Their routes, platform storage keys, local themes, and display copy define their schemas and copy sites. The docs site is a build-time documentation runtime with its own link/theme checks.
11. Platform lifecycle
Demo seeding, startup migrations, docs validation, and Compose/CI packaging initialize or package runtime modules. Configuration comes from Compose/environment and VitePress; lifecycle jobs run once at application startup, while CI runs per push/release.
Split Rationale
- Separate request orchestration from controllers because authentication/method security is a distinct admission concern, while controllers are 30 resource-specific translators.
- Keep services as the transaction/application boundary because
SettlementServiceImplcombines several repositories into transactional money workflows, andWxOfficialAccountServicecoordinates callbacks, accounts, files, and outbound APIs. - Split clinical reference from clinical operations because dictionaries/rules are reusable safety inputs for prescriptions, while operations track individual visits and workflow state.
- Separate financial settlement because recharge, deduction, commission, settlement, and reconciliation share transactional money-ledger invariants distinct from clinical flow.
- Treat channel integration separately because kiosk/mini-program/official-account traffic has channel-specific credentials, verification, lookup limits, and callback protocol behavior.
- Split content/peripherals from interaction runtimes because ad playlists and device capabilities have server/file/IPC boundaries different from frontend state and rendering.
- Keep interaction runtimes apart because each target has a distinct package/build system, channel, and device constraints even when sharing the REST contract.
- Keep platform lifecycle separate because demo seeding and startup migrations are conditional one-shot jobs, unlike always-on request services.