diff --git a/.agents/README.md b/.agents/README.md new file mode 100644 index 0000000..551f06d --- /dev/null +++ b/.agents/README.md @@ -0,0 +1,38 @@ +# .agents Directory + +This directory contains agent configuration and skills for OpenAI Codex CLI. + +## Structure + +``` +.agents/ + config.toml # Main configuration file + skills/ # Skill definitions + skill-name/ + SKILL.md # Skill instructions + scripts/ # Optional scripts + docs/ # Optional documentation + README.md # This file +``` + +## Configuration + +The `config.toml` file controls: +- Model selection +- Approval policies +- Sandbox modes +- MCP server connections +- Skills configuration + +## Skills + +Skills are invoked using `$skill-name` syntax. Each skill has: +- YAML frontmatter with metadata +- Trigger and skip conditions +- Commands and examples + +## Documentation + +- Main instructions: `AGENTS.md` (project root) +- Local overrides: `.codex/AGENTS.override.md` (gitignored) +- Claude Flow: https://github.com/ruvnet/claude-flow diff --git a/.agents/config.toml b/.agents/config.toml new file mode 100644 index 0000000..9110b8e --- /dev/null +++ b/.agents/config.toml @@ -0,0 +1,298 @@ +# ============================================================================= +# Claude Flow V3 - Codex Configuration +# ============================================================================= +# Generated by: @claude-flow/codex +# Documentation: https://github.com/ruvnet/claude-flow +# +# This file configures the Codex CLI for Claude Flow integration. +# Place in .agents/config.toml (project) or .codex/config.toml (user). +# ============================================================================= + +# ============================================================================= +# Core Settings +# ============================================================================= + +# Model selection - the AI model to use for code generation +# Options: gpt-5.3-codex, gpt-4o, claude-sonnet, claude-opus +model = "gpt-5.3-codex" + +# Approval policy determines when human approval is required +# - untrusted: Always require approval +# - on-failure: Require approval only after failures +# - on-request: Require approval for significant changes +# - never: Auto-approve all actions (use with caution) +approval_policy = "on-request" + +# Sandbox mode controls file system access +# - read-only: Can only read files, no modifications +# - workspace-write: Can write within workspace directory +# - danger-full-access: Full file system access (dangerous) +sandbox_mode = "workspace-write" + +# Web search enables internet access for research +# - disabled: No web access +# - cached: Use cached results when available +# - live: Always fetch fresh results +web_search = "cached" + +# ============================================================================= +# Project Documentation +# ============================================================================= + +# Maximum bytes to read from AGENTS.md files +project_doc_max_bytes = 65536 + +# Fallback filenames if AGENTS.md not found +project_doc_fallback_filenames = [ + "AGENTS.md", + "TEAM_GUIDE.md", + ".agents.md" +] + +# ============================================================================= +# Features +# ============================================================================= + +[features] +# Enable child AGENTS.md guidance +child_agents_md = true + +# Cache shell environment for faster repeated commands +shell_snapshot = true + +# Smart approvals based on request context +request_rule = true + +# Enable remote compaction for large histories +remote_compaction = true + +# ============================================================================= +# MCP Servers +# ============================================================================= + +[mcp_servers.claude-flow] +command = "npx" +args = ["-y", "@claude-flow/cli@latest"] +enabled = true +tool_timeout_sec = 120 + +# ============================================================================= +# Skills Configuration +# ============================================================================= + +[[skills.config]] +path = ".agents/skills/swarm-orchestration" +enabled = true + +[[skills.config]] +path = ".agents/skills/memory-management" +enabled = true + +[[skills.config]] +path = ".agents/skills/sparc-methodology" +enabled = true + +[[skills.config]] +path = ".agents/skills/security-audit" +enabled = true + +# ============================================================================= +# Profiles +# ============================================================================= + +# Development profile - more permissive for local work +[profiles.dev] +approval_policy = "never" +sandbox_mode = "danger-full-access" +web_search = "live" + +# Safe profile - maximum restrictions +[profiles.safe] +approval_policy = "untrusted" +sandbox_mode = "read-only" +web_search = "disabled" + +# CI profile - for automated pipelines +[profiles.ci] +approval_policy = "never" +sandbox_mode = "workspace-write" +web_search = "cached" + +# ============================================================================= +# History +# ============================================================================= + +[history] +# Save all session transcripts +persistence = "save-all" + +# ============================================================================= +# Shell Environment +# ============================================================================= + +[shell_environment_policy] +# Inherit environment variables +inherit = "core" + +# Exclude sensitive variables +exclude = ["*_KEY", "*_SECRET", "*_TOKEN", "*_PASSWORD"] + +# ============================================================================= +# Sandbox Workspace Write Settings +# ============================================================================= + +[sandbox_workspace_write] +# Additional writable paths beyond workspace +writable_roots = [] + +# Allow network access +network_access = true + +# Exclude temp directories +exclude_slash_tmp = false + +# ============================================================================= +# Security Settings +# ============================================================================= + +[security] +# Enable input validation for all user inputs +input_validation = true + +# Prevent directory traversal attacks +path_traversal_prevention = true + +# Scan for hardcoded secrets +secret_scanning = true + +# Scan dependencies for known CVEs +cve_scanning = true + +# Maximum file size for operations (bytes) +max_file_size = 10485760 + +# Allowed file extensions (empty = allow all) +allowed_extensions = [] + +# Blocked file patterns (regex) +blocked_patterns = ["\\.env$", "credentials\\.json$", "\\.pem$", "\\.key$"] + +# ============================================================================= +# Performance Settings +# ============================================================================= + +[performance] +# Maximum concurrent agents +max_agents = 8 + +# Task timeout in seconds +task_timeout = 300 + +# Memory limit per agent +memory_limit = "512MB" + +# Enable response caching +cache_enabled = true + +# Cache TTL in seconds +cache_ttl = 3600 + +# Enable parallel task execution +parallel_execution = true + +# ============================================================================= +# Logging Settings +# ============================================================================= + +[logging] +# Log level: debug, info, warn, error +level = "info" + +# Log format: json, text, pretty +format = "pretty" + +# Log destination: stdout, file, both +destination = "stdout" + +# ============================================================================= +# Neural Intelligence Settings +# ============================================================================= + +[neural] +# Enable SONA (Self-Optimizing Neural Architecture) +sona_enabled = true + +# Enable HNSW vector search +hnsw_enabled = true + +# HNSW index parameters +hnsw_m = 16 +hnsw_ef_construction = 200 +hnsw_ef_search = 100 + +# Enable pattern learning +pattern_learning = true + +# Learning rate for neural adaptation +learning_rate = 0.01 + +# ============================================================================= +# Swarm Orchestration Settings +# ============================================================================= + +[swarm] +# Default topology: hierarchical, mesh, ring, star +default_topology = "hierarchical" + +# Default strategy: balanced, specialized, adaptive +default_strategy = "specialized" + +# Consensus algorithm: raft, byzantine, gossip +consensus = "raft" + +# Enable anti-drift measures +anti_drift = true + +# Checkpoint interval (tasks) +checkpoint_interval = 10 + +# ============================================================================= +# Hooks Configuration +# ============================================================================= + +[hooks] +# Enable lifecycle hooks +enabled = true + +# Pre-task hook +pre_task = true + +# Post-task hook (for learning) +post_task = true + +# Enable neural training on post-edit +train_on_edit = true + +# ============================================================================= +# Background Workers +# ============================================================================= + +[workers] +# Enable background workers +enabled = true + +# Worker configuration +[workers.audit] +enabled = true +priority = "critical" +interval = 300 + +[workers.optimize] +enabled = true +priority = "high" +interval = 600 + +[workers.consolidate] +enabled = true +priority = "low" +interval = 1800 diff --git a/.agents/skills/memory-management/SKILL.md b/.agents/skills/memory-management/SKILL.md new file mode 100644 index 0000000..c337ff9 --- /dev/null +++ b/.agents/skills/memory-management/SKILL.md @@ -0,0 +1,126 @@ +--- +name: memory-management +description: > + AgentDB memory system with HNSW vector search. Provides 150x-12,500x faster pattern retrieval, persistent storage, and semantic search capabilities for learning and knowledge management. + Use when: need to store successful patterns, searching for similar solutions, semantic lookup of past work, learning from previous tasks, sharing knowledge between agents, building knowledge base. + Skip when: no learning needed, ephemeral one-off tasks, external data sources available, read-only exploration. +--- + +# Memory Management Skill + +## Purpose +AgentDB memory system with HNSW vector search. Provides 150x-12,500x faster pattern retrieval, persistent storage, and semantic search capabilities for learning and knowledge management. + +## When to Trigger +- need to store successful patterns +- searching for similar solutions +- semantic lookup of past work +- learning from previous tasks +- sharing knowledge between agents +- building knowledge base + +## When to Skip +- no learning needed +- ephemeral one-off tasks +- external data sources available +- read-only exploration + +## Commands + +### Store Pattern +Store a pattern or knowledge item in memory + +```bash +npx @claude-flow/cli memory store --key "[key]" --value "[value]" --namespace patterns +``` + +**Example:** +```bash +npx @claude-flow/cli memory store --key "auth-jwt-pattern" --value "JWT validation with refresh tokens" --namespace patterns +``` + +### Semantic Search +Search memory using semantic similarity + +```bash +npx @claude-flow/cli memory search --query "[search terms]" --limit 10 +``` + +**Example:** +```bash +npx @claude-flow/cli memory search --query "authentication best practices" --limit 5 +``` + +### Retrieve Entry +Retrieve a specific memory entry by key + +```bash +npx @claude-flow/cli memory get --key "[key]" --namespace [namespace] +``` + +**Example:** +```bash +npx @claude-flow/cli memory get --key "auth-jwt-pattern" --namespace patterns +``` + +### List Entries +List all entries in a namespace + +```bash +npx @claude-flow/cli memory list --namespace [namespace] +``` + +**Example:** +```bash +npx @claude-flow/cli memory list --namespace patterns --limit 20 +``` + +### Delete Entry +Delete a memory entry + +```bash +npx @claude-flow/cli memory delete --key "[key]" --namespace [namespace] +``` + +### Initialize HNSW Index +Initialize HNSW vector search index + +```bash +npx @claude-flow/cli memory init --enable-hnsw +``` + +### Memory Stats +Show memory usage statistics + +```bash +npx @claude-flow/cli memory stats +``` + +### Export Memory +Export memory to JSON + +```bash +npx @claude-flow/cli memory export --output memory-backup.json +``` + + +## Scripts + +| Script | Path | Description | +|--------|------|-------------| +| `memory-backup` | `.agents/scripts/memory-backup.sh` | Backup memory to external storage | +| `memory-consolidate` | `.agents/scripts/memory-consolidate.sh` | Consolidate and optimize memory | + + +## References + +| Document | Path | Description | +|----------|------|-------------| +| `HNSW Guide` | `docs/hnsw.md` | HNSW vector search configuration | +| `Memory Schema` | `docs/memory-schema.md` | Memory namespace and schema reference | + +## Best Practices +1. Check memory for existing patterns before starting +2. Use hierarchical topology for coordination +3. Store successful patterns after completion +4. Document any new learnings diff --git a/.agents/skills/security-audit/SKILL.md b/.agents/skills/security-audit/SKILL.md new file mode 100644 index 0000000..83f7d64 --- /dev/null +++ b/.agents/skills/security-audit/SKILL.md @@ -0,0 +1,135 @@ +--- +name: security-audit +description: > + Comprehensive security scanning and vulnerability detection. Includes input validation, path traversal prevention, CVE detection, and secure coding pattern enforcement. + Use when: authentication implementation, authorization logic, payment processing, user data handling, API endpoint creation, file upload handling, database queries, external API integration. + Skip when: read-only operations on public data, internal development tooling, static documentation, styling changes. +--- + +# Security Audit Skill + +## Purpose +Comprehensive security scanning and vulnerability detection. Includes input validation, path traversal prevention, CVE detection, and secure coding pattern enforcement. + +## When to Trigger +- authentication implementation +- authorization logic +- payment processing +- user data handling +- API endpoint creation +- file upload handling +- database queries +- external API integration + +## When to Skip +- read-only operations on public data +- internal development tooling +- static documentation +- styling changes + +## Commands + +### Full Security Scan +Run comprehensive security analysis on the codebase + +```bash +npx @claude-flow/cli security scan --depth full +``` + +**Example:** +```bash +npx @claude-flow/cli security scan --depth full --output security-report.json +``` + +### Input Validation Check +Check for input validation issues + +```bash +npx @claude-flow/cli security scan --check input-validation +``` + +**Example:** +```bash +npx @claude-flow/cli security scan --check input-validation --path ./src/api +``` + +### Path Traversal Check +Check for path traversal vulnerabilities + +```bash +npx @claude-flow/cli security scan --check path-traversal +``` + +### SQL Injection Check +Check for SQL injection vulnerabilities + +```bash +npx @claude-flow/cli security scan --check sql-injection +``` + +### XSS Check +Check for cross-site scripting vulnerabilities + +```bash +npx @claude-flow/cli security scan --check xss +``` + +### CVE Scan +Scan dependencies for known CVEs + +```bash +npx @claude-flow/cli security cve --scan +``` + +**Example:** +```bash +npx @claude-flow/cli security cve --scan --severity high +``` + +### Security Audit Report +Generate full security audit report + +```bash +npx @claude-flow/cli security audit --report +``` + +**Example:** +```bash +npx @claude-flow/cli security audit --report --format markdown --output SECURITY.md +``` + +### Threat Modeling +Run threat modeling analysis + +```bash +npx @claude-flow/cli security threats --analyze +``` + +### Validate Secrets +Check for hardcoded secrets + +```bash +npx @claude-flow/cli security validate --check secrets +``` + + +## Scripts + +| Script | Path | Description | +|--------|------|-------------| +| `security-scan` | `.agents/scripts/security-scan.sh` | Run full security scan pipeline | +| `cve-remediate` | `.agents/scripts/cve-remediate.sh` | Auto-remediate known CVEs | + + +## References + +| Document | Path | Description | +|----------|------|-------------| +| `Security Checklist` | `docs/security-checklist.md` | Security review checklist | +| `OWASP Guide` | `docs/owasp-top10.md` | OWASP Top 10 mitigation guide | + +## Best Practices +1. Check memory for existing patterns before starting +2. Use hierarchical topology for coordination +3. Store successful patterns after completion +4. Document any new learnings diff --git a/.agents/skills/sparc-methodology/SKILL.md b/.agents/skills/sparc-methodology/SKILL.md new file mode 100644 index 0000000..d48e6ef --- /dev/null +++ b/.agents/skills/sparc-methodology/SKILL.md @@ -0,0 +1,118 @@ +--- +name: sparc-methodology +description: > + SPARC development workflow: Specification, Pseudocode, Architecture, Refinement, Completion. A structured approach for complex implementations that ensures thorough planning before coding. + Use when: new feature implementation, complex implementations, architectural changes, system redesign, integration work, unclear requirements. + Skip when: simple bug fixes, documentation updates, configuration changes, well-defined small tasks, routine maintenance. +--- + +# Sparc Methodology Skill + +## Purpose +SPARC development workflow: Specification, Pseudocode, Architecture, Refinement, Completion. A structured approach for complex implementations that ensures thorough planning before coding. + +## When to Trigger +- new feature implementation +- complex implementations +- architectural changes +- system redesign +- integration work +- unclear requirements + +## When to Skip +- simple bug fixes +- documentation updates +- configuration changes +- well-defined small tasks +- routine maintenance + +## Commands + +### Specification Phase +Define requirements, acceptance criteria, and constraints + +```bash +npx @claude-flow/cli hooks route --task "specification: [requirements]" +``` + +**Example:** +```bash +npx @claude-flow/cli hooks route --task "specification: user authentication with OAuth2, MFA, and session management" +``` + +### Pseudocode Phase +Write high-level pseudocode for the implementation + +```bash +npx @claude-flow/cli hooks route --task "pseudocode: [feature]" +``` + +**Example:** +```bash +npx @claude-flow/cli hooks route --task "pseudocode: OAuth2 login flow with token refresh" +``` + +### Architecture Phase +Design system structure, interfaces, and dependencies + +```bash +npx @claude-flow/cli hooks route --task "architecture: [design]" +``` + +**Example:** +```bash +npx @claude-flow/cli hooks route --task "architecture: auth module with service layer, repository, and API endpoints" +``` + +### Refinement Phase +Iterate on the design based on feedback + +```bash +npx @claude-flow/cli hooks route --task "refinement: [feedback]" +``` + +**Example:** +```bash +npx @claude-flow/cli hooks route --task "refinement: add rate limiting and brute force protection" +``` + +### Completion Phase +Finalize implementation with tests and documentation + +```bash +npx @claude-flow/cli hooks route --task "completion: [final checks]" +``` + +**Example:** +```bash +npx @claude-flow/cli hooks route --task "completion: verify all tests pass, update API docs, security review" +``` + +### SPARC Coordinator +Spawn SPARC coordinator agent + +```bash +npx @claude-flow/cli agent spawn --type sparc-coord --name sparc-lead +``` + + +## Scripts + +| Script | Path | Description | +|--------|------|-------------| +| `sparc-init` | `.agents/scripts/sparc-init.sh` | Initialize SPARC workflow for a new feature | +| `sparc-review` | `.agents/scripts/sparc-review.sh` | Run SPARC phase review checklist | + + +## References + +| Document | Path | Description | +|----------|------|-------------| +| `SPARC Overview` | `docs/sparc.md` | Complete SPARC methodology guide | +| `Phase Templates` | `docs/sparc-templates.md` | Templates for each SPARC phase | + +## Best Practices +1. Check memory for existing patterns before starting +2. Use hierarchical topology for coordination +3. Store successful patterns after completion +4. Document any new learnings diff --git a/.agents/skills/swarm-orchestration/SKILL.md b/.agents/skills/swarm-orchestration/SKILL.md new file mode 100644 index 0000000..1e2a9df --- /dev/null +++ b/.agents/skills/swarm-orchestration/SKILL.md @@ -0,0 +1,114 @@ +--- +name: swarm-orchestration +description: > + Multi-agent swarm coordination for complex tasks. Uses hierarchical topology with specialized agents to break down and execute complex work across multiple files and modules. + Use when: 3+ files need changes, new feature implementation, cross-module refactoring, API changes with tests, security-related changes, performance optimization across codebase, database schema changes. + Skip when: single file edits, simple bug fixes (1-2 lines), documentation updates, configuration changes, quick exploration. +--- + +# Swarm Orchestration Skill + +## Purpose +Multi-agent swarm coordination for complex tasks. Uses hierarchical topology with specialized agents to break down and execute complex work across multiple files and modules. + +## When to Trigger +- 3+ files need changes +- new feature implementation +- cross-module refactoring +- API changes with tests +- security-related changes +- performance optimization across codebase +- database schema changes + +## When to Skip +- single file edits +- simple bug fixes (1-2 lines) +- documentation updates +- configuration changes +- quick exploration + +## Commands + +### Initialize Swarm +Start a new swarm with hierarchical topology (anti-drift) + +```bash +npx @claude-flow/cli swarm init --topology hierarchical --max-agents 8 --strategy specialized +``` + +**Example:** +```bash +npx @claude-flow/cli swarm init --topology hierarchical --max-agents 6 --strategy specialized +``` + +### Route Task +Route a task to the appropriate agents based on task type + +```bash +npx @claude-flow/cli hooks route --task "[task description]" +``` + +**Example:** +```bash +npx @claude-flow/cli hooks route --task "implement OAuth2 authentication flow" +``` + +### Spawn Agent +Spawn a specific agent type + +```bash +npx @claude-flow/cli agent spawn --type [type] --name [name] +``` + +**Example:** +```bash +npx @claude-flow/cli agent spawn --type coder --name impl-auth +``` + +### Monitor Status +Check the current swarm status + +```bash +npx @claude-flow/cli swarm status --verbose +``` + +### Orchestrate Task +Orchestrate a task across multiple agents + +```bash +npx @claude-flow/cli task orchestrate --task "[task]" --strategy adaptive +``` + +**Example:** +```bash +npx @claude-flow/cli task orchestrate --task "refactor auth module" --strategy parallel --max-agents 4 +``` + +### List Agents +List all active agents + +```bash +npx @claude-flow/cli agent list --filter active +``` + + +## Scripts + +| Script | Path | Description | +|--------|------|-------------| +| `swarm-start` | `.agents/scripts/swarm-start.sh` | Initialize swarm with default settings | +| `swarm-monitor` | `.agents/scripts/swarm-monitor.sh` | Real-time swarm monitoring dashboard | + + +## References + +| Document | Path | Description | +|----------|------|-------------| +| `Agent Types` | `docs/agents.md` | Complete list of agent types and capabilities | +| `Topology Guide` | `docs/topology.md` | Swarm topology configuration guide | + +## Best Practices +1. Check memory for existing patterns before starting +2. Use hierarchical topology for coordination +3. Store successful patterns after completion +4. Document any new learnings diff --git a/.gitignore b/.gitignore index 79f86ee..ce9f7ff 100644 --- a/.gitignore +++ b/.gitignore @@ -67,3 +67,15 @@ script/*.sh # ==================== 临时笔记 ==================== 订单日志.txt + +# Codex local configuration +.codex/ + +# Claude Flow runtime data +.claude-flow/data/ +.claude-flow/logs/ + +# Environment variables +.env +.env.local +.env.*.local diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..ad854b9 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,145 @@ +# ppanel-server + +> Multi-agent orchestration framework for agentic coding + +## Project Overview + +A Claude Flow powered project + +**Tech Stack**: TypeScript, Node.js +**Architecture**: Domain-Driven Design with bounded contexts + +## Quick Start + +### Installation +```bash +npm install +``` + +### Build +```bash +npm run build +``` + +### Test +```bash +npm test +``` + +### Development +```bash +npm run dev +``` + +## Agent Coordination + +### Swarm Configuration + +This project uses hierarchical swarm coordination for complex tasks: + +| Setting | Value | Purpose | +|---------|-------|---------| +| Topology | `hierarchical` | Queen-led coordination (anti-drift) | +| Max Agents | 8 | Optimal team size | +| Strategy | `specialized` | Clear role boundaries | +| Consensus | `raft` | Leader-based consistency | + +### When to Use Swarms + +**Invoke swarm for:** +- Multi-file changes (3+ files) +- New feature implementation +- Cross-module refactoring +- API changes with tests +- Security-related changes +- Performance optimization + +**Skip swarm for:** +- Single file edits +- Simple bug fixes (1-2 lines) +- Documentation updates +- Configuration changes + +### Available Skills + +Use `$skill-name` syntax to invoke: + +| Skill | Use Case | +|-------|----------| +| `$swarm-orchestration` | Multi-agent task coordination | +| `$memory-management` | Pattern storage and retrieval | +| `$sparc-methodology` | Structured development workflow | +| `$security-audit` | Security scanning and CVE detection | + +### Agent Types + +| Type | Role | Use Case | +|------|------|----------| +| `researcher` | Requirements analysis | Understanding scope | +| `architect` | System design | Planning structure | +| `coder` | Implementation | Writing code | +| `tester` | Test creation | Quality assurance | +| `reviewer` | Code review | Security and quality | + +## Code Standards + +### File Organization +- **NEVER** save to root folder +- `/src` - Source code files +- `/tests` - Test files +- `/docs` - Documentation +- `/config` - Configuration files + +### Quality Rules +- Files under 500 lines +- No hardcoded secrets +- Input validation at boundaries +- Typed interfaces for public APIs +- TDD London School (mock-first) preferred + +### Commit Messages +``` +(): + +[optional body] + +Co-Authored-By: claude-flow +``` + +Types: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `chore` + +## Security + +### Critical Rules +- NEVER commit secrets, credentials, or .env files +- NEVER hardcode API keys +- Always validate user input +- Use parameterized queries for SQL +- Sanitize output to prevent XSS + +### Path Security +- Validate all file paths +- Prevent directory traversal (../) +- Use absolute paths internally + +## Memory System + +### Storing Patterns +```bash +npx @claude-flow/cli memory store \ + --key "pattern-name" \ + --value "pattern description" \ + --namespace patterns +``` + +### Searching Memory +```bash +npx @claude-flow/cli memory search \ + --query "search terms" \ + --namespace patterns +``` + +## Links + +- Documentation: https://github.com/ruvnet/claude-flow +- Issues: https://github.com/ruvnet/claude-flow/issues diff --git a/internal/model/order/model.go b/internal/model/order/model.go index d98e361..12ff227 100644 --- a/internal/model/order/model.go +++ b/internal/model/order/model.go @@ -61,6 +61,11 @@ type customOrderLogicModel interface { IsUserEligibleForNewOrder(ctx context.Context, userID int64) (bool, error) QueryDailyOrdersList(ctx context.Context, date time.Time) ([]OrdersTotalWithDate, error) QueryMonthlyOrdersList(ctx context.Context, date time.Time) ([]OrdersTotalWithDate, error) + // FindPendingIAPOrders 查询待对账的 Apple IAP 订单 + // minAge: 订单创建时间距今最短时长(避免扫到刚创建的) + // maxAge: 订单创建时间距今最长时长(超出此范围由日终对账处理) + // requireTradeNo: true=只查 trade_no 非空的(第二层),false=全部(第三层) + FindPendingIAPOrders(ctx context.Context, minAge, maxAge time.Duration, requireTradeNo bool) ([]*Order, error) } // UserCounts User counts for new and renewal users @@ -281,6 +286,24 @@ func (m *customOrderModel) QueryDailyOrdersList(ctx context.Context, date time.T return results, err } +// FindPendingIAPOrders 查询待对账的 Apple IAP 待支付订单 +func (m *customOrderModel) FindPendingIAPOrders(ctx context.Context, minAge, maxAge time.Duration, requireTradeNo bool) ([]*Order, error) { + var list []*Order + now := time.Now() + err := m.QueryNoCacheCtx(ctx, &list, func(conn *gorm.DB, v interface{}) error { + q := conn.Model(&Order{}). + Where("method = ? AND status = ? AND created_at < ? AND created_at > ?", + "apple_iap", 1, now.Add(-minAge), now.Add(-maxAge)). + Order("created_at ASC"). + Limit(100) + if requireTradeNo { + q = q.Where("trade_no != '' AND trade_no IS NOT NULL") + } + return q.Find(&list).Error + }) + return list, err +} + // QueryMonthlyOrdersList 查询过去 6 个月订单统计(包含当前月) func (m *customOrderModel) QueryMonthlyOrdersList(ctx context.Context, date time.Time) ([]OrdersTotalWithDate, error) { var results []OrdersTotalWithDate diff --git a/queue/handler/routes.go b/queue/handler/routes.go index 2e96219..ab252a7 100644 --- a/queue/handler/routes.go +++ b/queue/handler/routes.go @@ -3,6 +3,7 @@ package handler import ( "github.com/hibiken/asynq" "github.com/perfect-panel/server/internal/svc" + iapLogic "github.com/perfect-panel/server/queue/logic/iap" orderLogic "github.com/perfect-panel/server/queue/logic/order" smslogic "github.com/perfect-panel/server/queue/logic/sms" "github.com/perfect-panel/server/queue/logic/subscription" @@ -43,4 +44,8 @@ func RegisterHandlers(mux *asynq.ServeMux, serverCtx *svc.ServiceContext) { // ForthwithQuotaTask mux.Handle(types.ForthwithQuotaTask, task.NewQuotaTaskLogic(serverCtx)) + + // Apple IAP 对账(第二层:5min 扫描 + 第三层:日终全量) + mux.Handle(types.SchedulerIAPReconcile, iapLogic.NewReconcileLogic(serverCtx)) + mux.Handle(types.SchedulerIAPDailyReconcile, iapLogic.NewDailyReconcileLogic(serverCtx)) } diff --git a/queue/logic/iap/dailyReconcileLogic.go b/queue/logic/iap/dailyReconcileLogic.go new file mode 100644 index 0000000..3159422 --- /dev/null +++ b/queue/logic/iap/dailyReconcileLogic.go @@ -0,0 +1,27 @@ +package iap + +import ( + "context" + "time" + + "github.com/hibiken/asynq" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/pkg/logger" +) + +// DailyReconcileLogic 第三层:日终全量对账(每天 02:00) +// 扫描过去 48h 内所有未支付的 IAP 订单(含 trade_no 为空的极端情况) +type DailyReconcileLogic struct { + inner *ReconcileLogic +} + +func NewDailyReconcileLogic(svc *svc.ServiceContext) *DailyReconcileLogic { + return &DailyReconcileLogic{inner: &ReconcileLogic{svc: svc}} +} + +func (l *DailyReconcileLogic) ProcessTask(ctx context.Context, _ *asynq.Task) error { + logger.Infof("[IAPDailyReconcile] start at %s", time.Now().Format("2006-01-02 15:04:05")) + // 第三层:扫描 1min ~ 48h,trade_no 非空(trade_no 为空说明客户端从未上传过 token,服务端无法主动补单) + // 实际上与第二层的区别是时间窗口:覆盖全天的遗漏 + return l.inner.reconcile(ctx, 1*time.Minute, 48*time.Hour, true) +} diff --git a/queue/logic/iap/reconcileLogic.go b/queue/logic/iap/reconcileLogic.go new file mode 100644 index 0000000..e79690c --- /dev/null +++ b/queue/logic/iap/reconcileLogic.go @@ -0,0 +1,134 @@ +package iap + +import ( + "context" + "encoding/json" + "strings" + "time" + + "github.com/hibiken/asynq" + "github.com/perfect-panel/server/internal/model/payment" + "github.com/perfect-panel/server/internal/svc" + iapapple "github.com/perfect-panel/server/pkg/iap/apple" + "github.com/perfect-panel/server/pkg/logger" + pkgpayment "github.com/perfect-panel/server/pkg/payment" + queueTypes "github.com/perfect-panel/server/queue/types" +) + +// ReconcileLogic 第二层:每 5 分钟扫描 trade_no 非空的待支付 IAP 订单 +type ReconcileLogic struct { + svc *svc.ServiceContext +} + +func NewReconcileLogic(svc *svc.ServiceContext) *ReconcileLogic { + return &ReconcileLogic{svc: svc} +} + +func (l *ReconcileLogic) ProcessTask(ctx context.Context, _ *asynq.Task) error { + logger.Infof("[IAPReconcile] start at %s", time.Now().Format("2006-01-02 15:04:05")) + return l.reconcile(ctx, 5*time.Minute, 48*time.Hour, true) +} + +// reconcile 核心对账逻辑,被第二层和第三层共享 +func (l *ReconcileLogic) reconcile(ctx context.Context, minAge, maxAge time.Duration, requireTradeNo bool) error { + apiCfg, err := l.loadAppleAPIConfig(ctx) + if err != nil { + logger.Errorf("[IAPReconcile] load apple config error: %v", err) + return nil + } + if apiCfg == nil { + logger.Infof("[IAPReconcile] no enabled apple iap payment found, skip") + return nil + } + + orders, err := l.svc.OrderModel.FindPendingIAPOrders(ctx, minAge, maxAge, requireTradeNo) + if err != nil { + logger.Errorf("[IAPReconcile] find pending orders error: %v", err) + return nil + } + if len(orders) == 0 { + return nil + } + logger.Infof("[IAPReconcile] found %d pending IAP orders (requireTradeNo=%v)", len(orders), requireTradeNo) + + for _, ord := range orders { + if ord.TradeNo == "" { + continue + } + // 用 originalTransactionId(即 trade_no)向 Apple Server API 查询交易详情 + jws, e := iapapple.GetTransactionInfo(*apiCfg, ord.TradeNo) + if e != nil { + logger.Errorf("[IAPReconcile] GetTransactionInfo error: orderNo=%s tradeNo=%s err=%v", + ord.OrderNo, ord.TradeNo, e) + time.Sleep(100 * time.Millisecond) + continue + } + // 解析 JWS(不校验证书链,只读取 payload) + txPayload, e := iapapple.ParseTransactionJWS(jws) + if e != nil { + logger.Errorf("[IAPReconcile] ParseTransactionJWS error: orderNo=%s err=%v", ord.OrderNo, e) + continue + } + if txPayload.RevocationDate != nil { + // 苹果已撤销交易 → 关闭订单 + logger.Infof("[IAPReconcile] transaction revoked, closing order: %s", ord.OrderNo) + _ = l.svc.OrderModel.UpdateOrderStatus(ctx, ord.OrderNo, 3) + continue + } + // 正常已付款交易 → enqueue 激活(activateOrderLogic 内部有幂等保护) + payload, _ := json.Marshal(queueTypes.ForthwithActivateOrderPayload{OrderNo: ord.OrderNo}) + task := asynq.NewTask(queueTypes.ForthwithActivateOrder, payload) + if _, e = l.svc.Queue.EnqueueContext(ctx, task); e != nil { + logger.Errorf("[IAPReconcile] enqueue activate error: orderNo=%s err=%v", ord.OrderNo, e) + } else { + logger.Infof("[IAPReconcile] enqueued activate: %s", ord.OrderNo) + } + time.Sleep(100 * time.Millisecond) // 避免 Apple API 限频 + } + return nil +} + +// loadAppleAPIConfig 从 payment 表读取第一个启用的 Apple IAP 支付方式配置 +func (l *ReconcileLogic) loadAppleAPIConfig(ctx context.Context) (*iapapple.ServerAPIConfig, error) { + pays, err := l.svc.PaymentModel.FindListByPlatform(ctx, pkgpayment.AppleIAP.String()) + if err != nil { + return nil, err + } + for _, pay := range pays { + if pay.Enable == nil || !*pay.Enable || pay.Config == "" { + continue + } + var cfg payment.AppleIAPConfig + if e := cfg.Unmarshal([]byte(pay.Config)); e != nil { + continue + } + if cfg.KeyID == "" || cfg.IssuerID == "" || cfg.PrivateKey == "" { + continue + } + apiCfg := &iapapple.ServerAPIConfig{ + KeyID: cfg.KeyID, + IssuerID: cfg.IssuerID, + PrivateKey: fixPEM(cfg.PrivateKey), + Sandbox: cfg.Sandbox, + } + // 从 site custom data 读取 BundleID + var customData struct { + IapBundleId string `json:"iapBundleId"` + } + if l.svc.Config.Site.CustomData != "" { + _ = json.Unmarshal([]byte(l.svc.Config.Site.CustomData), &customData) + apiCfg.BundleID = customData.IapBundleId + } + return apiCfg, nil + } + return nil, nil +} + +func fixPEM(key string) string { + if !strings.Contains(key, "\n") && strings.Contains(key, "BEGIN PRIVATE KEY") { + key = strings.ReplaceAll(key, " ", "\n") + key = strings.ReplaceAll(key, "-----BEGIN\nPRIVATE\nKEY-----", "-----BEGIN PRIVATE KEY-----") + key = strings.ReplaceAll(key, "-----END\nPRIVATE\nKEY-----", "-----END PRIVATE KEY-----") + } + return key +} diff --git a/queue/types/scheduler.go b/queue/types/scheduler.go index 51ef48c..8bf2631 100644 --- a/queue/types/scheduler.go +++ b/queue/types/scheduler.go @@ -1,8 +1,10 @@ package types const ( - SchedulerCheckSubscription = "scheduler:check:subscription" - SchedulerTotalServerData = "scheduler:total:server" - SchedulerResetTraffic = "scheduler:reset:traffic" - SchedulerTrafficStat = "scheduler:traffic:stat" + SchedulerCheckSubscription = "scheduler:check:subscription" + SchedulerTotalServerData = "scheduler:total:server" + SchedulerResetTraffic = "scheduler:reset:traffic" + SchedulerTrafficStat = "scheduler:traffic:stat" + SchedulerIAPReconcile = "scheduler:iap:reconcile" // 第二层:每 5 分钟扫描待支付 IAP 订单 + SchedulerIAPDailyReconcile = "scheduler:iap:daily:reconcile" // 第三层:日终全量对账 ) diff --git a/scheduler/scheduler.go b/scheduler/scheduler.go index bf131e8..f554cc3 100644 --- a/scheduler/scheduler.go +++ b/scheduler/scheduler.go @@ -52,6 +52,18 @@ func (m *Service) Start() { logger.Errorf("register update exchange rate task failed: %s", err.Error()) } + // schedule Apple IAP reconcile: every 5 minutes (第二层补单) + iapReconcileTask := asynq.NewTask(types.SchedulerIAPReconcile, nil) + if _, err := m.server.Register("@every 5m", iapReconcileTask, asynq.MaxRetry(1)); err != nil { + logger.Errorf("register iap reconcile task failed: %s", err.Error()) + } + + // schedule Apple IAP daily reconcile: every day at 02:00 (第三层日终对账) + iapDailyTask := asynq.NewTask(types.SchedulerIAPDailyReconcile, nil) + if _, err := m.server.Register("0 2 * * *", iapDailyTask, asynq.MaxRetry(1)); err != nil { + logger.Errorf("register iap daily reconcile task failed: %s", err.Error()) + } + if err := m.server.Run(); err != nil { logger.Errorf("run scheduler failed: %s", err.Error()) }