# 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/`: ```text 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 ` ``` `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_senders` from wallet-service POINT ledger entries; - `online_duration_ms` from App session heartbeat spans, merged per day so overlapping sessions are not double-counted; - `valid_mic_duration_ms`, `valid_mic_days` from user-service microphone daily facts; - `private_message_senders` from authenticated Tencent IM `C2C.CallbackAfterSendMsg` events; - `new_followers` from 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 1. Add `guild/products//product.js` and optional assets/theme overrides. 2. Add thin entries under `guild///`. 3. Reuse a feature package when its API/state semantics match; add a product adapter when DTOs differ. 4. Run `npm run test:guild-architecture` to prove the new default app code does not change legacy Lalu requests.