Files
browser/AGENTS.md
T

19 KiB
Raw Blame History

AGENTS.md

This file applies to the entire repository.

Scope

This repository is a game server management platform. Do not add billing, cloud host sales, agent-provider/cloud-provider workflows, or unrelated SaaS marketplace features unless an explicit future product decision requires them.

The platform's required first-party areas are 首页、服务器管理、插件市场、用户管理、AI 提供商管理.

The platform_web visual direction is a unified themed game operations console: the default first-party theme is black mecha, and the selectable alternate first-party theme is magical-girl crystal-moonlight. Preserve the style rules in platform_web/AGENTS.md and platform_web/theme/README.md; do not replace it with generic opaque SaaS cards or unrelated visual systems without an explicit future product decision. Global theme-aware ultimate effects belong in platform_web/components/MagicalParticleLayer.tsx, not in page-local fixed decoration spans or one-off backdrop CSS.

Pre-1.0 Product Completion Rules

Until the primary first-party workflows are implemented end-to-end and the product is ready for a 1.0 milestone, do not add audit-event systems, audit logs, audit-gated behavior, capability allowlists, controlled-action declarations, or similar feature restrictions. Incomplete functionality must not be wrapped in placeholder governance such as a declared-but-unimplemented controlled action like announcement.send.

Before 1.0, prioritize making the actual user-facing flows work fully. Remove or avoid audit/restriction scaffolding when it blocks, distracts from, or outpaces the core implementation. Reintroduce audit, compliance, or restrictive governance only after an explicit future product decision for a completed flow.

During pre-1.0 implementation, GPT must not add defensive code, speculative abstractions, fallback shells, feature gates, capability wrappers, compatibility layers, placeholder validators, or future-proof governance merely because a flow is unfinished or uncertain. Implement the concrete user-facing function first, in the owning root, with the minimum validation and error handling needed for that function to work correctly. Do not turn missing product work into extra indirection, policy checks, blocked states, or generic framework code; if a feature needs data or behavior, build that feature path directly.

Project Roots

  • platform/ contains backend platform code.
  • platform_web/ contains the management frontend.
  • plugins/ contains game management plugins and plugin SDK/examples.

Local Development

  • scum.npc0.com is NAT-mapped to the local frontend at http://127.0.0.1:5173/.
  • GPT must ignore the .local-debug/ directory when searching, inspecting, or modifying repository files.

The machine-side run executor lives in the independent repository git@git.npc0.com:admin343/run.git; do not re-add a run/ source tree to this repository.

Do not place implementation code outside the matching root. Shared contracts must be generated or copied through explicit contract packages, not imported by reaching across ownership boundaries casually.

CSS Authoring Rules

Any task that touches CSS must keep CSS declarations compressed and compact. Do not expand a single selector's style block across many lines when it can be written as a concise one-line rule.

Task Creation Rules

When creating a task, include the following prompt boundaries before implementation starts:

  • Positive prompt (正向提示词): clearly state the intended outcome, accepted success criteria, and the first-party product area the work supports.
  • Directional prompt (方向提示词): state the expected implementation direction, affected project root, relevant existing patterns to preserve, and verification command or evidence expected.
  • Boundary prompt (任务边界): explicitly list out-of-scope areas, forbidden product expansions, and files or roots that must not be touched unless the task explicitly requires them.

Git Completion Rules

All repository modifications must happen on main unless the user explicitly asks for another branch in the current task. Do not create, switch to, or push codex/* or other task branches by default. If the working tree is not on main, switch back to main before editing; if local changes block the switch, stop and report the blocker instead of creating a new branch.

For every substantial session task that modifies repository files, automatically stage only the files changed for that task, create a concise git commit after verification succeeds, and push the current branch to its configured git remote before sending the final response.

Do not include unrelated pre-existing worktree changes in the commit. If commit or push is blocked by missing credentials, a missing remote, conflicts, or a failing required verification step, report the blocker clearly instead of broadening the commit scope.

Structure Rules

Backend roots must keep these concerns in fixed directories:

  • API route declarations and handlers.
  • Request/response DTOs.
  • Domain types.
  • Database models.
  • Repository interfaces and implementations.
  • Service interfaces and implementations.
  • Protocol contracts.
  • Validation rules.
  • Shared utilities.

Frontend and plugin page roots must keep these concerns in fixed directories:

  • API clients and API types.
  • Route definitions.
  • Page/view contracts.
  • Component contracts.
  • Schemas and validators.
  • Bridge/SDK types.
  • Shared utilities.

Do not define business structs inside functions. Do not define request/response structs inside handlers. Do not define database models inside migrations. Do not hide shared frontend types inside page components.

Database, Cache, and Hot-Path Rules

The following rules apply to every backend, plugin, and frontend data-access path. Before adding a database, Redis, or API call, identify the user operation that triggers it, estimate its call count, and keep the hot path bounded and cache-aware.

SQL and Query Rules

  • 禁止在热路径使用 SELECT *LIKE '%keyword%'、无上限分页、深 OFFSET、无索引 ORDER BY、大范围 OR 扫描。
  • 列表分页优先使用游标或上次 seen key,不用深页 OFFSET 扫全表。
  • 写代码前先估算一次玩家操作会触发多少 SQL;一次 NPC 点击、一次菜单打开、一次任务刷新不应触发 N+1 查询。
  • 新增或修改高频查询时,必须在注释、README 或 migration 说明里写出预期索引;复杂查询要能用 EXPLAIN 验证不会全表扫。
  • 不为了“以后可能用”乱加索引;每个索引都会拖慢写入。只给真实查询路径建索引。

Partitioning Rules

  • 只有大体量、追加型、可按时间或赛季归档的数据才考虑分区:登录日志、活动贡献日志、奖励发放日志、审计事件、统计快照。
  • 玩家当前进度、权限、队伍当前状态、小配置表通常不分区,优先靠主键和复合索引解决。
  • 分区键必须出现在热查询条件里;如果查询不带 season_idevent_id 或月份,就不要指望分区救性能。
  • 推荐按 season_idoccurred_at 月份分区;大型活动可按 event_id 做逻辑分片或独立表归档。
  • 分区表必须有保留和归档策略,例如赛季结束 90 天后归档明细,只保留玩家摘要和领奖记录。
  • 不允许为了临时活动创建永久无限增长表;活动结束必须有归档、压缩或清理计划。
  • audit events 仅在现有 pre-1.0 规则允许、且有明确未来产品决策时才可引入;本节不授权提前添加审计系统。

Redis Cache Rules

  • Redis key 必须命名清楚:npc0:<env>:<module>:<type>:<id>,例如 npc0:prod:rpg:party:<party_id>
  • 除明确说明的持久状态外,Redis key 必须设置 TTL;没有 TTL 的缓存 key 视为 bug。
  • 推荐缓存:服务器在线人数、实例健康、Party 预约、队列、冷却、限流、玩家任务摘要、排行榜快照、NPC 菜单展示数据。
  • 不推荐只存在 Redis:经济余额、永久称号、任务最终完成、奖励发放记录、封禁记录、玩家背包关键状态。
  • NPC 点击、菜单打开、scoreboard 刷新优先读本地内存缓存或 Redis 快照;cache miss 才异步查数据库。
  • 使用 Redis 锁必须带过期时间和唯一 token;释放锁时校验 token,避免误删别人的锁。
  • 预约 slot、组队进 Pod、副本实例保留必须有 TTL 和幂等键,玩家掉线后可以过期释放。
  • 禁止在生产热路径使用 KEYS;需要扫描只能用 SCAN,且放在后台任务或运维工具里。
  • 多个 Redis 读写要 pipeline 或批量命令;不要对 100 个玩家循环发 100 次小请求。
  • 防缓存击穿:热门排行榜、服务器列表、活动状态必须有短 TTL、本地缓存和刷新抖动,不让同一秒所有玩家一起打 DB。

API and Query-Call Discipline

  • 能一次批量 API 获取的数据,不允许拆成多个 API;能一次 SQL 查出来的数据,不允许在循环里逐条查。
  • 禁止 N+1:不要先查玩家列表,再对每个玩家查进度、称号、队伍、余额。必须设计批量接口,例如 loadProgressForPlayers(Collection<UUID>)
  • 同一个事件链里需要的数据必须在入口层集中加载,向下传递数据对象;不要让每个 helper 方法自己偷偷查库。
  • 命令、NPC 点击、菜单打开必须加冷却或去抖;玩家连续点击不能造成连续 DB/API 请求。
  • scoreboard、TAB、BossBar、Placeholder 刷新必须低频、缓存化、按变更刷新;不要每 tick 重算字符串和查状态。
  • 跨服状态汇总要走缓存快照;不要每次 /servers 都同步探测所有后端或查数据库。
  • 排行榜、全服贡献、统计面板按秒级或分钟级刷新,不做实时逐点击重算。
  • 写入优先批量合并:任务进度、活动贡献、统计计数可以先入队,定时批量 flush;关键奖励必须幂等落库。
  • 所有重试必须有限次数和退避;禁止无限重试打爆数据库或 Redis。

Per-Operation Pressure Budget

操作 允许的热路径行为 禁止行为
玩家进服 异步批量加载玩家摘要、权限外展示状态、冷却和队伍 主线程逐表查询
NPC 点击 读本地缓存/Redis 快照,必要时异步查一次 同步查库、循环查多个系统
打开菜单 使用已缓存 DTO 一次性渲染 每个按钮单独查 API/SQL
任务完成 幂等写入队列或事务落库,成功后更新缓存 先查后写、多次发奖、不设幂等键
组队进副本 一次性读取 Partyreserve slots,整队调度 每个队员单独调度导致打散
排行榜 读 Redis/内存快照,后台定时刷新 玩家每打开一次就聚合全表
每 tick 任务 0 DB、0 HTTP、尽量 0 Redis 遍历全体玩家查远端状态
关服/重载 限时 flush 队列,失败写本地安全日志 无限等待数据库导致无法停服

Code-Review Requirements

  • 任何新增 DB/Redis/API 代码,都要在 PR/变更说明里写“调用次数预算”:一次命令、一次点击、一次进服、每分钟后台任务各会打多少次 DB/Redis/API。
  • 如果一个方法名是 getXxxhasXxxisXxx,它不能暗中做远程调用;会远程调用的方法必须在名字或注释里明确,例如 loadXxxAsync
  • 所有 DAO/Repository 方法默认异步或只允许在异步线程调用;主线程调用必须被明确禁止或断言。
  • 所有 SQL 使用预编译参数,不拼接玩家输入。
  • 连接池必须有最大连接数、连接超时、查询超时和慢查询日志;不能无限开连接。
  • 触及经济、奖励、任务完成、活动贡献的代码必须可重试且幂等;Pod 重启、玩家重连、消息重复不能重复发奖。
  • 压测前必须用 spark 或日志确认:主线程无阻塞 I/O,DB 慢查询为 0Redis hit rate 达标,单次玩家操作没有 N+1。
  • 如果为了赶工无法满足本节要求,宁可不上这个功能,也不要把数据库和服务器一起拖炸。

Run and Channel Rules

The external run executor must not expose host paths, raw credentials, or direct sockets to plugins or platform_web.

Platform, plugin, and run lifecycle ownership must stay separated. Run is the lifecycle authority for machine execution; Platform records desired lifecycle intent, registration/auth, generated package inputs, and persisted projections from Run-reported facts, not observed process truth:

  • Platform owns server instances, plugin manifest validation, platform-side distribution builds, generated Run package inputs, run registration binding, authorization, and persisted lifecycle projections.
  • Plugins own game-specific lifecycle declarations: init/install/update/pre-start checks, dependency probes/install plans, start arguments, stop logic, status/readiness probes, executable paths, Steam app IDs, and game-specific dependency commands.
  • Run owns generic machine lifecycle execution and the observed runtime/process state it supervises: local bootstrap from generated package plans, scoped file operations, bounded process execution/supervision, declared capability enforcement, logs, artifacts, and channel transport.

Observed machine/runtime status must flow from run reports, heartbeats, supervised process facts, and job/log channels. Platform must not treat stale persisted server state, such as running, as authoritative when evaluating the current machine process state. Run must preserve plugin-declared game records without per-game content redaction. Supervised stdout/stderr and declared file tails are opaque verbatim channels: Run and Platform only persist, relay, or display them; they never inspect, content-filter, redact, normalize, correlate, or use them to produce player/plugin data. A plugin-owned component may parse its own declared raw stream and publish typed plugin-owned records through the component boundary. This does not grant plugins or the browser a direct host-path, credential, or socket API outside the log channel.

SCUM current-service and player evidence must flow through Platform durable jobs, Run typed envelopes, or plugin-owned typed bridge records. Do not download or parse SCUM.db on the platform/plugin/browser side, and do not apply game-specific redaction to plugin-declared result fields, player records, stdout/stderr, or declared file-tail payloads.

Do not hardcode game-specific deployment behavior in run or platform services. Values such as SCUMServer.exe, Steam app 3792580, steamcmd +app_update, SCUM install directories, -port, -MaxPlayers, or -log belong in the SCUM plugin's manifests, action specs, templates, or scripts.

When a game needs "install if missing, update if present, then start" behavior, implement it as plugin-owned lifecycle actions and package those declarations into the generated Run autonomous lifecycle plan. Run executes the plan through generic capabilities; neither Platform nor Run should special-case a game by name to perform those steps.

Do not add extra platform/frontend lifecycle states just to represent game-specific setup checks. A plugin-owned start action should verify its declared files and dependencies, create missing directories, install or update missing server bits, then start the service through the same plugin-declared lifecycle script. Run should only execute that declared script through generic supervision, hide the started process window where the operating system supports it, and return the supervised process output through the declared stdout/stderr log channels.

Realtime log collection must be plugin-declared and plugin-configured. For live terminal output, prefer the plugin-declared supervised process channels (process.stdout / process.stderr) for the process that run started, and treat game-specific file tails only as plugin-declared sources for history, fallback, or explicit backfill. Do not inspect or prioritize a game log file such as SCUM.log merely because it exists on disk; if a plugin needs a file tail, window/console capture, startup flag, hidden window behavior, or another live-log source, declare that behavior in the plugin manifest/action/config and keep run/platform generic.

Run-platform communication must remain channelized:

  • Control is lightweight and high priority.
  • Jobs carry lifecycle and bounded operations.
  • Logs use durable batch ingest with local spool and sequence acknowledgement.
  • Artifacts use chunked and resumable transfer with lower priority than logs/control.
  • Optional game client bridge is separate from run lifecycle and log ingest.

Large file transfer must not block control heartbeat, job ack/result, or log upload.

Distribution Build Ownership Rules

Distribution building is a platform-side responsibility. The platform must be able to build a run package for any server instance without depending on a privileged worker run endpoint being registered and online. Do not route distribution.build execution through machine-side run endpoints, and do not derive build availability from a run endpoint advertising that capability.

Platform-side builds must execute in a platform-owned Docker builder using a pinned image, with build workspaces isolated per plugin and per job. Builder readiness is a platform-level probe; when it is unavailable, the reported reason must name the platform builder rather than a run endpoint capability.

A generated run carries credentials scoped to one server instance and must never hold distribution-build authority. This restriction is a security boundary, not a fallback path: it must not be relaxed to unblock building. Fix the build path instead.

Component auth keys must stay inside the platform for builder-executed builds. Do not return plaintext auth keys to machine-side run endpoints for distribution builds.

Local Run Distribution Testing

For local testing, when a generated run.exe must be made available to a remote server, start a temporary file server from the build output directory with python3 -m http.server 8000. Download the artifact through https://bt.npc0.com/ followed by its relative file path, then download that file again on the machine where run will execute. This is a test-only distribution path; do not treat the temporary HTTP server or tunnel as a production artifact-delivery service.

AI Provider Rules

AI provider keys and base URLs belong to platform/. Plugins may request AI assistance only through platform-mediated capabilities. Plugin page must never receive raw AI keys.

AI-suggested config changes must produce a reviewable diff or recommendation before platform dispatches a run-side write job.

Verification Rules

Run this before completion:

scripts/check-structure.sh

If you add or change a structural rule, update scripts/check-structure.sh in the same change.