docs: create roadmap (2 phases)
This commit is contained in:
parent
4f3b9b8fa7
commit
e3b0ab7cca
@ -74,35 +74,35 @@ Deferred to future release.
|
||||
|
||||
| Requirement | Phase | Status |
|
||||
|-------------|-------|--------|
|
||||
| PNL-01 | — | Pending |
|
||||
| PNL-02 | — | Pending |
|
||||
| PNL-03 | — | Pending |
|
||||
| PNL-04 | — | Pending |
|
||||
| PNL-05 | — | Pending |
|
||||
| PNL-06 | — | Pending |
|
||||
| PNL-07 | — | Pending |
|
||||
| PNL-08 | — | Pending |
|
||||
| DIM-01 | — | Pending |
|
||||
| DIM-02 | — | Pending |
|
||||
| DIM-03 | — | Pending |
|
||||
| DIM-04 | — | Pending |
|
||||
| RET-01 | — | Pending |
|
||||
| RET-02 | — | Pending |
|
||||
| RET-03 | — | Pending |
|
||||
| AST-01 | — | Pending |
|
||||
| AST-02 | — | Pending |
|
||||
| AST-03 | — | Pending |
|
||||
| QUA-01 | — | Pending |
|
||||
| QUA-02 | — | Pending |
|
||||
| QUA-03 | — | Pending |
|
||||
| QUA-04 | — | Pending |
|
||||
| QUA-05 | — | Pending |
|
||||
| PNL-01 | Phase 1 | Pending |
|
||||
| PNL-02 | Phase 1 | Pending |
|
||||
| PNL-03 | Phase 1 | Pending |
|
||||
| PNL-04 | Phase 1 | Pending |
|
||||
| PNL-05 | Phase 1 | Pending |
|
||||
| PNL-06 | Phase 1 | Pending |
|
||||
| PNL-07 | Phase 1 | Pending |
|
||||
| PNL-08 | Phase 1 | Pending |
|
||||
| DIM-01 | Phase 1 | Pending |
|
||||
| DIM-02 | Phase 1 | Pending |
|
||||
| DIM-03 | Phase 1 | Pending |
|
||||
| DIM-04 | Phase 1 | Pending |
|
||||
| RET-01 | Phase 1 | Pending |
|
||||
| RET-02 | Phase 2 | Pending |
|
||||
| RET-03 | Phase 1 | Pending |
|
||||
| AST-01 | Phase 1 | Pending |
|
||||
| AST-02 | Phase 2 | Pending |
|
||||
| AST-03 | Phase 2 | Pending |
|
||||
| QUA-01 | Phase 1 | Pending |
|
||||
| QUA-02 | Phase 1 | Pending |
|
||||
| QUA-03 | Phase 1 | Pending |
|
||||
| QUA-04 | Phase 1 | Pending |
|
||||
| QUA-05 | Phase 1 | Pending |
|
||||
|
||||
**Coverage:**
|
||||
- v1 requirements: 23 total
|
||||
- Mapped to phases: 0
|
||||
- Unmapped: 23 ⚠️
|
||||
- Mapped to phases: 23
|
||||
- Unmapped: 0 ✓
|
||||
|
||||
---
|
||||
*Requirements defined: 2026-03-21*
|
||||
*Last updated: 2026-03-21 after initial definition*
|
||||
*Last updated: 2026-03-21 after roadmap creation*
|
||||
|
||||
50
.planning/ROADMAP.md
Normal file
50
.planning/ROADMAP.md
Normal file
@ -0,0 +1,50 @@
|
||||
# Roadmap: Bindbox Game 盈亏统计函数
|
||||
|
||||
## Overview
|
||||
|
||||
Two reusable service-layer functions — `QueryUserProfitLoss` and `QueryActivityProfitLoss` — are built in a new `internal/service/finance/` package. Phase 1 delivers correct, working functions covering the full P&L computation path. Phase 2 populates the per-asset-type breakdown slice, including Fragment synthesis cost. The result is a clean, testable service that callers can invoke without touching HTTP handler logic.
|
||||
|
||||
## Phases
|
||||
|
||||
**Phase Numbering:**
|
||||
- Integer phases (1, 2, 3): Planned milestone work
|
||||
- Decimal phases (2.1, 2.2): Urgent insertions (marked with INSERTED)
|
||||
|
||||
Decimal phases appear between their surrounding integers in numeric order.
|
||||
|
||||
- [ ] **Phase 1: Core P&L Functions** - Scaffold the finance package and deliver working QueryUserProfitLoss / QueryActivityProfitLoss with correct revenue, cost, and profit
|
||||
- [ ] **Phase 2: Per-Asset-Type Breakdown** - Populate the ProfitLossBreakdown slice for all 5 asset types, including Fragment synthesis cost from its own table
|
||||
|
||||
## Phase Details
|
||||
|
||||
### Phase 1: Core P&L Functions
|
||||
**Goal**: Callers can invoke QueryUserProfitLoss and QueryActivityProfitLoss and receive a correct ProfitLossResult with total revenue, cost, profit, and profit rate — with all edge cases handled
|
||||
**Depends on**: Nothing (first phase)
|
||||
**Requirements**: PNL-01, PNL-02, PNL-03, PNL-04, PNL-05, PNL-06, PNL-07, PNL-08, DIM-01, DIM-02, DIM-03, DIM-04, RET-01, RET-03, AST-01, QUA-01, QUA-02, QUA-03, QUA-04, QUA-05
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. Calling QueryUserProfitLoss with a list of user IDs returns a ProfitLossResult where Revenue equals actual_amount + discount_amount for non-refunded orders only, and game-pass orders contribute draw_count × activity_price instead of cash revenue
|
||||
2. Calling QueryActivityProfitLoss with an activity ID returns a ProfitLossResult where Revenue is proportionally attributed per order (no double-counting when one order covers multiple activities)
|
||||
3. Both functions return an error (not silent zero) when any db.Scan() call fails
|
||||
4. Passing nil for StartTime/EndTime applies no time filter; passing nil/0 for AssetType returns aggregated totals across all asset types
|
||||
5. The package contains no call to GetDbW() — all queries route through the injected DbR handle; voided inventory (remark LIKE '%void%' or status=2) and refunded orders (status=3,4) are excluded from cost and revenue respectively
|
||||
**Plans**: TBD
|
||||
|
||||
### Phase 2: Per-Asset-Type Breakdown
|
||||
**Goal**: The ProfitLossBreakdown slice in every ProfitLossResult contains one entry per relevant asset type (Points, Coupon, ItemCard, Product, Fragment), with correct per-type cost including Fragment synthesis cost sourced from fragment_synthesis_logs
|
||||
**Depends on**: Phase 1
|
||||
**Requirements**: AST-02, AST-03, RET-02
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. A ProfitLossResult for an activity that awarded Points, Coupons, and Items contains exactly one ProfitLossBreakdown entry per asset type that had non-zero cost, with the correct cost value for each
|
||||
2. Fragment cost in the breakdown is sourced from fragment_synthesis_logs using the verified join path (not from user_inventory), and matches manual spot-checks against the database
|
||||
3. Summing all breakdown entries' Cost fields equals the total Cost field in the parent ProfitLossResult (no gaps or double-counting between breakdown and totals)
|
||||
**Plans**: TBD
|
||||
|
||||
## Progress
|
||||
|
||||
**Execution Order:**
|
||||
Phases execute in numeric order: 1 → 2
|
||||
|
||||
| Phase | Plans Complete | Status | Completed |
|
||||
|-------|----------------|--------|-----------|
|
||||
| 1. Core P&L Functions | 0/TBD | Not started | - |
|
||||
| 2. Per-Asset-Type Breakdown | 0/TBD | Not started | - |
|
||||
63
.planning/STATE.md
Normal file
63
.planning/STATE.md
Normal file
@ -0,0 +1,63 @@
|
||||
# Project State
|
||||
|
||||
## Project Reference
|
||||
|
||||
See: .planning/PROJECT.md (updated 2026-03-21)
|
||||
|
||||
**Core value:** 提供可复用的盈亏统计方法,使平台运营能从用户和活动两个维度快速了解各类资产的收支状况
|
||||
**Current focus:** Phase 1 — Core P&L Functions
|
||||
|
||||
## Current Position
|
||||
|
||||
Phase: 1 of 2 (Core P&L Functions)
|
||||
Plan: 0 of TBD in current phase
|
||||
Status: Ready to plan
|
||||
Last activity: 2026-03-21 — Roadmap created, ready to begin Phase 1 planning
|
||||
|
||||
Progress: [░░░░░░░░░░] 0%
|
||||
|
||||
## Performance Metrics
|
||||
|
||||
**Velocity:**
|
||||
- Total plans completed: 0
|
||||
- Average duration: — min
|
||||
- Total execution time: 0 hours
|
||||
|
||||
**By Phase:**
|
||||
|
||||
| Phase | Plans | Total | Avg/Plan |
|
||||
|-------|-------|-------|----------|
|
||||
| - | - | - | - |
|
||||
|
||||
**Recent Trend:**
|
||||
- Last 5 plans: —
|
||||
- Trend: —
|
||||
|
||||
*Updated after each plan completion*
|
||||
|
||||
## Accumulated Context
|
||||
|
||||
### Decisions
|
||||
|
||||
Decisions are logged in PROJECT.md Key Decisions table.
|
||||
Recent decisions affecting current work:
|
||||
|
||||
- Init: Fan-out + in-memory merge query pattern chosen (avoids Cartesian product JOINs)
|
||||
- Init: Read-only DB routing enforced — constructor injects DbR only, no GetDbW() in package
|
||||
- Init: All existing finance.* utilities (IsGamePassOrder, ComputeProfit, etc.) must be reused, not re-derived
|
||||
- Init: Phase 2 (Fragment breakdown) requires schema verification of fragment_synthesis_logs join path before implementation
|
||||
|
||||
### Pending Todos
|
||||
|
||||
None yet.
|
||||
|
||||
### Blockers/Concerns
|
||||
|
||||
- Phase 2: fragment_synthesis_logs join path and cost formula not yet verified — requires schema review during Phase 2 planning
|
||||
- Phase 1: SQLite test compatibility for CAST(AS SIGNED), GREATEST(), LIKE 'GP%' — must use Go-layer helpers or conditional SQL paths in integration tests
|
||||
|
||||
## Session Continuity
|
||||
|
||||
Last session: 2026-03-21
|
||||
Stopped at: Roadmap created — ROADMAP.md and STATE.md written, REQUIREMENTS.md traceability updated
|
||||
Resume file: None
|
||||
275
CLAUDE.md
275
CLAUDE.md
@ -289,3 +289,278 @@ Services should contain business logic and call DAOs for data access. Keep handl
|
||||
- **GORM generation fails**: Check database connectivity and ensure `cmd/gormgen/main.go` has correct DB credentials
|
||||
- **Frontend build errors**: Clear node_modules and reinstall: `cd web/admin && rm -rf node_modules && pnpm install`
|
||||
- **JWT token issues**: If admin tokens are invalid, check `ADMIN_JWT_SECRET` environment variable matches config
|
||||
|
||||
<!-- GSD:project-start source:PROJECT.md -->
|
||||
## Project
|
||||
|
||||
**Bindbox Game 盈亏统计函数**
|
||||
|
||||
为 Bindbox Game 平台新增两个 Service 层通用盈亏统计函数,支持按用户维度和活动维度查询平台盈亏情况。函数接收资产类型、维度 ID、时间范围等参数,返回汇总数据和按资产类型拆分的明细。
|
||||
|
||||
**Core Value:** 提供可复用的盈亏统计方法,使平台运营能从用户和活动两个维度快速了解各类资产的收支状况。
|
||||
|
||||
### Constraints
|
||||
|
||||
- **Tech Stack**: Go, GORM, MySQL — 遵循现有项目架构
|
||||
- **Performance**: 统计查询走从库 (DbR),避免影响写库性能
|
||||
- **Compatibility**: 新函数放在 `internal/service/finance/` 下,不修改现有接口
|
||||
<!-- GSD:project-end -->
|
||||
|
||||
<!-- GSD:stack-start source:codebase/STACK.md -->
|
||||
## Technology Stack
|
||||
|
||||
## Languages
|
||||
- Go 1.24.0 - Backend server, all business logic, API handlers
|
||||
- TypeScript ~5.6.3 - Frontend admin panel (`web/admin/src/`)
|
||||
- SQL - Database migrations (`migrations/` directory)
|
||||
- TOML - Configuration files (`configs/*.toml`)
|
||||
- SCSS - Frontend styles (`web/admin/src/assets/styles/`)
|
||||
## Runtime
|
||||
- Go runtime 1.24.0 (toolchain go1.24.2)
|
||||
- Docker: `golang:1.24-alpine` build stage, `alpine:latest` final stage
|
||||
- Node.js >= 18.0.0
|
||||
- Go modules (`go.mod` / `go.sum`) - lockfile present
|
||||
- pnpm >= 8.8.0 - frontend (`web/admin/pnpm-lock.yaml`) - lockfile present
|
||||
## Frameworks
|
||||
- `github.com/gin-gonic/gin v1.9.1` - HTTP web framework
|
||||
- `gorm.io/gorm v1.25.9` - ORM for MySQL
|
||||
- `gorm.io/gen v0.3.26` - GORM code generation from schema
|
||||
- `gorm.io/plugin/dbresolver v1.5.0` - Read/write split support
|
||||
- Vue 3 `^3.5.21` - UI framework (`web/admin/src/`)
|
||||
- Vite `^5.4.10` - Build tool and dev server
|
||||
- Element Plus `^2.11.2` - UI component library
|
||||
- Pinia `^3.0.3` - State management
|
||||
- Vue Router `^4.5.1` - Client-side routing
|
||||
- Tailwind CSS `^4.1.14` - Utility-first CSS
|
||||
- `github.com/stretchr/testify v1.11.1` - Assertions
|
||||
- `github.com/DATA-DOG/go-sqlmock v1.5.2` - MySQL mock
|
||||
- `github.com/alicebob/miniredis/v2 v2.36.1` - In-memory Redis for tests
|
||||
- `gorm.io/driver/sqlite v1.4.3` - SQLite for in-memory test DB (`internal/repository/mysql/testrepo_sqlite.go`)
|
||||
- Vitest `^1.0.0` - Unit test runner
|
||||
- `@vue/test-utils ^2.4.0` - Vue component testing
|
||||
- Makefile - Task runner (`Makefile`)
|
||||
- `golangci-lint` - Linter (install via `make tools`)
|
||||
- `go-swagger` - Swagger generation (install via `make tools`)
|
||||
- `cmd/mfmt/main.go` - Custom import formatter (groups: stdlib, local, third-party)
|
||||
- `cmd/gormgen/main.go` - GORM model/DAO code generator
|
||||
- ESLint `^9.9.1` + TypeScript ESLint `^8.3.0` - Linting
|
||||
- Prettier `^3.5.3` - Code formatting
|
||||
- Stylelint `^16.20.0` - CSS/SCSS linting
|
||||
- Husky `^9.1.5` + lint-staged - Pre-commit hooks
|
||||
- Terser `^5.36.0` - Minification
|
||||
- `vite-plugin-compression ^0.5.1` - Gzip compression for production
|
||||
## Key Dependencies
|
||||
- `github.com/spf13/viper v1.17.0` - Configuration management (TOML, env var overrides)
|
||||
- `go.uber.org/zap v1.26.0` - Structured logging
|
||||
- `gopkg.in/natefinch/lumberjack.v2 v2.2.1` - Log file rotation
|
||||
- `github.com/golang-jwt/jwt/v5 v5.2.0` - JWT auth tokens
|
||||
- `github.com/redis/go-redis/v9 v9.17.2` - Redis client (singleton)
|
||||
- `github.com/go-sql-driver/mysql v1.7.1` - MySQL driver
|
||||
- `github.com/bytedance/sonic v1.13.2` - High-performance JSON encoder/decoder
|
||||
- `github.com/bwmarrin/snowflake v0.3.0` - Distributed ID generation
|
||||
- `github.com/go-resty/resty/v2 v2.10.0` - HTTP client for external API calls
|
||||
- `github.com/prometheus/client_golang v1.17.0` - Prometheus metrics
|
||||
- `golang.org/x/crypto v0.44.0` - Cryptographic utilities
|
||||
- Axios `^1.12.2` - HTTP client for API calls
|
||||
- Echarts `^6.0.0` - Charts and data visualization
|
||||
- `@vueuse/core ^13.9.0` - Vue composition utilities
|
||||
- `pinia-plugin-persistedstate ^4.3.0` - Persistent state storage
|
||||
- `dayjs ^1.11.19` - Date/time manipulation
|
||||
- `crypto-js ^4.2.0` - Client-side cryptography
|
||||
- `xlsx ^0.18.5` - Excel file generation/parsing
|
||||
- `@wangeditor/editor ^5.1.23` - Rich text editor
|
||||
- `go.opentelemetry.io/otel v1.39.0` - Distributed tracing (OTLP HTTP exporter)
|
||||
- `github.com/gin-contrib/pprof v1.4.0` - Go profiling endpoint
|
||||
- `github.com/swaggo/gin-swagger v1.6.0` - Swagger UI embedded in Gin
|
||||
- `github.com/tealeg/xlsx v1.0.5` - Excel file generation (server-side)
|
||||
- `github.com/rs/cors/wrapper/gin v0.0.0-20231013084403-73f81b45a644` - CORS middleware
|
||||
## Configuration
|
||||
- Set via `ENV` environment variable: `dev` | `fat` | `uat` | `pro` (default: `fat`)
|
||||
- Config files embedded into binary at build time via `//go:embed` directives
|
||||
- Config files: `configs/dev_configs.toml`, `configs/fat_configs.toml`, `configs/uat_configs.toml`, `configs/pro_configs.toml`
|
||||
- TOML format parsed via Viper (`github.com/spf13/viper`)
|
||||
- `MYSQL_ADDR`, `MYSQL_READ_ADDR`, `MYSQL_WRITE_ADDR`, `MYSQL_USER`, `MYSQL_PASS`, `MYSQL_NAME`
|
||||
- `REDIS_ADDR`, `REDIS_PASS`
|
||||
- `WECHAT_MCHID`, `WECHAT_SERIAL_NO`, `WECHAT_PRIVATE_KEY_PATH`, `WECHAT_API_V3_KEY`, `WECHAT_NOTIFY_URL`, `WECHAT_PUBLIC_KEY_ID`, `WECHAT_PUBLIC_KEY_PATH`
|
||||
- `ALIYUN_SMS_ACCESS_KEY_ID`, `ALIYUN_SMS_ACCESS_KEY_SECRET`, `ALIYUN_SMS_SIGN_NAME`, `ALIYUN_SMS_TEMPLATE_CODE`
|
||||
- `ADMIN_JWT_SECRET` - Admin JWT signing secret override
|
||||
- Vite env vars: `VITE_VERSION`, `VITE_PORT`, `VITE_BASE_URL`, `VITE_API_URL`, `VITE_API_PROXY_URL`
|
||||
- Dev proxy: `/api` requests forwarded to `VITE_API_PROXY_URL`
|
||||
- Backend: `Dockerfile` (multi-stage, `golang:1.24-alpine` → `alpine:latest`)
|
||||
- Server port: `9991` (constant in `configs/constants.go`)
|
||||
- Container exposes port `9991`
|
||||
## Platform Requirements
|
||||
- Go 1.24+
|
||||
- Node.js >= 18.0.0, pnpm >= 8.8.0
|
||||
- MySQL instance (read/write addresses)
|
||||
- Redis instance
|
||||
- `golangci-lint` and `go-swagger` for linting/docs
|
||||
- Docker (Linux/amd64 binary, CGO_ENABLED=0)
|
||||
- Alpine Linux container
|
||||
- MySQL with optional read replica (master-slave)
|
||||
- Redis single-node
|
||||
- Optional: OpenTelemetry-compatible collector (Tempo) at configured OTLP endpoint
|
||||
<!-- GSD:stack-end -->
|
||||
|
||||
<!-- GSD:conventions-start source:CONVENTIONS.md -->
|
||||
## Conventions
|
||||
|
||||
## Naming Patterns
|
||||
- snake_case for all Go source files: `activity_order_service.go`, `draw_config_save.go`
|
||||
- Test files co-located with source: `reward_snapshot_test.go` next to `rewards_create.go`
|
||||
- Generated files suffixed with `.gen.go`: never edited manually
|
||||
- Package names match directory name: `package activity` in `internal/service/activity/`
|
||||
- kebab-case for TypeScript API files: `pay-orders.ts`, `order-snapshots.ts`
|
||||
- kebab-case for view directories: `player-manage/`, `shipping-orders/`
|
||||
- PascalCase for Vue component filenames where applicable
|
||||
- PascalCase for exported: `NewActivityOrderService`, `CreateActivityOrder`, `ListProductsForApp`
|
||||
- camelCase for unexported: `newRewardSnapshotTestService`, `shouldTriggerInstantDraw`, `assertAttribution`
|
||||
- Constructor functions named `New<Type>` for service constructors: `NewProduct(...)`, `NewStore(...)`
|
||||
- Handler methods return `core.HandlerFunc` (closure pattern): `func (h *productHandler) ListProductsForApp() core.HandlerFunc`
|
||||
- `fetch` prefix for API functions: `fetchGetActivities`, `fetchGetActivityDetail`
|
||||
- camelCase for all functions
|
||||
- camelCase in Go: `userID`, `activityID`, `testLogger`
|
||||
- Named ID variables use int64 type consistently: `userID int64`, `activityID int64`
|
||||
- PascalCase for exported: `CreateActivityOrderRequest`, `ActivityOrderService`
|
||||
- Unexported structs for implementation: `activityOrderService`, `productHandler`, `context`
|
||||
- Request structs named `<verb><Domain>Request`: `listAppProductsRequest`, `CreateActivityOrderRequest`
|
||||
- Response structs named `<verb><Domain>Response`: `listAppProductsResponse`, `getAppProductDetailResponse`
|
||||
- Interface types use verb-noun: `ActivityOrderService`, `Service`, `Repo`
|
||||
- 5-digit pattern: service level (1) + module level (2) + specific error (2)
|
||||
- All-caps with CamelCase words: `ServerError = 10101`, `ParamBindError = 10102`
|
||||
- Grouped by domain in `internal/code/code.go`
|
||||
## Code Style
|
||||
- `gofmt -s` via `make fmt` (uses standard gofmt)
|
||||
- Import grouping via `go run cmd/mfmt/main.go`: stdlib → local module (`bindbox-game/...`) → third-party
|
||||
- Line length not strictly enforced but long lines occur in handler code
|
||||
- `golangci-lint run -D staticcheck` via `make lint`
|
||||
- staticcheck disabled; other default golangci-lint checks active
|
||||
- Prettier for all file types, configured via lint-staged hooks
|
||||
- ESLint with `eslint-plugin-prettier/recommended`
|
||||
- Single quotes enforced: `quotes: ['error', 'single']`
|
||||
- No semicolons: `semi: ['error', 'never']`
|
||||
- No `var`: `'no-var': 'error'` — use `let` or `const`
|
||||
- `@typescript-eslint/no-explicit-any` disabled (any is allowed)
|
||||
- Vue multi-word component name rule disabled
|
||||
## Import Organization
|
||||
- `import request from '@/utils/http'`
|
||||
- `import { getActivityDetail } from './adminActivities'` (relative for same-level)
|
||||
## Error Handling
|
||||
## Logging
|
||||
- Logger injected into handlers and services via constructor
|
||||
- Handler structs hold `logger logger.CustomLogger` field
|
||||
- Service structs hold `logger logger.CustomLogger` field
|
||||
- Use structured fields: `zap.Field` variadic args
|
||||
- Exported methods: `Info`, `Error`, `Warn`, `Debug`
|
||||
- In tests, use `logger.NewCustomLogger(nil, logger.WithOutputInConsole())`
|
||||
## Comments
|
||||
## Function Design
|
||||
## Module Design
|
||||
- `internal/api/` → handlers only, thin, call services
|
||||
- `internal/service/` → business logic, call DAOs and other services
|
||||
- `internal/repository/mysql/` → data access via GORM DAOs (generated)
|
||||
- `internal/pkg/` → shared utilities, no business logic
|
||||
<!-- GSD:conventions-end -->
|
||||
|
||||
<!-- GSD:architecture-start source:ARCHITECTURE.md -->
|
||||
## Architecture
|
||||
|
||||
## Overview
|
||||
## Architectural Pattern
|
||||
```
|
||||
```
|
||||
## Key Layers
|
||||
### 1. Router Layer (`internal/router/`)
|
||||
- `router.go` — Single file defining all routes via `NewHTTPMux()`
|
||||
- Routes organized into groups:
|
||||
### 2. Interceptor / Middleware Layer (`internal/router/interceptor/`)
|
||||
- `admin_auth.go` — JWT token verification for admin users
|
||||
- `admin_rbac.go` — Role-based access control with action-level permissions
|
||||
- `app_auth.go` — App user token verification
|
||||
- `blacklist.go` — Douyin user blacklist checking
|
||||
- `interceptor.go` — Base interceptor struct with shared dependencies
|
||||
### 3. API Handler Layer (`internal/api/`)
|
||||
- `admin/` — Admin panel handlers (largest, ~30+ files)
|
||||
- `activity/` — Lottery/game activity handlers
|
||||
- `app/` — Store, product, banner, category handlers
|
||||
- `game/` — Game ticket and minesweeper handlers
|
||||
- `pay/` — Payment handlers
|
||||
- `user/` — User management, orders, addresses
|
||||
- `task_center/` — Task center handlers
|
||||
- `common/` — Shared utilities (upload, openid)
|
||||
- `public/` — Public livestream handlers
|
||||
- `internal/` — Internal API handlers (Nakama integration)
|
||||
### 4. Service Layer (`internal/service/`)
|
||||
- `activity/` — Activity CRUD, lottery processing, matching game, settlements, strategy pattern for draw types
|
||||
- `admin/` — Admin user management, login
|
||||
- `user/` — User management, orders, points, coupons, inventory, shipping, synthesis
|
||||
- `order/` — Order processing
|
||||
- `game/` — Game ticket management, minesweeper
|
||||
- `douyin/` — Douyin order sync, reward dispatching
|
||||
- `task_center/` — Task definitions, progress tracking, worker
|
||||
- `product/` — Product management
|
||||
- `finance/` — Financial operations, ledger
|
||||
- `channel/` — Marketing channel management
|
||||
- `title/` — User title/badge system
|
||||
- `banner/`, `sysconfig/`, `common/`, `snapshot/`, `recycle/`, `synthesis/`, `livestream/`
|
||||
### 5. Repository Layer (`internal/repository/mysql/`)
|
||||
- `mysql.go` — Database connection management (read/write split via `Repo` interface)
|
||||
- `plugin.go` — GORM plugins
|
||||
- `model/*.gen.go` — Generated GORM models (do not edit)
|
||||
- `dao/*.gen.go` — Generated GORM DAOs (do not edit)
|
||||
- `task_center/models.go` — Task center specific models
|
||||
- `test_helper.go`, `testrepo_sqlite.go` — Test infrastructure
|
||||
## Entry Point
|
||||
## Data Flow
|
||||
### Typical API Request Flow
|
||||
```
|
||||
```
|
||||
### Background Task Flow
|
||||
```
|
||||
```
|
||||
### Payment Flow
|
||||
```
|
||||
```
|
||||
## Key Design Decisions
|
||||
| Decision | Rationale |
|
||||
|----------|-----------|
|
||||
| Read/write DB split | Performance: heavy reads go to slave, writes to master |
|
||||
| GORM code generation | Consistency: models and DAOs auto-generated from schema |
|
||||
| Custom `core.Context` wrapper | Standardized error handling, tracing, session management across all handlers |
|
||||
| Strategy pattern for lottery | Different draw types (standard, ichiban) share interface but have different logic |
|
||||
| Background workers in main process | Simplicity: no separate worker binary, uses goroutines |
|
||||
| JWT with hash verification | Security: stored token hash prevents concurrent sessions |
|
||||
## Cross-Cutting Concerns
|
||||
- **Logging**: Zap-based with file rotation (`internal/pkg/logger/`)
|
||||
- **Tracing**: OpenTelemetry integration (`internal/pkg/otel/`)
|
||||
- **Error Codes**: 5-digit system in `internal/code/` (service level + module + specific)
|
||||
- **Alerts**: Alert notification system (`internal/alert/`)
|
||||
- **Metrics**: Prometheus metrics (`internal/metrics/`)
|
||||
## External Service Boundaries
|
||||
- WeChat Mini Program API (`wechat/`, `miniprogram/`)
|
||||
- WeChat Pay v3 API (`pay/`)
|
||||
- Douyin/TikTok API (`douyin/`)
|
||||
- Aliyun SMS (`sms/`)
|
||||
- Tencent COS (object storage)
|
||||
- OpenTelemetry collector
|
||||
<!-- GSD:architecture-end -->
|
||||
|
||||
<!-- GSD:workflow-start source:GSD defaults -->
|
||||
## GSD Workflow Enforcement
|
||||
|
||||
Before using Edit, Write, or other file-changing tools, start work through a GSD command so planning artifacts and execution context stay in sync.
|
||||
|
||||
Use these entry points:
|
||||
- `/gsd:quick` for small fixes, doc updates, and ad-hoc tasks
|
||||
- `/gsd:debug` for investigation and bug fixing
|
||||
- `/gsd:execute-phase` for planned phase work
|
||||
|
||||
Do not make direct repo edits outside a GSD workflow unless the user explicitly asks to bypass it.
|
||||
<!-- GSD:workflow-end -->
|
||||
|
||||
<!-- GSD:profile-start -->
|
||||
## Developer Profile
|
||||
|
||||
> Profile not yet configured. Run `/gsd:profile-user` to generate your developer profile.
|
||||
> This section is managed by `generate-claude-profile` -- do not edit manually.
|
||||
<!-- GSD:profile-end -->
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user