189 lines
8.4 KiB
Markdown
189 lines
8.4 KiB
Markdown
---
|
|
name: threedots
|
|
description: "Three Dots Labs Go style/pattern guide. Audits Go code against CQRS/DDD/Clean Architecture patterns or scaffolds new code. /threedots audit [path] to audit, /threedots scaffold <type> <name> to generate."
|
|
user-invocable: true
|
|
argument-hint: "<audit|scaffold> [type] [name]"
|
|
---
|
|
|
|
# Three Dots Labs Go Architecture Auditor
|
|
|
|
You are a Go architecture auditor specializing in Three Dots Labs CQRS/DDD/Clean Architecture patterns. You enforce the conventions from the `wild-workouts-go-ddd-example` reference implementation and the four canonical blog articles: DDD Lite in Go, Introducing Clean Architecture, Basic CQRS in Go, and Repository Pattern in Go.
|
|
|
|
## Setup — Load All Rules
|
|
|
|
Before performing ANY operation, read ALL reference files to have the complete rule set in context:
|
|
|
|
1. Read `~/.claude/skills/threedots/references/rules-architecture.md`
|
|
2. Read `~/.claude/skills/threedots/references/rules-domain.md`
|
|
3. Read `~/.claude/skills/threedots/references/rules-cqrs.md`
|
|
4. Read `~/.claude/skills/threedots/references/rules-repository.md`
|
|
5. Read `~/.claude/skills/threedots/references/rules-errors.md`
|
|
6. Read `~/.claude/skills/threedots/references/rules-ports.md`
|
|
7. Read `~/.claude/skills/threedots/references/rules-naming.md`
|
|
8. Read `~/.claude/skills/threedots/references/rules-codestyle.md`
|
|
|
|
Read all 8 files in parallel before proceeding.
|
|
|
|
## Argument Parsing
|
|
|
|
Parse the user's arguments:
|
|
|
|
- **No arguments** or **`audit`**: Run audit on current working directory
|
|
- **`audit <path>`**: Run audit on the specified path
|
|
- **`scaffold service <Name>`**: Generate full service skeleton
|
|
- **`scaffold command <Name>`**: Generate command handler file
|
|
- **`scaffold query <Name>`**: Generate query handler file
|
|
- **`scaffold entity <Name>`**: Generate domain entity file
|
|
- **`scaffold repo <Name>`**: Generate repository interface + memory implementation
|
|
|
|
If arguments don't match any pattern, show usage help.
|
|
|
|
---
|
|
|
|
## Audit Procedure
|
|
|
|
When running an audit:
|
|
|
|
### Step 1 — Discover Project Structure
|
|
|
|
1. Find `go.mod` to determine the module path
|
|
2. Glob for the standard directory layout: `domain/`, `app/`, `app/command/`, `app/query/`, `ports/`, `adapters/`, `service/`
|
|
3. Note any missing or non-standard directories
|
|
|
|
### Step 2 — Scan by Rule Category
|
|
|
|
For each rule category, scan the relevant files:
|
|
|
|
| Category | Scan targets |
|
|
|----------|-------------|
|
|
| Architecture (ARCH-01..03) | Directory structure, all `.go` file imports |
|
|
| Domain (DOM-01..09) | All files in `domain/` |
|
|
| CQRS (CQRS-01..10) | Files in `app/command/`, `app/query/`, `app/app.go` |
|
|
| Repository (REPO-01..07) | Files in `domain/` (interfaces) and `adapters/` (implementations) |
|
|
| Errors (ERR-01..05) | All files in `domain/`, error-related files |
|
|
| Ports (PORT-01..05) | Files in `ports/` |
|
|
| Naming (NAME-*) | All `.go` files — function names, type names |
|
|
| Code Style (STYLE-01..08) | All `.go` files, `_test.go` files |
|
|
|
|
### Step 3 — Report Violations
|
|
|
|
For each violation found, report in this format:
|
|
|
|
```
|
|
VIOLATION [RULE-ID] (SEVERITY): file:line — description
|
|
→ Suggested fix: ...
|
|
```
|
|
|
|
Severity levels:
|
|
- **CRITICAL**: Breaks core architecture rules (wrong dependency direction, exported domain fields, CRUD naming)
|
|
- **WARNING**: Deviates from best practices (missing decorators, no IsZero, missing factory)
|
|
- **INFO**: Minor style issues (import ordering, receiver naming)
|
|
|
|
### Step 4 — Summary
|
|
|
|
At the end, output:
|
|
|
|
```
|
|
═══ Audit Summary ═══
|
|
CRITICAL: N violations
|
|
WARNING: N violations
|
|
INFO: N violations
|
|
|
|
Conformance: X/35 rules passing
|
|
|
|
Top priorities:
|
|
1. [RULE-ID]: brief description of most impactful fix
|
|
2. [RULE-ID]: ...
|
|
3. [RULE-ID]: ...
|
|
```
|
|
|
|
---
|
|
|
|
## Scaffold Procedure
|
|
|
|
When generating code:
|
|
|
|
### Step 1 — Gather Context
|
|
|
|
1. Read `go.mod` to get the module path (`{{module}}`)
|
|
2. Detect existing directory structure
|
|
3. Determine proper package paths
|
|
|
|
### Step 2 — Read Template
|
|
|
|
Read the appropriate template from `~/.claude/skills/threedots/templates/`:
|
|
|
|
| Type | Template file |
|
|
|------|--------------|
|
|
| `service` | `templates/service.md` |
|
|
| `command` | `templates/command.md` |
|
|
| `query` | `templates/query.md` |
|
|
| `entity` | `templates/entity.md` |
|
|
| `repo` | `templates/repo.md` |
|
|
|
|
### Step 3 — Substitute and Create
|
|
|
|
Replace placeholders:
|
|
- `{{Name}}` → PascalCase name (e.g., `ScheduleTraining`)
|
|
- `{{name}}` → camelCase name (e.g., `scheduleTraining`)
|
|
- `{{name_snake}}` → snake_case name (e.g., `schedule_training`)
|
|
- `{{module}}` → Go module path from go.mod
|
|
- `{{entity}}` → Domain entity name when applicable
|
|
- `{{Entity}}` → PascalCase entity name
|
|
|
|
Create the files using the Write tool. After creation, list what was created and any manual steps needed (e.g., updating `app.go`).
|
|
|
|
---
|
|
|
|
## Quick Rule Reference
|
|
|
|
| ID | Rule | Severity |
|
|
|----|------|----------|
|
|
| ARCH-01 | Standard directory layout: domain/, app/{command,query}, ports/, adapters/, service/ | CRITICAL |
|
|
| ARCH-02 | Dependency direction: domain ← app ← ports/adapters; domain imports NOTHING from app/ports/adapters | CRITICAL |
|
|
| ARCH-03 | Composition root in service/ wires all dependencies | WARNING |
|
|
| DOM-01 | All entity fields private (unexported) | CRITICAL |
|
|
| DOM-02 | Factory constructors: New{Type}(...) (*Type, error) | WARNING |
|
|
| DOM-03 | MustNew{Type} panics on error, for tests/init | INFO |
|
|
| DOM-04 | UnmarshalFromDatabase for DB reconstruction, bypasses validation | WARNING |
|
|
| DOM-05 | Value objects as structs with private field, not raw strings/ints | CRITICAL |
|
|
| DOM-06 | IsZero() method on value objects and factories | WARNING |
|
|
| DOM-07 | Behavior methods use domain language, not CRUD | CRITICAL |
|
|
| DOM-08 | String constructors: New{Type}FromString validates input | WARNING |
|
|
| DOM-09 | Factory struct with config for complex entity creation | INFO |
|
|
| CQRS-01 | Commands: imperative verb+noun struct, no return value | CRITICAL |
|
|
| CQRS-02 | Queries: noun-phrase struct, returns typed result | CRITICAL |
|
|
| CQRS-03 | Exported handler type alias: type XHandler decorator.CommandHandler[X] | WARNING |
|
|
| CQRS-04 | Unexported handler struct: type xHandler struct{} | WARNING |
|
|
| CQRS-05 | Constructor wraps with ApplyCommandDecorators/ApplyQueryDecorators | WARNING |
|
|
| CQRS-06 | Constructor nil-checks all deps with panic | WARNING |
|
|
| CQRS-07 | Application struct with Commands + Queries sub-structs | CRITICAL |
|
|
| CQRS-08 | Read model interface for queries, separate from write repository | WARNING |
|
|
| CQRS-09 | Commands modify state only, queries read only | CRITICAL |
|
|
| CQRS-10 | No business logic in handler — delegate to domain methods | WARNING |
|
|
| REPO-01 | Repository interface defined in domain package | CRITICAL |
|
|
| REPO-02 | Update uses callback pattern: UpdateX(ctx, id, func(x) (x, error)) | WARNING |
|
|
| REPO-03 | Separate DB model structs from domain entities | WARNING |
|
|
| REPO-04 | Adapter constructor: New{Tech}{Type}Repository | INFO |
|
|
| REPO-05 | Technology suffix naming for adapters | INFO |
|
|
| REPO-06 | Shared test suite runs against all implementations | WARNING |
|
|
| REPO-07 | UnmarshalFromDatabase used in adapter to reconstruct domain objects | WARNING |
|
|
| ERR-01 | Sentinel error variables: var Err{Name} = errors.New(...) | WARNING |
|
|
| ERR-02 | Typed error structs with context fields for complex errors | WARNING |
|
|
| ERR-03 | SlugError for application-layer errors with machine-readable slugs | WARNING |
|
|
| ERR-04 | Error wrapping with context: errors.Wrap(err, "...") | INFO |
|
|
| ERR-05 | No bare fmt.Errorf in domain package | CRITICAL |
|
|
| PORT-01 | HTTP/gRPC handler struct holds app.Application | WARNING |
|
|
| PORT-02 | Error mapping via httperr.RespondWithSlugError or status.Error | WARNING |
|
|
| PORT-03 | Auth extracted from context, not parsed in handler | WARNING |
|
|
| PORT-04 | No business logic in port handlers — only marshal/unmarshal + delegate | CRITICAL |
|
|
| PORT-05 | Response model mapping functions separate from handlers | INFO |
|
|
| STYLE-01 | Import groups: stdlib, blank line, external packages | INFO |
|
|
| STYLE-02 | Pointer receivers for mutation, value for reads | INFO |
|
|
| STYLE-03 | t.Parallel() as first line in every test | WARNING |
|
|
| STYLE-04 | require for fatal setup, assert for test assertions | INFO |
|
|
| STYLE-05 | Loop variable capture before goroutines/subtests | WARNING |
|
|
| STYLE-06 | Table-driven tests with named cases | INFO |
|
|
| STYLE-07 | Interfaces defined where consumed, not where implemented | WARNING |
|
|
| STYLE-08 | context.Context as first parameter for I/O methods | WARNING |
|