跳到主要内容

Admin Service Public API Standard

Goal

admin_service is the single servers_v2 API origin configured by BO/BFF:

  • admin_service owns writes, business actions, approvals, state transitions, orchestration, human BO identity/RBAC/data scope, and narrowly-scoped PII reveal actions.
  • Explicit BO read contracts are published by admin_service; complex projections may be implemented by an internal service such as reporting_service, which is never a second BO/BFF origin.
  • External docs must expose only the canonical public surface, not historical compatibility aliases.

Route Style

Use a hybrid style:

  • Resource writes use RESTful methods.
  • Business commands use explicit POST .../actions/....
  • Sensitive PII reveal uses explicit POST .../pii/reveal.
  • BO reads use explicit, tested contracts on the public router; historical broad query handlers remain private unless individually allow-listed.

HTTP Method Rules

CaseMethodPatternNotes
Create resourcePOST/api/v1/{resources}Do not use /create suffix.
Partial field updatePATCH/api/v1/{resources}/{id}For ordinary editable fields.
Replace subresource/configPUT/api/v1/{resources}/{id}/{subresource}Idempotent replacement only.
Delete resourceDELETE/api/v1/{resources}/{id}Real delete only.
Business actionPOST/api/v1/{resources}/{id}/actions/{action}Status transitions, audits, money, side effects.
Collection actionPOST/api/v1/{resources}/actions/{action}Batch commands or action without one URL id.
PII revealPOST/api/v1/{resources}/pii/revealBody is exactly { "guids": [...] }; guids are positive integers; batch decrypts phone and bank fields, requires audit, and must not be a GET.
BO queryPOST/api/v1/admin/{resources}/{query}Fixed request model; admin_service injects database-owned dataScope after resolving the BFF's opaque human Session; may proxy an internal read service.
HealthGET/health, /api/v1/healthNo authentication required.

Naming Rules

  • Resource names are plural and kebab-case: players, player-deposits, bank-card-groups, message-templates.
  • Path parameters are explicit: {player_id}, {deposit_id}, {brand_id}.
  • Action names are kebab-case verbs or verb phrases: lock, unlock, reset-password, approve, decline, recycle, activate, import.
  • Do not use singular legacy prefixes such as /player/deposit or /coupon.
  • Do not use RPC-style suffixes directly under resources: /edit-phone, /update-commission, /create, /send.
  • Do not expose historical broad query terms in public routes unless the exact route is a reviewed BO contract in the allow-list: list, search, stats, logs, details, condition, history, meta.

Auth And Audit Rules

Every public non-health route must require:

  • Admin JWT.
  • Calls from the fixed bo_admin_v2 service subject additionally require an opaque human Session resolved from PostgreSQL on every request.
  • BO query dataScope derived by admin_service from that human account, never accepted from the browser or BFF request body.
  • Brand context when the target is brand-scoped. BFF PII reveal additionally requires the explicit permission and verifies every target against the database-owned human scope before decryption.
  • JWT-derived immutable admin account for writes/actions. Do not accept caller-supplied operator identity in request bodies for business attribution.
  • Audit for money, approvals, state transitions, PII reveal, and security sensitive changes.

PII reveal responses must return only guid, phone_num, and bank_num, and must not include full entity rows. Because the reveal endpoints have a fixed meaning, they always return phone_num and bank_num; callers must not send a fields selector or encrypted PII values in the request body.

Current Public Surface Status

Current public_router has:

  • canonical write/action routes and narrowly scoped Admin UI reads.
  • BO identity endpoints for login, logout, current identity and forced password change, plus permission-gated account/role/scope/auth-event administration.
  • four player-list reporting gateways:
    • POST /api/v1/admin/players/query
    • POST /api/v1/admin/players/meta
    • POST /api/v1/admin/players/summary
    • POST /api/v1/admin/players/stream
  • no unreviewed broad query/list/log/stat routes.
  • 0 internal operational routes.
  • 0 legacy-style public aliases.
  • 0 public WebSocket routes.
  • PII reveal actions:
    • POST /api/v1/players/pii/reveal
    • POST /api/v1/agents/pii/reveal

Published Cleanup Status

The public surface is normalized before external publication. Historical route handlers are still retained on the internal router for compatibility tests and controlled transition work, but public_router hides them from OpenAPI and from the externally mounted app.

Player Routes

CurrentCanonicalAction
POST /api/v1/players/{player_id}/lockPOST /api/v1/players/{player_id}/actions/lockAdd canonical, deprecate current.
POST /api/v1/players/{player_id}/unlockPOST /api/v1/players/{player_id}/actions/unlockAdd canonical, deprecate current.
POST /api/v1/players/{player_id}/unlock-freezePOST /api/v1/players/{player_id}/actions/unlock-freezeAdd canonical, deprecate current.
POST /api/v1/players/{player_id}/edit-passwordPOST /api/v1/players/{player_id}/actions/reset-passwordRename action.
POST /api/v1/players/{player_id}/edit-phonePUT /api/v1/players/{player_id}/phoneUse explicit audited PII subresource replace.
POST /api/v1/players/{player_id}/edit-levelPATCH /api/v1/players/{player_id}/levelUse explicit field subresource update.
POST /api/v1/players/{player_id}/edit-groupPATCH /api/v1/players/{player_id}/groupUse explicit field subresource update.
POST /api/v1/players/{player_id}/edit-agentPATCH /api/v1/players/{player_id}/agentUse explicit assignment update.
POST /api/v1/players/{player_id}/edit-bankPUT /api/v1/players/{player_id}/bank-accountTreat as sensitive subresource replace.
POST /api/v1/players/edit-level-multiPATCH /api/v1/players/bulkBody contains ids and patch.
POST /api/v1/players/edit-group-multiPATCH /api/v1/players/bulkBody contains ids and patch.
POST /api/v1/players/{player_id}/tagsPUT /api/v1/players/{player_id}/tagsRemove duplicate tag update.
POST /api/v1/players/tags/createPOST /api/v1/player-tagsUse resource collection.
POST /api/v1/players/groupsPOST /api/v1/player-groupsUse resource collection.
DELETE /api/v1/players/groups/{group_id}DELETE /api/v1/player-groups/{group_id}Use resource collection.

Finance And Approval Routes

CurrentCanonicalAction
POST /api/v1/players/deposits/{deposit_id}/agreePOST /api/v1/player-deposits/{deposit_id}/actions/approveRename.
POST /api/v1/players/deposits/{deposit_id}/declinePOST /api/v1/player-deposits/{deposit_id}/actions/declineRename.
POST /api/v1/players/deposits/{deposit_id}/recyclePOST /api/v1/player-deposits/{deposit_id}/actions/recycleRename.
POST /api/v1/players/deposits/{deposit_id}/coin-agreePOST /api/v1/player-deposits/{deposit_id}/actions/approve-coinRename.
POST /api/v1/player/deposit/coin/agreeRemove from external docsLegacy singular alias.
POST /api/v1/player/deposit/declineRemove from external docsLegacy singular alias.
POST /api/v1/player/deposit/recycleRemove from external docsLegacy singular alias.
POST /api/v1/players/deposits/shooter-agreePOST /api/v1/player-deposits/actions/approve-shooterCollection action.
POST /api/v1/players/withdrawals/{withdraw_id}/review-agreePOST /api/v1/player-withdrawals/{withdraw_id}/actions/review-approveRename.
POST /api/v1/players/withdrawals/{withdraw_id}/review-declinePOST /api/v1/player-withdrawals/{withdraw_id}/actions/review-declineRename.
POST /api/v1/players/withdrawals/{withdraw_id}/pay-agreePOST /api/v1/player-withdrawals/{withdraw_id}/actions/pay-approveRename.
POST /api/v1/players/withdrawals/{withdraw_id}/pay-declinePOST /api/v1/player-withdrawals/{withdraw_id}/actions/pay-declineRename.
POST /api/v1/players/rolling/{rolling_id}/force-completePOST /api/v1/player-rollings/{rolling_id}/actions/force-completeRename resource.

Agent Routes

CurrentCanonicalAction
POST /api/v1/agents/createPOST /api/v1/agentsRemove /create.
POST /api/v1/agents/{agent_id}/reset-passwordPOST /api/v1/agents/{agent_id}/actions/reset-passwordAdd actions namespace.
POST /api/v1/agents/{agent_id}/lockPOST /api/v1/agents/{agent_id}/actions/lockAdd actions namespace.
POST /api/v1/agents/{agent_id}/unlockPOST /api/v1/agents/{agent_id}/actions/unlockAdd actions namespace.
POST /api/v1/agents/{agent_id}/update-commissionPATCH /api/v1/agents/{agent_id}/commissionTreat as subresource update.
POST /api/v1/agents/{agent_id}/adjust-balancePOST /api/v1/agents/{agent_id}/actions/adjust-balanceMoney action.
POST /api/v1/agents/{agent_id}/add-couponPOST /api/v1/agents/{agent_id}/actions/add-couponAction.
POST /api/v1/agents/{agent_id}/domains/createPOST /api/v1/agents/{agent_id}/domainsRemove /create.

Promotion Routes

CurrentCanonicalAction
POST /api/v1/coupons/createPOST /api/v1/couponsRemove /create.
POST /api/v1/coupons/grantPOST /api/v1/coupons/actions/grantCollection action.
POST /api/v1/coupons/recyclePOST /api/v1/coupons/{coupon_id}/actions/recyclePrefer URL id.
POST /api/v1/coupon/recycleRemove from external docsLegacy singular alias.
POST /api/v1/coupons/sendPOST /api/v1/coupons/actions/sendCollection action.
POST /api/v1/coupon/sendRemove from external docsLegacy singular alias.
POST /api/v1/promotions/createPOST /api/v1/promotionsRemove /create.
POST /api/v1/events/deposit/createNot publicdeposit_event is not present in the v2 schema; the legacy handler remains an internal not-implemented placeholder only.
PUT /api/v1/events/deposit/{event_id}Not publicSame blocker: no production deposit_event owner/table/route contract exists yet.
POST /api/v1/events/register/createPOST /api/v1/register-eventsResource collection.
POST /api/v1/events/register/updatePUT /api/v1/register-events/{event_id}URL id required.
POST /api/v1/events/attendance/createPOST /api/v1/attendance-eventsResource collection.
PUT /api/v1/events/attendance/{event_id}PUT /api/v1/attendance-events/{event_id}Resource collection.
POST /api/v1/message-templates/createPOST /api/v1/message-templatesRemove /create.
POST /api/v1/message-templates/updatePUT /api/v1/message-templates/{template_id}URL id required.

System, Brand, Wallet, Upload Routes

CurrentCanonicalAction
POST /api/v1/ip-blacklistPOST /api/v1/ip-blacklistsPluralize.
PUT /api/v1/ip-blacklist/{entry_id}PUT /api/v1/ip-blacklists/{entry_id}Pluralize.
DELETE /api/v1/ip-blacklist/{entry_id}DELETE /api/v1/ip-blacklists/{entry_id}Pluralize.
POST /api/v1/upload/imagePOST /api/v1/uploads/imagesResource collection.
POST /api/v1/brands/{brand_id}/enablePOST /api/v1/brands/{brand_id}/actions/enableState action.
POST /api/v1/brands/{brand_id}/disablePOST /api/v1/brands/{brand_id}/actions/disableState action.
POST /api/v1/brands/{brand_id}/config/importPOST /api/v1/brands/{brand_id}/config/actions/importAction.
POST /api/v1/agent-brandPOST /api/v1/agent-brandsPluralize or model as /agents/{agent_id}/brands.
PATCH /api/v1/agent-brand/{agent_id}/{brand_id}PATCH /api/v1/agent-brands/{agent_id}/{brand_id}Pluralize.
DELETE /api/v1/agent-brand/{agent_id}/{brand_id}DELETE /api/v1/agent-brands/{agent_id}/{brand_id}Pluralize.
PUT /api/v1/wallet/topologies/{code}/activatePOST /api/v1/wallet/topologies/{code}/actions/activateState action.
PUT /api/v1/wallet/policies/{policy_key}/activatePOST /api/v1/wallet/policies/{policy_key}/actions/activateState action.

Implemented Policy

  1. Internal router keeps legacy handlers for compatibility tests and controlled migration.
  2. External public_router exposes canonical aliases only.
  3. public_router prunes:
    • broad reads not present in the explicit Admin UI allow-list,
    • internal operational paths,
    • singular legacy aliases,
    • /create,
    • /edit-*,
    • historical action verbs outside /actions.
  4. Public surface tests fail when a canonical alias is missing or a legacy alias leaks.
  5. External API docs must be generated from public_router, not the internal router.
  6. Placeholder routes whose backing table/domain contract does not exist, such as deposit_event, must not be registered as canonical aliases or published in OpenAPI. A future deposit-event migration must add the schema, owner, route tests, and OpenAPI contract in the same change.

Test Standard

Every public non-health operation must have either:

  • a direct route test, or
  • a documented exception in the public API contract test.

Minimum direct test coverage per operation:

  • auth required,
  • brand required when brand-scoped,
  • happy-path envelope,
  • audit/side-effect assertion for money, approval, state transition, and PII.