Files
planet/rules.md
2026-05-12 17:15:02 +08:00

505 lines
18 KiB
Markdown

---
name: planet-rules
description: Planet repository rules split into LLM-loadable modules.
---
# Planet Rules
**These rules are mandatory. If a requested action conflicts with this file, stop and report the conflict.**
## Loading Protocol
Read this top section first, then load only the modules relevant to the task.
Always load:
- `core`
- `security`
- `workflow`
Load selectively:
| Module | Load when |
|--------|-----------|
| `docs` | Writing, translating, linking, or publishing documentation |
| `uiux` | Visual design, layout, interaction, accessibility, responsive behavior |
| `frontend` | React, TypeScript, CSS, Vite, Bun, admin console, docs UI |
| `backend` | FastAPI, SQLAlchemy, data collectors, database, API performance |
| `earth` | 3D Earth, canvas/Three.js, BGP/vessel/satellite/cable layers, map icons |
| `ai` | AI Provider, LLM gateway, prompts, model config, AI Playground |
| `release` | Version bumps, changelog, version history, commit/tag/push release work |
Do not load the entire file by default for small tasks. Use `rg -n "^## Module:" rules.md` to find module boundaries, then read only the needed block.
---
## Module: core
### Load When
Always.
### Must
- Keep functions small and focused; one concern per file/module.
- Write self-documenting code; comments explain why, not what.
- Prefer dependency injection for testability.
- Use feature flags for incomplete features.
- Use config files or environment variables for environment-specific settings.
- Maintain one source of truth for business state. Temporary UI state, cached state, and persisted backend state must not become parallel truths.
- Transitional paths are temporary. Once a new implementation is stable, remove old branches, old interfaces, old mocks, and compatibility layers.
- Extract repeated request flow, response handling, auth/header assembly, validation, and state reconciliation into helpers or shared layers.
- Centralize default values, system prompts, placeholder structures, and fixed constants.
- Public interfaces, persisted fields, and state structures must have a current owner and caller. Delete unused ones.
- After large feature work, run an explicit cleanup pass for dead code, duplicated helpers, stale interfaces, and naming drift.
### Code Style
- Python: 4-space indentation, Black style, max line length 100.
- TypeScript: 2-space indentation, Prettier style, max line length 100.
- No trailing whitespace.
- Empty line at end of file.
- Sort imports alphabetically inside groups.
- Never use wildcard imports.
- Avoid unclear abbreviations except common ones such as `id`, `ok`, `err`.
- Prefer descriptive names.
- Keep functions around 50 lines or less where practical.
- Split files before they become mixed-responsibility modules.
### Import Order
Python:
```python
# stdlib -> third-party -> local
import json
from datetime import datetime
from fastapi import APIRouter
from sqlalchemy.orm import Session
from app.core.config import settings
```
TypeScript:
```typescript
// React -> third-party -> local
import { useEffect, useState } from 'react'
import axios from 'axios'
import { api } from '@/services/api'
```
### Type Rules
- Use type hints throughout Python.
- Define TypeScript interfaces/types for all structured data.
- Avoid `Any`; use specific unions, generics, or `unknown` where appropriate.
- Prefer typed helpers over repeated type casting.
### Verify
- Use deterministic checks before broad manual inspection:
```bash
git diff --check
rg -n "TODO|FIXME|console\.log|debugger|print\(" <changed-paths>
```
---
## Module: security
### Load When
Always.
### Must
- Never commit `.env`, secrets, keys, tokens, or credentials.
- Use environment variables or the configured settings store for credentials.
- Validate and sanitize user input.
- Use parameterized database queries.
- Never store plain-text passwords.
- Hash passwords with bcrypt/argon2.
- Use short-lived JWT tokens when auth tokens are involved.
- Use token blacklist or equivalent revocation support for logout.
- Do not expose full tokens in UI. Show only a short prefix and mask the rest.
### Verify
```bash
git diff --name-only HEAD
rg -n "api[_-]?key|client_secret|BEGIN .*PRIVATE KEY|AKIA[0-9A-Z]" .
```
---
## Module: workflow
### Load When
Always.
### Git
- Do not revert user changes unless explicitly requested.
- Do not force push to protected branches.
- Use clear commit messages.
- Run relevant tests and builds before committing.
- Frontend package management must use Bun only.
- Never use `npm`, `pnpm`, or `yarn` in the frontend project.
- Verify package legitimacy before adding dependencies.
- Prefer maintained, widely used libraries.
- Pin dependency versions in `pyproject.toml`, `uv.lock`, and `package.json`.
### Deterministic Context
- Prefer compact CLI evidence over reading large files or full diffs:
```bash
git status --short
git diff --stat HEAD
git diff --name-only HEAD
git diff --unified=0 HEAD -- <path>
rg -n "<pattern>" <path>
```
---
## Module: docs
### Load When
Writing, translating, linking, restructuring, or publishing docs.
### Must
- Chinese docs under `docs/technical/zh/` must be Chinese prose, not copied English placeholders.
- Keep technical identifiers, API paths, config keys, code symbols, and product names in English where appropriate.
- Explain why a change exists, not only what files changed.
- Prefer updating an existing relevant doc over creating a duplicate.
- Use `##` and `###` headings; avoid going deeper than three levels.
- Use fenced code blocks with language tags.
- Use tables when comparing options or listing parameters.
- Do not reference PR numbers, issue numbers, or the current conversation.
- Internal links inside `docs/technical/zh/` should point to `docs/technical/zh/...` unless intentionally linking to English-only docs.
- Public Docs UI must only expose documents explicitly registered in `frontend/src/pages/Docs/docs-content.ts`.
- Development plans and task notes under `docs/plans/` are not automatically public documentation.
### Required Content
- Background/problem.
- Core design decisions and rationale.
- Key snippets or focused examples.
- Related files and each file's role.
- Operational caveats or verification steps when relevant.
### Verify
```bash
git diff --stat HEAD
git diff --name-only HEAD
ls docs/technical/zh/
rg -n "\]\(([^)]+)\)" docs/technical/zh/<doc>.md
rg -n "/home/ray/dev/linkong/planet/docs/technical/(?!zh|en)" docs/technical/zh --pcre2
```
Check zh/en duplicates:
```bash
python - <<'PY'
from pathlib import Path
same = []
for en in sorted(Path("docs/technical/en").glob("*.md")):
zh = Path("docs/technical/zh") / en.name
if zh.exists() and en.read_text() == zh.read_text():
same.append(en.name)
if same:
raise SystemExit("identical en/zh docs: " + ", ".join(same))
print("no identical en/zh docs")
PY
```
---
## Module: uiux
### Load When
Changing layout, visual hierarchy, controls, interaction states, responsive behavior, or accessibility.
### Must
- Backend/admin pages are single-screen workspaces first, not long landing pages.
- Common desktop viewports should show the page header, summary/controls, and main work area.
- The main work area gets most available height.
- If text, controls, or tables become unreadable, give that region an internal scrollbar instead of crushing it.
- Overflow ownership must be explicit:
- parent height chain is valid
- height-constrained flex parents use `min-height: 0`
- only the intended scroll node owns `overflow: auto`
- Do not use `overflow: hidden` as a final fix unless another child owns scrolling.
- Tabs define their own scroll strategy; hidden panes must stay hidden.
- Long-form content such as AI briefs, logs, Markdown, raw JSON, and help text should stay readable.
- Prefer stable readable minimum heights plus scrolling for constrained content.
- Avoid brittle `100vh/100vw` in embedded/admin shells; prefer `height: 100%` chains.
- Verify layouts under browser zoom 125% and 150% when changing height-critical screens.
- Avoid wrapper components with implicit layout behavior, such as `Space`, in height-critical scroll regions unless the generated DOM is accounted for.
- Any UI state that hides data or a layer must also reconcile hover, lock, tooltip, and selection state.
### Visual Controls
- Use icons in buttons for common tools/actions when an established icon exists.
- Keep icon-only buttons accessible with `aria-label` and `title`.
- Use segmented controls for modes, switches/checkboxes for binary settings, sliders/inputs for numeric values, menus/selects for option sets, and tabs for views.
- Connection-test actions for endpoint/Base URL inputs must use the shared `ConnectionTestInput` pattern: a single plug/connector icon at the input suffix, no adjacent text button; disabled integrations should grey out the field and its test action.
- Do not put cards inside cards.
- Do not use visible in-app text to explain obvious UI features or styling.
- Text must fit within its parent on mobile and desktop.
- Do not scale font size with viewport width.
- Letter spacing should usually be `0`.
### Verify
```bash
changed=$(git diff --name-only HEAD -- frontend/src)
[ -z "$changed" ] || rg -n "overflow|min-height|Space|Tabs|aria-label|title=" $changed
```
---
## Module: frontend
### Load When
Editing React, TypeScript, CSS, Vite, Bun, admin console, public Docs UI, or client-side services.
### Must
- Use Bun for frontend commands:
```bash
bun install
bun run --cwd frontend build
```
- Never use `npm`, `pnpm`, or `yarn`.
- Keep shared behavior in reusable components/services, not page-local copies.
- Prefer existing project components and patterns.
- Keep page state, backend state, and persisted state clearly separated.
- Presentation state must not pretend to be business state.
- Loading, error, stopped, retry, edit, and view states need explicit semantics.
- Responsive adaptations must preserve the primary action path.
- Markdown rendering behavior belongs in the shared Markdown renderer, not individual docs.
- Public Docs navigation must be whitelist-driven through metadata, not file-system fallback.
### TypeScript/CSS
- Define interfaces for API payloads and component props.
- Avoid broad casts.
- Prefer CSS classes over inline styles except for truly dynamic values.
- For fixed-format UI elements, define stable dimensions with `aspect-ratio`, grid tracks, min/max constraints, or container-relative sizing.
### Verify
```bash
bun run --cwd frontend build
git diff --check -- frontend
rg -n "npm|pnpm|yarn" frontend package.json
```
---
## Module: backend
### Load When
Editing FastAPI, SQLAlchemy, collectors, database models, migrations, services, API routes, or performance-sensitive code.
### Must
- Use custom exceptions for domain errors.
- Never swallow errors silently.
- Distinguish recoverable and unrecoverable errors.
- Log errors with useful context and appropriate level.
- Propagate errors unless explicitly handled.
- Repeated `load -> validate -> transform -> respond` flow should be centralized.
- Each data source has its own collector class.
- Collectors must inherit the repository's base collector abstraction when available.
- Collectors implement `fetch()` and `transform()` or the current project-equivalent pipeline hooks.
- Support incremental and full sync modes where the source allows it.
### Query Performance
- Never load whole tables into Python for filtering, pagination, counting, dedupe, or summary aggregation.
- Push filters, sorting, pagination, `count`, `distinct`, and grouped statistics down to the database.
- Summary/dashboard endpoints should prefer aggregate queries or aggregate endpoints.
- Avoid selecting large JSON/text payload columns on hot paths unless needed.
- List endpoints default to database-side pagination.
- When a query is slow, first check:
- full-table ORM loads
- Python-side post-filtering
- repeated summary queries that can be merged
- repeated per-request recomputation that should be cached or aggregated
### Country Data
- Data sources carrying country, region, or territory fields must validate against `backend/app/core/countries.py`.
- Use `normalize_country(value)` as the single gate.
- If normalization returns `None`, log and reject or flag the value.
- Do not override canonical political labels with raw source labels.
- Add aliases to `COUNTRY_ENTRIES`; do not scatter aliases across collectors or API handlers.
- Frontend country labels should come from the canonical dictionary after normalization.
### Verify
```bash
git diff --name-only HEAD -- backend
python3 -m py_compile <changed-python-files>
rg -n "scalars\\(\\)\\.all\\(\\)|\\.all\\(\\).*\\[:|len\\(.*\\.all\\(" backend/app
rg -n "text\\(\"SELECT \\*|execute.*SELECT \\*" backend/app
rg -n "normalize_country|COUNTRY_ENTRIES" backend/app
```
---
## Module: earth
### Load When
Editing `frontend/public/earth`, 3D Earth, canvas/Three.js rendering, BGP/vessel/satellite/cable layers, geographic boundaries, or Earth marker icons.
### Must
- Keep rendering state and UI state explicitly synchronized.
- If a layer is hidden, clear or reconcile related hover, lock, tooltip, and selection state.
- Avoid one-off visual patches before checking render order, coordinate ownership, and data lifecycle.
- Use Three.js for 3D elements.
- Verify 3D/canvas work with real rendering, not only TypeScript build.
- Do not let loading messages, phase labels, or optimistic UI override real backend task state.
- WebSocket data frames should include timestamps, type, and payload when streaming Earth state.
- Default heartbeat for real-time streams is 30 seconds unless a protocol states otherwise.
### Icon System
Canvas-drawn marker icons for Earth must have canonical SVG sources in:
```text
frontend/public/earth/assets/icons/
```
This directory is the single source of truth for icon geometry. Canvas or Three.js drawing code may use `Path2D` strings or draw calls derived from these SVGs, but the shape must originate here.
Naming:
| Prefix | Context |
|--------|---------|
| `marker-` | Surface map markers |
| `bgp-` | BGP/routing layer icons and event symbols |
| `compute-` | Compute center markers |
Rules:
- Use `fill="currentColor"` for single-color icons.
- Hardcode brand colors only when color is part of icon identity.
- State variants are handled by calling code via color/opacity; do not create separate SVGs per state.
- Use the native canvas coordinate space as `viewBox`, typically `0 0 128 128`.
- When adding an icon, create the SVG, document it in this module, and reference its geometry from rendering code.
Current icons:
| File | Used in | Description |
|------|---------|-------------|
| `marker-landing-point.svg` | `cables.js` | Cable landing point pin |
| `bgp-collector.svg` | `bgp.js` | BGP collector marker |
| `bgp-glow-dot.svg` | `bgp.js` | Base radial glow dot |
| `bgp-event-ring.svg` | `bgp.js` | Event ring overlay |
| `bgp-event-triangle.svg` | `bgp.js` | Origin anomaly |
| `bgp-event-exclamation.svg` | `bgp.js` | Withdraw event |
| `bgp-event-wave.svg` | `bgp.js` | Flap event |
| `bgp-event-burst.svg` | `bgp.js` | Specific/burst anomaly |
| `bgp-event-leak.svg` | `bgp.js` | Route leak |
| `bgp-event-dot.svg` | `bgp.js` | Generic event |
| `compute-supercomputer.svg` | `compute-centers.js` | Supercomputer |
| `compute-gpu-cluster.svg` | `compute-centers.js` | GPU cluster |
### Verify
```bash
bun run --cwd frontend build
rg -n "hover|locked|selected|tooltip|visible|Path2D|drawImage" frontend/public/earth
ls frontend/public/earth/assets/icons/
```
---
## Module: ai
### Load When
Editing AI Provider, LLM gateway, AI Playground, prompt templates, model selection, custom collector mapping generation, or LLM-assisted data transformation.
### Must
- AI provider endpoint/base URL/model/token configuration belongs in settings/integration config, not hardcoded page state.
- The local API route used by the console is not the same as the external LLM provider base URL.
- Common LLM provider presets should be selectable and refreshable from provider docs or catalog logic.
- Store fallback/default provider config centrally.
- Credential previews must reuse the existing product masking convention instead of inventing page-local display logic.
- Never send secrets to logs or docs.
- LLMs may assist with mapping generation or unknown API exploration, but runtime collection should use saved deterministic mapping rules.
- If custom collectors transform into existing domain data, require an explicit target schema.
- If custom collectors introduce entirely new data, do not pretend Earth can use it until a corresponding feature exists.
- Prompts, mapping schemas, default examples, and provider constants must be centralized.
### Verify
```bash
rg -n "AI_PROVIDER|provider_api|base_url|api_key|service_token|prompt|mapping" backend aiprovider frontend/src
git diff --check -- backend aiprovider frontend/src
```
---
## Module: release
### Load When
The user asks to `发版`, bump version, release, commit/push release work, or update changelog/version history as part of a release.
### Must
- Treat release work as release workflow, not a plain commit.
- Use `.codex/skills/release/SKILL.md` when Codex performs a release.
- Version bump rules:
- `feature` -> `+0.1.0`
- `improvement` -> `+0.0.1`
- `bugfix` -> `+0.0.1`
- `docs`, `maintenance`, `refactor` do not bump unless explicitly requested
- Mixed bugfix and small feature/UI work defaults to `improvement` unless the user explicitly chooses another release type.
- A release bump updates all version-bearing files together:
- `VERSION`
- `frontend/package.json`
- `pyproject.toml`
- `uv.lock`
- A release bump updates release records together:
- `docs/CHANGELOG.md`
- `docs/version-history.md`
- `uv.lock` must be regenerated by `uv lock`, never edited manually.
- Before committing a release, verify target version consistency.
- Before pushing a release, run the smallest relevant validation for the changed scope and report what was or was not validated.
- Do not include generated runtime output directories in release commits.
### Verify
```bash
git branch --show-current
git status --short
cat VERSION
rg -n "\"version\":|^version =|version = " frontend/package.json pyproject.toml uv.lock
git diff --stat HEAD
```