505 lines
18 KiB
Markdown
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
|
|
```
|