--- 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\(" ``` --- ## 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 -- rg -n "" ``` --- ## 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/.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 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 ```