Skip to content

Commit 8c3cdb7

Browse files
committed
update member/delete api
1 parent 13d2c38 commit 8c3cdb7

19 files changed

Lines changed: 5910 additions & 8 deletions

.claude/skills/api-review/SKILL.md

Lines changed: 323 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
# Analyze phase
2+
3+
Goal: produce a findings YAML that lists every public API in the requested scope, each annotated with the Go handler that serves it and the input/output types we plan to lift into OpenAPI. The human reviews this file before we spend tokens generating JSON.
4+
5+
## Inputs
6+
7+
- `--scope` — module or sub-module key from `mapping.yaml`, or `all`.
8+
- Parsed registry from `scripts/parse_pgy_registry.py` (run it once, cache the JSON in memory for the rest of this phase).
9+
- Source repos, synced to latest `origin/main`.
10+
11+
## Step 1 — load and filter the registry
12+
13+
Run the parser:
14+
15+
```bash
16+
python3 <skill-path>/scripts/parse_pgy_registry.py ../fc-pgy/logic/api/api_test.go --format json
17+
```
18+
19+
Keep only rows where:
20+
21+
- `auth == "all"` (other auth modes are not public — see `references/auth-modes.md`), AND
22+
- the `path` does NOT start with `/event/push/` (integration-key routes, never `app_key`-callable), AND
23+
- the row's `path` top-level segment matches one of the requested scope's `path_prefixes`, AND
24+
- the row's `provider` is in the scope's `providers` list (when specified — if `providers` is omitted, match on prefix alone).
25+
26+
If `--scope all`, iterate every module where `hidden` is falsy and run the rest of the pipeline once per module.
27+
28+
**Commented vs uncommented — treat them the same.** The convention: commented-out rows are existing production APIs already persisted in the DB; uncommented rows are new additions left active so `go test` can register them. Commenting is a deployment workflow detail, not a status indicator — a commented row is NOT deleted or inactive. All rows in this file are live APIs. This is the single biggest thing to remember.
29+
30+
**Subgroup matching:** When a module defines `subgroups` in `mapping.yaml`, each surviving row must be assigned to a subgroup. Match by checking the row's `path` against each subgroup's `path_prefixes` in order — **first matching subgroup wins**. If no subgroup matches, assign the row to a catch-all group and emit a warning in findings so the user can update the mapping.
31+
32+
## Step 2 — resolve the backend handler for each row
33+
34+
For each surviving row, find the Go file that serves its `path`. The scope's `repos` entry tells you where to look. The convention is:
35+
36+
- `fc-event`: `cmd/server/controller/<feature>/<operation>.go` — one file per operation, named after the URL segment.
37+
- `fc-oncall`: `callee/...` — grep for the path string.
38+
- `fc-pgy`: `cmd/server/controller/...` or `logic/.../controller.go`.
39+
- `monit-webapi`: `api/...` or `logic/.../http.go`.
40+
- `fc-rum`: `controller/...`.
41+
- `fc-statuspage`: `cmd/.../handler.go`.
42+
43+
Practical lookup strategy:
44+
45+
1. Try the file-name convention first. `/template/info``cmd/server/controller/template/info.go`. That's an O(1) hit rate >70% of the time inside fc-event.
46+
2. If not found, `git -C <repo> grep -l '"<path>"' origin/<branch> -- <controller-paths>` — the exact path string often appears in a routes.go file near the handler reference.
47+
3. If still not found, grep for the last URL segment as a Go identifier (e.g. `/template/preview``func Preview(`). Confirm you found the right handler by looking for `srv.GinToCtx` or `srv.Validate` in the same file.
48+
4. If none of those work, record the row under `unresolved` in findings and move on. Do not guess — unresolved rows are fine and the user can fix the mapping.
49+
50+
For each resolved row, extract three things from the handler file:
51+
52+
- `handler_file`: repo-relative path (e.g., `cmd/server/controller/template/info.go`).
53+
- `input_type`: the Go type passed to `srv.Validate(ctx, ...)`, `c.ShouldBindJSON(...)`, or `c.ShouldBindQuery(...)`. This is usually a local `xxxInput` struct in the same file. Record its name.
54+
- `output_type`: the Go type of the value passed to `srv.JSON(ctx, <value>)` on the success branch. This is trickier — follow these rules in order:
55+
1. If the handler builds a struct literal inline (e.g., `srv.JSON(ctx, gin.H{"items": items, "total": total})`), record `output_type: inline` and include the field→type mapping.
56+
2. If the handler calls a logic method and passes the result directly (e.g., `srv.JSON(ctx, item)`), trace the Go type of `item` — usually `*structs.IncidentItem` or `[]*structs.ChannelItem` — and record the fully qualified type name.
57+
3. If the type is a generic helper (e.g., `listResult[structs.XxxItem]`), record both the wrapper and the element type.
58+
59+
Do not inline the entire struct definition here — that's phase 2's job. Phase 1 just names types and their source files so phase 2 can read them.
60+
61+
## Step 3 — assemble the findings YAML
62+
63+
Write to `.api-review/findings-<scope-slug>-<YYYYMMDD-HHMMSS>.yaml` in the docs repo. Use forward slashes in the slug (`on-call-template`).
64+
65+
Structure:
66+
67+
```yaml
68+
scope: on-call/template
69+
generated_at: 2026-04-10T18:30:12Z
70+
docs_path: api-reference/on-call/template/
71+
tag_en: Templates
72+
tag_zh: 模板管理
73+
providers: [event]
74+
source_registry: ../fc-pgy/logic/api/api_test.go
75+
source_registry_commit: <git sha of origin/main HEAD>
76+
77+
operations:
78+
- id: 1060
79+
method: POST
80+
path: /template/info
81+
name: template:read:info
82+
name_cn: 查看模板详情
83+
description: ""
84+
auth: all
85+
is_dangerous: false
86+
is_audit: false
87+
handler:
88+
repo: fc-event
89+
file: cmd/server/controller/template/info.go
90+
input_type: infoInput
91+
output_type: "*structs.TemplateItem"
92+
notes: ""
93+
- id: 1061
94+
# ...
95+
96+
unresolved:
97+
- id: 1234
98+
method: POST
99+
path: /template/mysterious-op
100+
reason: "no handler found under cmd/server/controller/template/"
101+
102+
stats:
103+
total_public: 8
104+
resolved: 8
105+
unresolved: 0
106+
```
107+
108+
`source_registry_commit` matters — it pins what we parsed so stale re-runs are obvious later.
109+
110+
## Step 4 — emit the JSON sidecar and HTML report
111+
112+
Right after writing the YAML, emit two companion files with the same stem:
113+
114+
1. **JSON sidecar** at `.api-review/findings-<scope-slug>-<ts>.json` — identical structure to the YAML (`scope`, `generated_at`, `tag_en`, `tag_zh`, `operations`, `unresolved`, `stats`, …). Powers the HTML render without a PyYAML dependency.
115+
2. **HTML report** via the bundled renderer:
116+
117+
```bash
118+
python3 <skill_dir>/scripts/render_html.py \
119+
.api-review/findings-<scope-slug>-<ts>.json \
120+
--out .api-review/findings-<scope-slug>-<ts>.html
121+
```
122+
123+
`<skill_dir>` is the directory containing this `analyze.md`. The renderer is stdlib-only — no install step. It renders operations sorted by path with HTTP-method chips, dangerous / audit-logged flags, and a dedicated "unresolved" section coloured warm oxblood so missing handlers are impossible to miss.
124+
125+
**Rule of thumb:** YAML is for agents (the generate phase reads it), HTML is for humans (review the picked-up set). The HTML must never be parsed or rewritten by an agent.
126+
127+
## Step 5 — human checkpoint
128+
129+
Print to the user:
130+
131+
- The paths to BOTH the YAML and HTML files.
132+
- The stats block.
133+
- Any `unresolved` rows with their reasons.
134+
- A one-line instruction: "Review the HTML at `<html_path>`, edit the YAML to drop any rows you don't want, then run `/api-review --mode generate --scope <scope>`."
135+
136+
Stop. Do not proceed to generate unless `--auto` was set.
137+
138+
## Auto-mode behavior
139+
140+
If `--auto` is set, skip the "stop and wait" step but still write the findings file. Then invoke the generate phase in the same run, reading the file you just wrote.

0 commit comments

Comments
 (0)