7.5 KiB
Guild H5 architecture
Decision
The existing gonghui/ tree is the Lalu legacy product and remains independently deployable. New guild products use a zero-build, static multi-package architecture under guild/:
guild/
├── packages/
│ ├── core/ # Product context, date ranges, errors, state machines
│ ├── ui/ # Product-neutral center layouts and components
│ ├── host-center/ # Host feature package (added with the first host screen)
│ ├── agency-center/ # Agency feature package
│ ├── bd-center/ # BD feature package
│ └── wallet/ # Shared coin-seller and USDT withdrawal flow
├── products/
│ └── fami/ # Fami manifest, assets and visual overrides
└── fami/
├── host-center/ # Thin deployable page entry
├── agency-center/
├── bd-center/
└── wallet/
Each page entry composes packages with ordered classic <script> and <link> tags. There is deliberately no bundling step: the current repository is deployed as static files, so a build-system failure must not take down existing H5 pages.
Package boundaries
| Package | Owns | Must not own |
|---|---|---|
common/ |
Existing cross-H5 API transport, environment selection, i18n and base theme | Guild role semantics or Fami page state |
guild/packages/core |
Product context, shared time range model, request DTO mapping, async state primitives | DOM layout and product colors |
guild/packages/ui |
Responsive cards, filters, tables, empty/loading/error presentation | API paths or role permissions |
guild/packages/<feature> |
One role/flow's state, API adapter and render controller | Fami-only text, assets or hardcoded app code |
guild/products/fami |
app_code=fami, feature flags, Fami assets and permitted visual overrides |
Shared business calculations |
guild/fami/<feature> |
HTML composition and page-only wiring | Reusable business logic |
Runtime composition
Every Fami page must load scripts in this order:
<script src="../../packages/core/product-context.js"></script>
<script src="../../products/fami/product.js"></script>
<script src="../../../common/api.js"></script>
<script src="../../../common/params.js"></script>
<script src="../../../common/i18n.js"></script>
product.js runs before common/api.js, making Fami the page-level default tenant even when an older client omits app_code. An explicit URL app_code still wins for diagnostics. Pages under the old gonghui/ tree load none of these files, so their default remains Lalu.
Shared domain rules from the initial specification
- Host, agency and BD statistics consume one date-range model: today, yesterday, last 7 days, last 30 days, this month, last month and custom range.
- Metrics are response-driven. The frontend renders values and definitions but does not recompute diamonds, gift senders, online duration, valid live duration/days, private-message users or new followers.
- Agency and BD list rows use stable IDs as keys. Removing a host or agency updates the view only after the server confirms the command.
- Wallet is a separate feature package because host, agency and BD reuse it. Coin-seller withdrawal and USDT withdrawal are separate state machines with separate validation, idempotency command IDs and histories.
- Permissions and feature switches come from backend capabilities. Functional switches default to enabled; only external addresses, secrets and third-party credentials may require environment configuration.
Backend/admin contract direction
New endpoints should be app-scoped through X-App-Code: fami and return server-calculated metrics. Prefer additive /api/v1/guild/... contracts or additive fields on existing center endpoints; do not change Lalu response meaning in place.
The admin coin-seller withdrawal whitelist belongs to backend/admin storage. The H5 only consumes eligible coin sellers and must never treat a locally cached list as authorization.
Implemented host statistics contract
GET /api/v1/host-center/stats?start_date=YYYY-MM-DD&end_date=YYYY-MM-DD returns an inclusive UTC natural-day range and these server-owned metrics:
diamond_earnings,diamond_exchanged,gift_sendersfrom wallet-service POINT ledger entries;online_duration_msfrom App session heartbeat spans, merged per day so overlapping sessions are not double-counted;valid_mic_duration_ms,valid_mic_daysfrom user-service microphone daily facts;private_message_sendersfrom authenticated Tencent IMC2C.CallbackAfterSendMsgevents;new_followersfrom follow/unfollow delta events.
The Tencent C2C callback URL must include the matching product context, for example app_code=fami. The callback stores only event ID, sender, receiver and event time; message content is never written to the statistics table.
Implemented Agency contract and revenue policy
GET /api/v1/agency-center/stats?start_date=YYYY-MM-DD&end_date=YYYY-MM-DD returns the Agency summary and current host rows for the same inclusive UTC date range. Host earnings come from wallet POINT entries; engagement metrics come from user-service facts.
Agency share is configured in the shared Admin revenue-policy template JSON as agency.point_ratio_percent. The common legacy template defaults to 0; the seeded fami_guild_revenue_policy template defaults to 20. Publishing an App policy compiles the value into wallet_policy_instances.agency_point_ratio_ppm. Each successful gift atomically credits the owner POINT account and writes agency_point_share_entries, including the host, owner, ratio and policy instance snapshots. Historical earnings therefore do not move when a host later changes Agency.
Implemented BD and wallet contracts
GET /api/v1/bd-center/stats aggregates the current BD's direct Agencies, active host counts and host gift POINT income without including Agency-share POINT. The page reuses the same date-range model and invitation acceptance flow as the existing organization domain.
The Fami wallet is a shared guild/packages/wallet feature mounted at guild/fami/wallet/. GET /api/v1/point-wallet/overview returns the POINT balance, published policy exchange/fee snapshot and the country-filtered coin-seller whitelist. POINT-to-seller transfers never accept an exchange ratio from H5: wallet-service locks point_withdrawal_coin_seller_configs and atomically debits POINT while crediting COIN_SELLER_COIN. Admin edits the same app-scoped table from /host/point-withdrawal-config; switching the selected App supports Fami, Huwaa, Lalu and future products without adding boolean columns.
Adding another guild product
- Add
guild/products/<product>/product.jsand optional assets/theme overrides. - Add thin entries under
guild/<product>/<feature>/. - Reuse a feature package when its API/state semantics match; add a product adapter when DTOs differ.
- Run
npm run test:guild-architectureto prove the new default app code does not change legacy Lalu requests.