chore: seal Design Vision v1 and monorepo scaffold
Archive the differentiated YuXinGu product docs, AI engineering system, design contract, and Go/Vue scaffold. Next execution prioritizes Cece-parity over early innovation (see .ai/product/STRATEGY.md). Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
# Pattern: CRUD slice
|
||||
|
||||
For a resource `Foo`:
|
||||
|
||||
1. Migration `foo` table (`id, created_at, updated_at, deleted_at`, …)
|
||||
2. `model.Foo`
|
||||
3. `repository` methods: Get / List / Create / Update / SoftDelete
|
||||
4. `service` with authz + validation
|
||||
5. `handler` REST routes
|
||||
6. OpenAPI paths
|
||||
7. SDK methods + types
|
||||
8. UI only if user-facing
|
||||
|
||||
List endpoints always paginate (`page`, `page_size`, `total`).
|
||||
@@ -0,0 +1,37 @@
|
||||
# Pattern: Handler
|
||||
|
||||
## Responsibility
|
||||
|
||||
HTTP only: bind JSON/query → validate → call service interface → map errors to envelope.
|
||||
|
||||
## Shape
|
||||
|
||||
```go
|
||||
type ReportService interface {
|
||||
Decode(ctx context.Context, in DecodeInput) (*DecodeOutput, error)
|
||||
}
|
||||
|
||||
type ReportHandler struct {
|
||||
svc ReportService
|
||||
}
|
||||
|
||||
func (h *ReportHandler) Decode(c *gin.Context) {
|
||||
var req DecodeRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.Fail(c, 400, 10000, "invalid request")
|
||||
return
|
||||
}
|
||||
out, err := h.svc.Decode(c.Request.Context(), toInput(req))
|
||||
if err != nil {
|
||||
// map domain errors → codes
|
||||
response.Fail(c, 400, 30001, err.Error())
|
||||
return
|
||||
}
|
||||
response.OK(c, out)
|
||||
}
|
||||
```
|
||||
|
||||
## Never
|
||||
|
||||
- SQL here
|
||||
- Business unlock math here (belongs service)
|
||||
@@ -0,0 +1,13 @@
|
||||
# Pattern: JWT / Bearer
|
||||
|
||||
## Middleware
|
||||
|
||||
1. Read `Authorization: Bearer <token>`
|
||||
2. Parse/verify
|
||||
3. Put `user_id` into context
|
||||
4. Reject with code in 1xxxx if missing/invalid
|
||||
|
||||
## Service
|
||||
|
||||
Always take `userID` from context for mutating ops.
|
||||
Never trust body `user_id` from client for ownership.
|
||||
@@ -0,0 +1,22 @@
|
||||
# Pattern: Pagination
|
||||
|
||||
## Query
|
||||
|
||||
`?page=1&page_size=20`
|
||||
|
||||
Defaults: page=1, page_size=20, max page_size=100.
|
||||
|
||||
## Response data
|
||||
|
||||
```json
|
||||
{
|
||||
"list": [],
|
||||
"total": 0,
|
||||
"page": 1,
|
||||
"page_size": 20
|
||||
}
|
||||
```
|
||||
|
||||
## SQL
|
||||
|
||||
`LIMIT $n OFFSET $m` with bound params. Always return `total` via `COUNT(*)` (or approximate only with ADR).
|
||||
@@ -0,0 +1,24 @@
|
||||
# Pattern: Repository
|
||||
|
||||
## Responsibility
|
||||
|
||||
Persistence only. Parameterized SQL. Map rows ↔ model.
|
||||
|
||||
## Shape
|
||||
|
||||
```go
|
||||
func (r *ReportRepository) SaveReport(ctx context.Context, m *model.Report) error {
|
||||
const q = `INSERT INTO report (id, user_id, kind, payload, created_at, updated_at)
|
||||
VALUES ($1,$2,$3,$4,now(),now())`
|
||||
_, err := r.db.ExecContext(ctx, q, m.ID, m.UserID, m.Kind, m.Payload)
|
||||
if err != nil {
|
||||
return fmt.Errorf("insert report: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
## Never
|
||||
|
||||
- `SELECT *` in new code
|
||||
- Business policy (VIP checks) here — return data, let service decide
|
||||
@@ -0,0 +1,31 @@
|
||||
# Pattern: Service
|
||||
|
||||
## Responsibility
|
||||
|
||||
Business rules, authorization, orchestration, transactions.
|
||||
|
||||
## Shape
|
||||
|
||||
```go
|
||||
type ReportRepo interface {
|
||||
SaveReport(ctx context.Context, r *model.Report) error
|
||||
}
|
||||
|
||||
type ReportService struct {
|
||||
repo ReportRepo
|
||||
}
|
||||
|
||||
func (s *ReportService) Decode(ctx context.Context, in DecodeInput) (*DecodeOutput, error) {
|
||||
if err := in.Validate(); err != nil {
|
||||
return nil, fmt.Errorf("validate decode: %w", err)
|
||||
}
|
||||
// rules / engine
|
||||
// persist via repo
|
||||
return out, nil
|
||||
}
|
||||
```
|
||||
|
||||
## Never
|
||||
|
||||
- Import `gin`
|
||||
- Bypass repo with ad-hoc SQL drivers scattered around
|
||||
Reference in New Issue
Block a user