docs: design feishu export workflow

This commit is contained in:
whzy 2026-06-15 14:07:58 +08:00
parent 71ca2bb683
commit a4f3954b2c
3 changed files with 1140 additions and 0 deletions

View File

@ -0,0 +1,740 @@
# Codex Clean Task Chain: GitLink CLI Feishu Export
## Goal
Add a safe `feishu` shortcut module to `gitlink-cli`.
This task only implements:
```text
GitLink workflow JSON
-> Feishu card preview
-> Feishu bot send with explicit --send
-> weekly report
-> Bitable schema
-> Bitable-ready records
-> Agent Skill
```
## Boundaries
Do not implement:
```text
Feishu tasks
Feishu approval
callback server
button callbacks
GitLink remote writes
GitLink comments
Issue closure
code merge actions
direct GitLink webhook creation
real Bitable OpenAPI writes
Feishu Base creation
Feishu table creation
Feishu view creation
open_id person mapping
```
## Hard Rules
```text
1. Target repository: gitlink-cli.
2. Language: Go.
3. Do not add Ruby, Rails, Python, or Node services.
4. First implementation consumes local workflow JSON only.
5. Default behavior is local preview.
6. Real Feishu bot sending requires explicit --send.
7. If --send and --dry-run are both set, return an error.
8. Tests must use local fixtures or mock HTTP servers.
9. Tests must not depend on a real Feishu tenant, bot, token, or webhook.
10. Logs and errors must not print full webhook URLs or secrets.
11. Do not add non-engineering packaging language to code, docs, comments, or reports.
```
## Phase 0: Repository Scan
### Objective
Scan the current codebase and record implementation anchors.
### Read
```text
cmd/root.go
shortcuts/register.go
shortcuts/common/runner.go
shortcuts/common/types.go
shortcuts/workflow/workflow.go
shortcuts/workflow/repo_report.go
shortcuts/workflow/pr_summary.go
shortcuts/workflow/render.go
shortcuts/workflow/testdata/
internal/output/
skills/
docs/
examples/
go.mod
Makefile
.github/
```
### Create
```text
reports/FEISHU_IMPLEMENTATION_SCAN.md
```
### Required Content
```text
Repository anchors
Reusable workflow data and renderers
Reusable output behavior
Shortcut registration pattern
Test fixtures
Current test baseline
Implementation landing points
```
### Verification
```bash
go test ./shortcuts/workflow
go test ./shortcuts
```
Use this when the default Go proxy is unavailable:
```powershell
$env:GOPROXY='https://goproxy.cn,direct'
```
## Phase 1: Feishu Command Skeleton
### Objective
Add a `feishu` shortcut group with five commands. All commands must compile and support `--help`. No command sends network traffic by default.
### Add
```text
shortcuts/feishu/
feishu.go
options.go
redact.go
output.go
```
### Register
Update:
```text
shortcuts/register.go
```
Add:
```text
feishu -> feishu.Shortcuts()
```
Description:
```text
Export GitLink workflow data to Feishu cards and Bitable-ready records
```
### Commands
```bash
gitlink-cli feishu +bot-test
gitlink-cli feishu +notify
gitlink-cli feishu +weekly-report
gitlink-cli feishu +bitable-schema
gitlink-cli feishu +bitable-records
```
Do not add:
```text
+sync-bitable
+approval-create
+sync-tasks
+serve
+webhook-create
```
### Shared Flags
```text
--owner
--repo
--since
--include issues,prs,contributors,health
--format json|table|markdown
--lang zh-CN|en-US
--dry-run
--from-workflow-json
```
### Bot Flags
```text
--webhook-url
--secret
--send
```
### Bitable Preview Flags
```text
--tables issues,prs,contributors,reports
```
### Environment Variables
Read only:
```text
FEISHU_WEBHOOK_URL
FEISHU_WEBHOOK_SECRET
```
Do not read in this task:
```text
FEISHU_TENANT_ACCESS_TOKEN
FEISHU_APP_ID
FEISHU_APP_SECRET
FEISHU_BASE_APP_TOKEN
FEISHU_ISSUE_TABLE_ID
FEISHU_PR_TABLE_ID
FEISHU_CONTRIBUTOR_TABLE_ID
FEISHU_REPORT_TABLE_ID
```
### Verification
```bash
gofmt -w shortcuts/feishu
go test ./shortcuts/feishu
go test ./shortcuts
```
Check help:
```bash
go run . feishu --help
go run . feishu +bot-test --help
go run . feishu +notify --help
go run . feishu +weekly-report --help
go run . feishu +bitable-schema --help
go run . feishu +bitable-records --help
```
## Phase 2: Options and Redaction
### Objective
Implement safe option loading, validation, and redaction.
### Files
```text
shortcuts/feishu/options.go
shortcuts/feishu/redact.go
shortcuts/feishu/options_test.go
shortcuts/feishu/redact_test.go
```
### Options
```go
type Options struct {
Owner string
Repo string
Since string
Include []string
Format string
Lang string
DryRun bool
Send bool
FromWorkflowJSON string
WebhookURL string
WebhookSecret string
Tables []string
}
```
### Functions
```go
func LoadOptions(ctx *common.RuntimeContext) (Options, error)
func ValidateCommonOptions(opts Options) error
func ValidateBotOptions(opts Options) error
func ValidateWorkflowJSONOptions(opts Options) error
func ValidateBitableRecordOptions(opts Options) error
func NormalizeInclude(value string) ([]string, error)
func NormalizeTables(value string) ([]string, error)
func ValidateSendMode(opts Options) error
```
### Send Mode
```text
Default: preview only.
--send: send Feishu bot message.
--send + --dry-run: error.
--send without webhook URL: error.
No --send: no HTTP request.
```
### Redaction
```go
func MaskSecret(value string) string
func MaskWebhookURL(value string) string
func MaskToken(value string) string
func MaskError(err error) string
```
Rules:
```text
secret -> ***
token -> ***
webhook URL -> scheme + host + final 4 path characters
empty string -> ""
short sensitive string -> ***
```
### Verification
```bash
gofmt -w shortcuts/feishu
go test ./shortcuts/feishu
```
## Phase 3: Bot Signature
### Objective
Implement Feishu custom bot signing.
### Files
```text
shortcuts/feishu/signer.go
shortcuts/feishu/signer_test.go
```
### Functions
```go
func BuildBotSign(timestamp int64, secret string) (string, error)
func BuildBotEnvelope(card map[string]any, secret string, now time.Time) (map[string]any, error)
```
### Behavior
```text
Empty secret: no timestamp/sign.
Non-empty secret: add timestamp/sign.
Timestamp: Unix seconds.
Errors must not include secret.
Tests use fixed timestamps.
```
## Phase 4: Card Builders
### Objective
Build Feishu interactive card JSON without network calls.
### Files
```text
shortcuts/feishu/model.go
shortcuts/feishu/card.go
shortcuts/feishu/card_test.go
```
### Models
```go
type ProjectActivity struct {
Repository string
Period string
IssueSummary SummaryBlock
PullRequestSummary SummaryBlock
ContributorSummary SummaryBlock
HealthSummary SummaryBlock
Risks []string
Recommendations []string
}
type SummaryBlock struct {
Title string
Count int
Items []string
}
type WeeklyReport struct {
Repository string
Period string
NewIssues int
ClosedIssues int
NewPullRequests int
MergedPullRequests int
ActiveContributors int
Risks []string
Recommendations []string
Markdown string
}
```
### Functions
```go
func BuildBotTestCard(lang string) map[string]any
func BuildProjectActivityCard(activity ProjectActivity, lang string) map[string]any
func BuildWeeklyReportCard(report WeeklyReport, lang string) map[string]any
```
### Requirements
```text
Use interactive card.
Support zh-CN and en-US text.
Handle empty data.
Do not include secrets or webhook URLs.
```
## Phase 5: Bot Webhook Client
### Objective
Send Feishu bot payloads through an injectable HTTP client.
### Files
```text
shortcuts/feishu/client.go
shortcuts/feishu/client_test.go
```
### API
```go
type Client struct {
HTTPClient *http.Client
}
func NewClient(httpClient *http.Client) *Client
func (c *Client) SendBotMessage(ctx context.Context, webhookURL string, payload any) error
```
### Behavior
```text
POST JSON.
2xx means success.
Non-2xx returns redacted error.
Limit response body read size.
Network errors are redacted.
Never print full webhook URL.
```
### Tests
Use `httptest.Server` for:
```text
200
400
429
500
network error
redaction
```
Do not implement Bitable OpenAPI client in this phase.
## Phase 6: Bot Test Command
### Objective
Preview or explicitly send a test card.
### Commands
Preview:
```bash
go run . feishu +bot-test --format json
```
Send:
```bash
go run . feishu +bot-test --webhook-url "$FEISHU_WEBHOOK_URL" --secret "$FEISHU_WEBHOOK_SECRET" --send
```
### Behavior
```text
Default preview.
Preview prints JSON.
--send sends through mockable client.
--send requires webhook URL.
Output shows only redacted target.
No GitLink data read.
No GitLink write.
```
## Phase 7: Workflow JSON Mapper
### Objective
Read local workflow JSON and map it into Feishu models.
### Files
```text
shortcuts/feishu/mapper.go
shortcuts/feishu/mapper_test.go
shortcuts/feishu/testdata/
repo_report.json
pr_summary.json
health.json
```
### Functions
```go
func LoadWorkflowJSON(path string) (map[string]any, error)
func MapWorkflowToProjectActivity(data map[string]any, opts Options) (ProjectActivity, error)
func MapWorkflowToWeeklyReport(data map[string]any, opts Options) (WeeklyReport, error)
```
### Rules
```text
Support workflow +repo-report JSON first.
Missing fields must not panic.
Unknown fields are ignored.
Do not duplicate workflow analysis logic.
Do not call GitLink remote APIs.
Do not change existing workflow behavior.
```
## Phase 8: Notify Command
### Objective
Create a project activity card from workflow JSON.
### Commands
Preview:
```bash
go run . feishu +notify --from-workflow-json report.json --include issues,prs,contributors,health --format json
```
Send:
```bash
go run . feishu +notify --from-workflow-json report.json --webhook-url "$FEISHU_WEBHOOK_URL" --secret "$FEISHU_WEBHOOK_SECRET" --send
```
### Behavior
```text
Requires --from-workflow-json.
Uses include filter.
Default output is JSON preview.
--send sends a card.
No GitLink write.
```
## Phase 9: Weekly Report Command
### Objective
Create a weekly report from workflow JSON.
### Commands
```bash
go run . feishu +weekly-report --from-workflow-json report.json --format markdown
go run . feishu +weekly-report --from-workflow-json report.json --format json
go run . feishu +weekly-report --from-workflow-json report.json --webhook-url "$FEISHU_WEBHOOK_URL" --secret "$FEISHU_WEBHOOK_SECRET" --send
```
### Behavior
```text
Default output is markdown.
JSON output returns structured WeeklyReport.
--send sends a Feishu card after local report generation.
No GitLink write.
```
## Phase 10: Bitable Schema
### Objective
Generate recommended Bitable schema. Do not connect to Feishu OpenAPI.
### Files
```text
shortcuts/feishu/schema.go
shortcuts/feishu/schema_test.go
```
### Command
```bash
go run . feishu +bitable-schema --tables issues,prs,contributors,reports --format markdown
go run . feishu +bitable-schema --tables issues,prs,contributors,reports --format json
```
### Tables
```text
Issues
Pull Requests
Contributors
Weekly Reports
```
### Rules
```text
Do not create Base.
Do not create tables.
Do not create fields.
Do not create views.
Do not call Feishu OpenAPI.
```
## Phase 11: Bitable Records
### Objective
Generate Bitable-ready records from workflow JSON. Output only.
### Files
```text
shortcuts/feishu/bitable.go
shortcuts/feishu/bitable_test.go
```
### Command
```bash
go run . feishu +bitable-records --from-workflow-json report.json --tables issues,prs,contributors,reports --format json
```
### Rules
```text
Requires --from-workflow-json.
Only outputs records.
Does not read app token.
Does not read table IDs.
Does not call Feishu OpenAPI.
Does not create, update, or upsert.
```
## Phase 12: Skill and Docs
### Add
```text
skills/gitlink-feishu/SKILL.md
docs/feishu-integration.md
docs/feishu-security.md
docs/feishu-bitable-schema.md
examples/feishu/
bot-test.md
notify.md
weekly-report.md
bitable-schema.md
bitable-records.md
```
### Content Rules
```text
Describe engineering usage only.
Default to preview examples.
Show --send only for bot cards.
State that Bitable output is local-only in this task.
Do not include non-engineering packaging language.
```
## Phase 13: Final Verification
### Commands
```bash
gofmt -w shortcuts/feishu
go test ./shortcuts/feishu
go test ./shortcuts/workflow
go test ./shortcuts
```
If dependencies are already available or a temporary proxy is set:
```bash
go test ./...
```
### Completion Report
Create:
```text
reports/FEISHU_TASK_COMPLETION.md
```
Include:
```text
implemented commands
changed files
preview behavior
explicit send behavior
mock test coverage
redaction checks
test results
excluded capabilities
```
## Final Acceptance
```text
feishu --help works.
+bot-test previews JSON.
+bot-test --send is covered by mock HTTP tests.
+notify reads workflow JSON and previews card JSON.
+notify --send is covered by mock HTTP tests.
+weekly-report reads workflow JSON and outputs markdown/json.
+bitable-schema outputs markdown/json.
+bitable-records outputs records JSON.
No output leaks full webhook URL or secret.
No Feishu send happens without --send.
No GitLink remote write exists.
No real Bitable write exists.
Targeted tests pass.
```

View File

@ -0,0 +1,97 @@
# Feishu Export Design Evaluation
## Current Baseline
Working directory:
```text
E:\GitLinkCLI-Competition\gitlink-cli-feishu-clean
```
Branch and base:
```text
feat/feishu-export-clean
origin/master ef7a2c6
```
Baseline tests:
```powershell
$env:GOPROXY='https://goproxy.cn,direct'; go test ./...
```
Result: passed.
The first default `go test ./...` attempt failed only because `proxy.golang.org` was unreachable for new dependencies. With a temporary Go proxy override, the latest master baseline is clean.
## Judgment
The v2 task chain is substantially better than the earlier version and is close to executable. It correctly narrows the feature into a safe one-way export module:
```text
workflow JSON -> local preview
workflow JSON -> Feishu bot card
workflow JSON -> weekly report
workflow JSON -> Bitable schema
workflow JSON -> Bitable-ready records
```
The remaining design adjustments are:
1. Keep the first implementation limited to local workflow JSON input.
2. Use `--send` as the only real Feishu bot send switch.
3. Use `prs` in flags and table keys, while displaying `Pull Requests` to users.
4. Replace any `sync-bitable` wording with `bitable-records`.
5. Do not implement real Bitable OpenAPI writes in this task.
6. Keep `doctor` out of the first implementation unless the other commands already exist.
## What Is Complete
The v2 task chain is complete enough for:
- Command skeleton design.
- Safety options and redaction design.
- Feishu bot card and signature design.
- Mocked webhook client design.
- Workflow JSON mapping design.
- Local weekly report generation.
- Bitable schema generation.
- Bitable-ready record generation.
- Agent Skill and documentation outline.
## What Is Not Closed Yet
The following should not be implemented in the first pass:
- Real Bitable record creation.
- Real Bitable record update.
- Bitable unique-key lookup through Feishu OpenAPI.
- Tenant token acquisition.
- Token cache behavior.
- Feishu Base/table/view creation.
- Any GitLink remote write.
These require a separate authentication and data consistency design.
## Practical Utility
The design is useful in a real CLI workflow:
1. A user generates a workflow report with the existing `workflow +repo-report` command.
2. The new `feishu` command consumes that JSON file.
3. The user previews a card, weekly report, schema, or records locally.
4. Only when `--send` is explicit does the CLI send a Feishu bot message.
This produces a small, testable feature that is useful without requiring Feishu enterprise app credentials.
## Implementation Scope Rating
```text
Direction: strong
Safety boundary: strong
Repository fit: strong
First implementation size: acceptable after removing real Bitable writes
Direct executability: good after using the clean task chain in this directory
```

View File

@ -0,0 +1,303 @@
# Feishu Export Technical Plan
## Latest Master Anchors
Current command registration:
```text
shortcuts/register.go
```
Add imports:
```go
github.com/gitlink-org/gitlink-cli/shortcuts/feishu
```
Add group:
```go
"feishu": feishu.Shortcuts(),
```
Add description:
```go
"feishu": "Export GitLink workflow data to Feishu cards and Bitable-ready records",
```
Shortcut mounting:
```text
shortcuts/common/runner.go
```
Important behavior:
- Boolean flags are read from Cobra as strings in `RuntimeContext.Args`.
- A bool flag with default `true` cannot tell whether the user explicitly set it. Therefore `--send` should be the positive action flag, and `--dry-run` should remain a preview indicator.
- If implementation must detect explicit `--dry-run`, it needs a command-specific Cobra command instead of the generic shortcut runner. Avoid that for the first implementation.
## Send Flag Decision
Use this rule:
```text
--send=false or omitted: preview only.
--send=true and dry-run=false: send.
--send=true and dry-run=true: error.
```
Since generic shortcut flags cannot detect whether `--dry-run` was explicitly passed, set `--dry-run` default to `false` in Feishu commands and treat preview as `!Send`. This avoids a default conflict where `--send` would always collide with default `--dry-run=true`.
Effective mode:
```go
Preview := !opts.Send
```
Validation:
```go
if opts.Send && opts.DryRun {
return error
}
if opts.Send && opts.WebhookURL == "" {
return error
}
```
User-facing meaning:
```text
No --send: preview.
--dry-run: preview and forbid send.
--send: real bot send.
--send --dry-run: invalid.
```
## Output Strategy
Do not extend `internal/output` in the first implementation.
Reason:
- Global output supports `json`, `yaml`, and generic `table`.
- Workflow uses local renderers for markdown.
- Feishu needs markdown for weekly reports and schema docs.
Implement local Feishu render helpers:
```go
func renderJSON(w io.Writer, value any) error
func renderMarkdown(w io.Writer, value any) error
func renderTable(w io.Writer, value any) error
func normalizeFormat(format string, defaultFormat string) string
```
Default formats:
```text
+bot-test: json
+notify: json
+weekly-report: markdown
+bitable-schema: markdown
+bitable-records: json
```
## Workflow JSON Input
First implementation only supports local JSON files.
Expected source:
```bash
gitlink-cli workflow +repo-report --owner <owner> --repo <repo> --format json > report.json
```
Mapping should accept both shapes if found:
1. Raw `RepoReportResult`.
2. Envelope-like object with `data`.
Fields to use:
```text
repository
health.health_score
health.risk_level
issue_summary.total
issue_summary.high_risk
issue_summary.missing_info
pr_summary.total
pr_summary.high_risk
pr_summary.review_focus
recommendations
risk_level
report_score
source
```
Do not import unexported workflow readers. Use JSON mapping to avoid changing workflow internals.
## Feishu Signature
Use Feishu custom bot signing:
```text
string_to_sign = timestamp + "\n" + secret
sign = base64(hmac_sha256(string_to_sign, secret))
```
Implementation notes:
- `timestamp` is Unix seconds and serialized as a string.
- Empty secret means no timestamp/sign.
- Tests use fixed timestamp.
- Errors must be redacted.
## Feishu Card Shape
Use custom bot interactive card payload:
```json
{
"msg_type": "interactive",
"card": {
"header": {
"title": {
"tag": "plain_text",
"content": "GitLink Project Activity"
}
},
"elements": []
}
}
```
Envelope with signature:
```json
{
"timestamp": "1710000000",
"sign": "redacted in logs",
"msg_type": "interactive",
"card": {}
}
```
## HTTP Client
Use package-local client:
```go
type Client struct {
HTTPClient *http.Client
}
```
Use `httptest.Server` for all tests.
Do not use `internal/client.Client` for Feishu because it appends GitLink `.json` suffixes and injects GitLink auth.
## Naming
CLI flags:
```text
prs
--include issues,prs,contributors,health
--tables issues,prs,contributors,reports
```
User-facing labels:
```text
Pull Requests
```
Internal model names:
```text
PullRequestSummary
NewPullRequests
MergedPullRequests
```
Do not use `pulls` in new user-facing flags.
## Bitable Scope
First implementation:
```text
+bitable-schema
+bitable-records
```
No Feishu OpenAPI calls.
No environment variables for app tokens or table IDs.
No tenant token.
No create/update/upsert.
The records command outputs local JSON only:
```go
type BitableRecordsOutput struct {
Repository string `json:"repository"`
Tables []BitableTableRecords `json:"tables"`
}
type BitableTableRecords struct {
Table string `json:"table"`
Records []BitableRecord `json:"records"`
}
type BitableRecord struct {
UniqueKey string `json:"unique_key"`
Fields map[string]any `json:"fields"`
}
```
## Tests To Add
```text
shortcuts/feishu/options_test.go
shortcuts/feishu/redact_test.go
shortcuts/feishu/signer_test.go
shortcuts/feishu/card_test.go
shortcuts/feishu/client_test.go
shortcuts/feishu/mapper_test.go
shortcuts/feishu/schema_test.go
shortcuts/feishu/bitable_test.go
shortcuts/feishu/commands_test.go
```
Minimum assertions:
```text
No --send means no HTTP.
--send means HTTP in mock tests.
--send --dry-run errors.
Missing webhook URL with --send errors.
Errors redact webhook URL and secret.
Workflow JSON can be loaded from fixture.
Missing fields do not panic.
Weekly report markdown is stable.
Bitable schema JSON is parseable.
Bitable records JSON is parseable.
```
## Baseline Verification
Current latest master passes with:
```powershell
$env:GOPROXY='https://goproxy.cn,direct'; go test ./...
```
Keep this as the baseline before implementation.