gorig-cli 1.0.24 → 1.0.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +112 -22
- package/commands/create.js +267 -112
- package/commands/doc.js +21 -8
- package/commands/init.js +316 -255
- package/commands/skill.js +55 -17
- package/package.json +1 -1
- package/templates/config.go.ejs +6 -5
- package/templates/config.yaml.ejs +3 -38
- package/templates/controller.go.ejs +11 -42
- package/templates/crud.controller.go.ejs +71 -0
- package/templates/crud.doc.md.ejs +60 -0
- package/templates/crud.dto.go.ejs +103 -0
- package/templates/crud.integration.init_test.go.ejs +17 -0
- package/templates/crud.integration_test.go.ejs +66 -0
- package/templates/crud.model.go.ejs +25 -0
- package/templates/crud.module.README.md.ejs +70 -0
- package/templates/crud.mongo.config.yaml.ejs +19 -0
- package/templates/crud.mysql.config.yaml.ejs +14 -0
- package/templates/crud.router.go.ejs +18 -0
- package/templates/crud.service.go.ejs +179 -0
- package/templates/crud.test.go.ejs +52 -0
- package/templates/dto.go.ejs +16 -0
- package/templates/gitignore.ejs +18 -49
- package/templates/hello.controller.go.ejs +19 -0
- package/templates/hello.router.go.ejs +12 -0
- package/templates/hello.service.go.ejs +31 -0
- package/templates/hello.test.go.ejs +34 -0
- package/templates/init.go.ejs +1 -27
- package/templates/main.go.ejs +2 -5
- package/templates/model.go.ejs +3 -4
- package/templates/project.README.md.ejs +35 -0
- package/templates/router.go.ejs +4 -8
- package/templates/service.go.ejs +25 -77
- package/templates/skills/gorig-backend/SKILL.md +89 -0
- package/templates/skills/gorig-backend/agents/openai.yaml +4 -0
- package/templates/skills/gorig-backend/assets/api-doc-template.md +59 -0
- package/templates/skills/gorig-backend/assets/gorig.gitignore +65 -0
- package/templates/skills/gorig-backend/assets/module-readme-template.md +58 -0
- package/templates/skills/gorig-backend/references/advanced-data-access.md +275 -0
- package/templates/skills/gorig-backend/references/auth-security.md +194 -0
- package/templates/skills/gorig-backend/references/business-scenarios.md +155 -0
- package/templates/skills/gorig-backend/references/cache.md +301 -0
- package/templates/skills/gorig-backend/references/capability-matrix.md +37 -0
- package/templates/skills/gorig-backend/references/configuration.md +48 -0
- package/templates/skills/gorig-backend/references/framework-api.md +190 -0
- package/templates/skills/gorig-backend/references/messaging.md +143 -0
- package/templates/skills/gorig-backend/references/onboarding-files.md +46 -0
- package/templates/skills/gorig-backend/references/outbound-http.md +162 -0
- package/templates/skills/gorig-backend/references/persistent-crud.md +332 -0
- package/templates/skills/gorig-backend/references/project-bootstrap.md +128 -0
- package/templates/skills/gorig-backend/references/scheduled-tasks.md +231 -0
- package/templates/skills/gorig-backend/references/service-lifecycle.md +51 -0
- package/templates/skills/gorig-backend/references/source-map.md +43 -0
- package/templates/skills/gorig-backend/references/source-policy.md +58 -0
- package/templates/skills/gorig-backend/references/sse.md +121 -0
- package/templates/skills/gorig-backend/references/testing.md +171 -0
- package/templates/skills/gorig-backend/scripts/check-source-links.sh +48 -0
- package/templates/skills/gorig-backend/scripts/detect-gorig-context.sh +67 -0
- package/templates/skills/gorig-backend/scripts/verify-basic-project.sh +108 -0
- package/npm_publish copy.sh +0 -65
- package/templates/internal.go.ejs +0 -49
- package/templates/req.go.ejs +0 -8
- package/templates/resp.go.ejs +0 -8
- package/templates/service.pub.go.ejs +0 -22
- package/templates/skills/claude/gorig-backend/SKILL.md +0 -766
- package/templates/skills/claude/gorig-backend/assets/api-doc-template.md +0 -50
- package/templates/skills/claude/gorig-backend/assets/module-readme-template.md +0 -46
- package/templates/skills/claude/gorig-backend/references/onboarding-files.md +0 -44
- package/templates/skills/codex/gorig-backend/SKILL.md +0 -766
- package/templates/skills/codex/gorig-backend/agents/openai.yaml +0 -4
- package/templates/skills/codex/gorig-backend/assets/api-doc-template.md +0 -50
- package/templates/skills/codex/gorig-backend/assets/module-readme-template.md +0 -46
- package/templates/skills/codex/gorig-backend/references/onboarding-files.md +0 -44
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Service Lifecycle
|
|
2
|
+
|
|
3
|
+
## Built-in Startup
|
|
4
|
+
|
|
5
|
+
Use one application entry point:
|
|
6
|
+
|
|
7
|
+
```go
|
|
8
|
+
func main() {
|
|
9
|
+
bootstrap.StartUp()
|
|
10
|
+
}
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
In the verified baseline, `bootstrap.StartUp()` registers the built-in HTTP service, prints registered routes, and calls `serv.Running()`.
|
|
14
|
+
|
|
15
|
+
Do not also register an application-specific service whose `Startup` and `Shutdown` are `httpx.Startup` and `httpx.Shutdown`; that creates duplicate lifecycle entries for one HTTP server.
|
|
16
|
+
|
|
17
|
+
## Registration Through Imports
|
|
18
|
+
|
|
19
|
+
Gorig projects commonly register routes, migrations, scheduled tasks, and services from package `init()` functions. Entry points use explicit blank imports to activate the intended packages:
|
|
20
|
+
|
|
21
|
+
```go
|
|
22
|
+
import _ "example.com/demo/domain"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Keep the import graph visible. Do not add a component import merely to make a package compile; every blank import changes application startup behavior.
|
|
26
|
+
|
|
27
|
+
## Custom Service
|
|
28
|
+
|
|
29
|
+
Register a distinct lifecycle component only when it owns a distinct resource:
|
|
30
|
+
|
|
31
|
+
```go
|
|
32
|
+
err := serv.RegisterService(serv.Service{
|
|
33
|
+
Code: "WORKER",
|
|
34
|
+
Startup: workerStartup,
|
|
35
|
+
Shutdown: workerShutdown,
|
|
36
|
+
})
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Requirements:
|
|
40
|
+
|
|
41
|
+
- Use a unique stable code.
|
|
42
|
+
- Return startup failures.
|
|
43
|
+
- Honor the shutdown context.
|
|
44
|
+
- Make shutdown idempotent.
|
|
45
|
+
- Do not rely on service map iteration order.
|
|
46
|
+
|
|
47
|
+
## Graceful Shutdown
|
|
48
|
+
|
|
49
|
+
The verified baseline waits for `os.Interrupt`, then gives registered services a five-second shutdown context. Test graceful shutdown with `SIGINT` and require the process to exit successfully.
|
|
50
|
+
|
|
51
|
+
Do not claim `SIGTERM` support without checking the resolved version; signal handling is version-specific.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Source Map
|
|
2
|
+
|
|
3
|
+
Prefer an exact version or commit over the moving `master` links below.
|
|
4
|
+
|
|
5
|
+
## Core Framework
|
|
6
|
+
|
|
7
|
+
- Repository: `https://github.com/jom-io/gorig`
|
|
8
|
+
- Startup: `https://github.com/jom-io/gorig/blob/master/bootstrap/startup.go`
|
|
9
|
+
- Service lifecycle: `https://github.com/jom-io/gorig/blob/master/serv/serv.go`
|
|
10
|
+
- HTTP: `https://github.com/jom-io/gorig/tree/master/httpx`
|
|
11
|
+
- API helpers: `https://github.com/jom-io/gorig/tree/master/apix`
|
|
12
|
+
- Data access: `https://github.com/jom-io/gorig/tree/master/domainx`
|
|
13
|
+
- dx facade: `https://github.com/jom-io/gorig/blob/master/domainx/dx/dx.go`
|
|
14
|
+
- Cache: `https://github.com/jom-io/gorig/tree/master/cache`
|
|
15
|
+
- Scheduled tasks: `https://github.com/jom-io/gorig/tree/master/cronx`
|
|
16
|
+
- Messaging: `https://github.com/jom-io/gorig/tree/master/mid/messagex`
|
|
17
|
+
- Authentication: `https://github.com/jom-io/gorig/tree/master/mid/tokenx`
|
|
18
|
+
- Auth middleware: `https://github.com/jom-io/gorig/blob/master/httpx/mid.sign.go`
|
|
19
|
+
- Security middleware: `https://github.com/jom-io/gorig/blob/master/httpx/mid.cors.go`, `https://github.com/jom-io/gorig/blob/master/httpx/mid.debounce.go`
|
|
20
|
+
- Outbound HTTP: `https://github.com/jom-io/gorig/blob/master/httpx/http.go`
|
|
21
|
+
- Tests: `https://github.com/jom-io/gorig/tree/master/test`
|
|
22
|
+
|
|
23
|
+
To inspect a release, replace `/master/` with the tag, for example `/v0.0.52/`, after confirming the tag exists.
|
|
24
|
+
|
|
25
|
+
## Ecosystem
|
|
26
|
+
|
|
27
|
+
- Service registry: `https://github.com/jom-io/gorig-hub`
|
|
28
|
+
- Service node/client: `https://github.com/jom-io/gorig-node`
|
|
29
|
+
- Operations and deployment: `https://github.com/jom-io/gorig-om`
|
|
30
|
+
|
|
31
|
+
Check each repository's `go.mod`; ecosystem projects may pin different Gorig versions.
|
|
32
|
+
|
|
33
|
+
## Local Sibling Discovery
|
|
34
|
+
|
|
35
|
+
When working inside a directory such as `<workspace>/gorig-cli`, check sibling directories only after resolving the target dependency:
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
find .. -maxdepth 2 -name go.mod -print
|
|
39
|
+
git -C ../gorig branch --show-current
|
|
40
|
+
git -C ../gorig log -1 --oneline
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Useful local examples may exist in business repositories, but they are evidence of usage, not a replacement for the framework API source. Avoid copying product-specific dependencies, secrets, or architecture without evaluating fit.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Source and Version Policy
|
|
2
|
+
|
|
3
|
+
Use this policy before selecting any Gorig API or example.
|
|
4
|
+
|
|
5
|
+
## Evidence Order
|
|
6
|
+
|
|
7
|
+
1. Read the target project's `go.mod` and all `replace` directives.
|
|
8
|
+
2. Prefer the exact resolved dependency source in the Go module cache.
|
|
9
|
+
3. Use a local sibling Gorig checkout only when it matches the project version or the task explicitly targets that checkout.
|
|
10
|
+
4. Use the matching public GitHub tag or commit for versioned work.
|
|
11
|
+
5. Use GitHub `master` only for explicit latest-version, framework-development, or upgrade work.
|
|
12
|
+
6. Use bundled examples only as offline fallbacks and re-check their signatures before editing.
|
|
13
|
+
|
|
14
|
+
## Required Version Report
|
|
15
|
+
|
|
16
|
+
Before a material change, report:
|
|
17
|
+
|
|
18
|
+
- Target module name and Go version.
|
|
19
|
+
- Required Gorig version or pseudo-version.
|
|
20
|
+
- Active `replace` target, if any.
|
|
21
|
+
- Source directory used for verification.
|
|
22
|
+
- Whether the work preserves the current version or upgrades it.
|
|
23
|
+
|
|
24
|
+
Do not silently run `go get ...@latest` in an existing project.
|
|
25
|
+
|
|
26
|
+
## Source Resolution
|
|
27
|
+
|
|
28
|
+
Run:
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
scripts/detect-gorig-context.sh /path/to/project
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
If the script cannot locate an exact source directory:
|
|
35
|
+
|
|
36
|
+
1. Run `go env GOMODCACHE` from the target project.
|
|
37
|
+
2. Use `go list -m -json github.com/jom-io/gorig` when dependencies are available.
|
|
38
|
+
3. Inspect a compatible local checkout.
|
|
39
|
+
4. Ask before downloading or upgrading dependencies when that changes external state.
|
|
40
|
+
|
|
41
|
+
## Compatibility Decisions
|
|
42
|
+
|
|
43
|
+
- Preserve the current dependency for feature work unless the user requests an upgrade or the requested capability is unavailable.
|
|
44
|
+
- Treat a pseudo-version as commit-specific. Do not substitute the nearest release without comparison.
|
|
45
|
+
- When local `master` differs from the resolved module, compare signatures and behavior explicitly.
|
|
46
|
+
- Prefer APIs already used by the target repository when both legacy and newer APIs exist.
|
|
47
|
+
- Mark version-dependent advice in code comments or delivery notes when future maintenance could otherwise misread it.
|
|
48
|
+
|
|
49
|
+
## Capability Maturity
|
|
50
|
+
|
|
51
|
+
Use these labels:
|
|
52
|
+
|
|
53
|
+
- `verified`: Confirmed by source plus a compiling or behavioral test for the selected version.
|
|
54
|
+
- `experimental`: Present in source but incomplete, risky, or lacking sufficient behavioral verification.
|
|
55
|
+
- `deprecated`: Explicitly deprecated by source or replaced by a preferred API.
|
|
56
|
+
- `unsupported`: Stubbed, absent, or known not to work for the required scenario.
|
|
57
|
+
|
|
58
|
+
Never convert `experimental` or `unsupported` into a working example without first proving it.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# Server-Sent Events
|
|
2
|
+
|
|
3
|
+
Use this reference when a task needs SSE streaming, event/error payloads, GET-only stream routes, disconnect handling, or message-to-SSE composition.
|
|
4
|
+
|
|
5
|
+
Always inspect the target project's resolved Gorig source first. The examples below reflect the locally inspected Gorig `master` commit `35bbefb`.
|
|
6
|
+
|
|
7
|
+
## Route Setup
|
|
8
|
+
|
|
9
|
+
Use `github.com/jom-io/gorig/httpx/ssex`.
|
|
10
|
+
|
|
11
|
+
```go
|
|
12
|
+
func init() {
|
|
13
|
+
httpx.RegisterRouter(func(root *gin.RouterGroup) {
|
|
14
|
+
root.GET("/orders/events", ssex.Mid(), streamOrderEvents)
|
|
15
|
+
})
|
|
16
|
+
}
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
`ssex.Mid()`:
|
|
20
|
+
|
|
21
|
+
- allows only `GET`,
|
|
22
|
+
- returns HTTP `405` JSON for non-GET requests,
|
|
23
|
+
- sets `Content-Type: text/event-stream`,
|
|
24
|
+
- sets `Cache-Control: no-cache`,
|
|
25
|
+
- sets `Connection: keep-alive`,
|
|
26
|
+
- sets `Access-Control-Allow-Origin: *`,
|
|
27
|
+
- flushes headers before calling the handler.
|
|
28
|
+
|
|
29
|
+
## Sending Events
|
|
30
|
+
|
|
31
|
+
```go
|
|
32
|
+
func streamOrderEvents(ctx *gin.Context) {
|
|
33
|
+
if err := ssex.SendOK(ctx, "ready", map[string]any{"ok": true}); err != nil {
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
if err := ssex.SendError(ctx, "warning", "temporary degraded state"); err != nil {
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The wire format is:
|
|
43
|
+
|
|
44
|
+
```text
|
|
45
|
+
event: ready
|
|
46
|
+
data: {"status":"ok","data":{"ok":true}}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Error events use:
|
|
50
|
+
|
|
51
|
+
```json
|
|
52
|
+
{"status":"error","message":"temporary degraded state"}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`SendOK` and `SendError` return ordinary Go errors from JSON encoding or response writing. Treat a write error as a disconnect or broken stream and stop sending.
|
|
56
|
+
|
|
57
|
+
## Long-Lived Streams
|
|
58
|
+
|
|
59
|
+
For long-lived streams, block on either application events or request cancellation:
|
|
60
|
+
|
|
61
|
+
```go
|
|
62
|
+
func stream(ctx *gin.Context) {
|
|
63
|
+
ticker := time.NewTicker(30 * time.Second)
|
|
64
|
+
defer ticker.Stop()
|
|
65
|
+
|
|
66
|
+
for {
|
|
67
|
+
select {
|
|
68
|
+
case <-ctx.Request.Context().Done():
|
|
69
|
+
return
|
|
70
|
+
case <-ticker.C:
|
|
71
|
+
if err := ssex.SendOK(ctx, "heartbeat", map[string]any{"ts": time.Now().Unix()}); err != nil {
|
|
72
|
+
return
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Rules:
|
|
80
|
+
|
|
81
|
+
- SSE endpoints must be `GET`.
|
|
82
|
+
- Do not call `apix.HandleData` after starting an SSE stream.
|
|
83
|
+
- Do not write unrelated JSON responses to the same stream.
|
|
84
|
+
- Always watch `ctx.Request.Context().Done()`.
|
|
85
|
+
- Keep per-connection goroutines bounded and unregister subscribers on disconnect.
|
|
86
|
+
|
|
87
|
+
## Message to SSE Composition
|
|
88
|
+
|
|
89
|
+
When the event source is `messagex`, register a subscriber for the connection and unregister it on exit:
|
|
90
|
+
|
|
91
|
+
```go
|
|
92
|
+
func streamOrderUpdates(ctx *gin.Context) {
|
|
93
|
+
broker := messagex.Ins(messagex.Local)
|
|
94
|
+
subID, err := broker.RegisterTopic("order.updated", func(msg *messagex.Message) *errors.Error {
|
|
95
|
+
if sendErr := ssex.SendOK(ctx, "order.updated", msg.Content); sendErr != nil {
|
|
96
|
+
return errors.Sys(sendErr.Error())
|
|
97
|
+
}
|
|
98
|
+
return nil
|
|
99
|
+
})
|
|
100
|
+
if err != nil {
|
|
101
|
+
_ = ssex.SendError(ctx, "order.updated", err.Error())
|
|
102
|
+
return
|
|
103
|
+
}
|
|
104
|
+
defer broker.UnRegisterTopic("order.updated", subID)
|
|
105
|
+
|
|
106
|
+
<-ctx.Request.Context().Done()
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
This simple pattern is appropriate for low-volume same-process streams. For high fan-out, backpressure, or cross-process delivery, design a bounded stream loop and verify Redis-backed messaging behavior.
|
|
111
|
+
|
|
112
|
+
## Verification Checklist
|
|
113
|
+
|
|
114
|
+
- Compile against the target project's resolved Gorig version.
|
|
115
|
+
- Verify GET responses include SSE headers.
|
|
116
|
+
- Verify non-GET requests return HTTP 405 with the framework error JSON.
|
|
117
|
+
- Verify `SendOK` writes the expected `event:` and JSON `status:"ok"` payload.
|
|
118
|
+
- Verify `SendError` writes `status:"error"` and message payload.
|
|
119
|
+
- Verify long-lived handlers exit on `ctx.Request.Context().Done()`.
|
|
120
|
+
- Verify write errors or disconnects stop the loop and unregister any message subscribers.
|
|
121
|
+
- For message-to-SSE, verify publish -> receive -> SSE event output and cleanup.
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# Testing and Effect Verification
|
|
2
|
+
|
|
3
|
+
Prefer repository-specific commands from `AGENTS.md`, CI, or existing scripts. Otherwise use the checks below.
|
|
4
|
+
|
|
5
|
+
## Standard Go Gates
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
go fmt ./...
|
|
9
|
+
go vet ./...
|
|
10
|
+
go build ./...
|
|
11
|
+
go test ./... -v -race -cover
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Narrow the test command while iterating, then run the full applicable suite before delivery.
|
|
15
|
+
|
|
16
|
+
## Test Placement
|
|
17
|
+
|
|
18
|
+
Prefer the project-level `test/` package for Gorig feature tests because it centralizes configuration, database setup, cache setup, and framework initialization. Add package-local tests only when the target project already follows that convention or the code under test has no Gorig initialization dependency.
|
|
19
|
+
|
|
20
|
+
## Effect Verification
|
|
21
|
+
|
|
22
|
+
Match verification to the delivered behavior:
|
|
23
|
+
|
|
24
|
+
- Business scenario: verify the observable business outcome, not only the framework primitive.
|
|
25
|
+
- Project bootstrap: start the binary, request `/ping`, then stop it gracefully.
|
|
26
|
+
- HTTP API: exercise success, required-parameter, invalid-parameter, not-found, and service-error responses.
|
|
27
|
+
- Database: verify migration/index creation plus read/write/update/delete and pagination.
|
|
28
|
+
- Cache: verify miss, hit, expiry, invalidation, and concurrency behavior.
|
|
29
|
+
- Cron: verify execution count, timeout, panic recovery, deduplication, and shutdown.
|
|
30
|
+
- Messaging: verify publish/consume, ordering, retry, DLQ, unsubscribe, and cross-process behavior when Redis-backed.
|
|
31
|
+
- SSE: verify event shape, error event, timeout, disconnect, and cleanup.
|
|
32
|
+
- Authentication and security: verify valid, missing, malformed, expired, refreshed, revoked/logout, and forbidden tokens; verify user and trace context, CORS preflight, debounce behavior, exception paths, and secret hygiene.
|
|
33
|
+
- Outbound HTTP: verify GET, form, JSON, XML, headers, context/header propagation, timeout, bad responses, malformed payloads, and image fetching against a local server.
|
|
34
|
+
- Deployment: verify startup, health, business endpoint, graceful stop, and rollback in a disposable target.
|
|
35
|
+
|
|
36
|
+
## External Infrastructure
|
|
37
|
+
|
|
38
|
+
Use disposable containers or explicitly supplied development services for MySQL, MongoDB, and Redis integration checks. Do not silently target shared or production infrastructure.
|
|
39
|
+
|
|
40
|
+
If required infrastructure is unavailable, keep the capability unverified and report the exact missing check.
|
|
41
|
+
|
|
42
|
+
## Business Scenario Tests
|
|
43
|
+
|
|
44
|
+
For ordinary user requests, write tests around the business behavior first, then prove the selected Gorig component supports it.
|
|
45
|
+
|
|
46
|
+
Examples:
|
|
47
|
+
|
|
48
|
+
- A "customer follow-up reminder" test should prove a customer without follow-up becomes pending follow-up after the delay, while a customer already followed up is not changed.
|
|
49
|
+
- A "send notification after order paid" test should prove the order-paid event triggers exactly the intended subscribers and is safe to retry.
|
|
50
|
+
- A "live progress page" test should prove the browser stream receives the expected event and subscriber cleanup happens on disconnect.
|
|
51
|
+
- A "speed up customer detail" test should prove cache miss, hit, invalidation after update, and fallback when cache is unavailable.
|
|
52
|
+
|
|
53
|
+
When the selected solution requires Redis, MySQL, MongoDB, or another external service, split tests into:
|
|
54
|
+
|
|
55
|
+
- ordinary tests for business decision logic and framework error paths, and
|
|
56
|
+
- integration tests for runtime delivery against disposable or explicitly supplied infrastructure.
|
|
57
|
+
|
|
58
|
+
Do not claim the business feature is verified when only the ordinary tests ran and the required integration service was unavailable.
|
|
59
|
+
|
|
60
|
+
## Advanced Data Access Tests
|
|
61
|
+
|
|
62
|
+
For advanced `domainx/dx` work:
|
|
63
|
+
|
|
64
|
+
- Ordinary compile and unit tests must cover query construction and service validation without external services when possible.
|
|
65
|
+
- MySQL and MongoDB behavior must be proven with tagged or container-backed integration tests before it is claimed verified.
|
|
66
|
+
- Verify optional filters with empty values and intentional zero values.
|
|
67
|
+
- Verify sorting, projection, count, sum, existence checks, pagination, update/delete guards, migrations, and indexes.
|
|
68
|
+
- Verify list/page implementations use database-backed filtering, sorting, and pagination. Do not accept tests that pass only because a small fixture was loaded into memory and sliced.
|
|
69
|
+
- Verify direct-driver escape hatches and transactions only against the backend where they are used.
|
|
70
|
+
- Record backend-specific differences and unsupported operations in delivery notes or module documentation.
|
|
71
|
+
|
|
72
|
+
## Cache Tests
|
|
73
|
+
|
|
74
|
+
For cache work:
|
|
75
|
+
|
|
76
|
+
- Memory, JSON, and SQLite cache behavior should run locally without Redis or database services.
|
|
77
|
+
- Verify miss, hit, expiry, delete, invalidation, counter, flush, and persistence when the backend is persistent.
|
|
78
|
+
- Verify multi-level cache by testing L1 miss, lower-layer hit backfill, full miss loader, delete across layers, and concurrent same-key loading.
|
|
79
|
+
- Redis behavior must run only with disposable or explicitly supplied Redis configuration.
|
|
80
|
+
- State whether cache is an acceleration layer or a source of state. Do not use cache as source of truth unless loss, expiry, and cross-process behavior are acceptable and tested.
|
|
81
|
+
|
|
82
|
+
## Generated Persistent CRUD Tests
|
|
83
|
+
|
|
84
|
+
For CLI-generated persistent CRUD modules:
|
|
85
|
+
|
|
86
|
+
- Keep validation tests in `test/<module>_test.go`; ordinary `go test ./...` must not require a database.
|
|
87
|
+
- Keep real database tests behind backend-specific build tags in `test/<module>_integration_test.go`.
|
|
88
|
+
- Initialize only the selected backend in `test/init_mysql_integration_test.go` or `test/init_mongo_integration_test.go`.
|
|
89
|
+
- Synchronize non-secret connection skeletons into `test/_bin/local.yaml`. Gorig tests normally read this file because the package working directory is `test/`.
|
|
90
|
+
- Run `go test -tags=integration,mysql ./test/... -v` or `go test -tags=integration,mongo ./test/... -v` after local connection values are available.
|
|
91
|
+
|
|
92
|
+
Never claim database behavior is verified merely because a tagged integration test compiles.
|
|
93
|
+
|
|
94
|
+
## Scheduled Task Tests
|
|
95
|
+
|
|
96
|
+
For `cronx` work:
|
|
97
|
+
|
|
98
|
+
- Prefer short deterministic schedules such as `@every 1s` in tests; keep the test bounded with channel waits or deadlines.
|
|
99
|
+
- Verify duplicate registration with a stable named function and the same spec.
|
|
100
|
+
- Verify timeout by asserting the handler observes `ctx.Done()`.
|
|
101
|
+
- Verify panic recovery by proving a later task still runs or the wrapper returns without terminating the process.
|
|
102
|
+
- Verify delay and once jobs run exactly once.
|
|
103
|
+
- Call `cronx.Shutdown("CRON", context.Background())` at the end of the test.
|
|
104
|
+
- Verify `AddEveryTask` registration returns promptly and the interval task executes when the target version includes commit `92c28b5` or an equivalent fix.
|
|
105
|
+
- For persistent delay tasks, verify handler registration rejects anonymous functions, scheduling rejects unregistered handlers, and non-JSON payloads fail before enqueue.
|
|
106
|
+
- Run persistent delay/once runtime tests only with disposable or explicitly supplied Redis. Assert payload delivery, timeout/failure behavior when relevant, task key cleanup, and worker shutdown.
|
|
107
|
+
|
|
108
|
+
## Messaging Tests
|
|
109
|
+
|
|
110
|
+
For `messagex` work:
|
|
111
|
+
|
|
112
|
+
- Use unique topic names per test and always unregister subscribers.
|
|
113
|
+
- Verify local publish/consume with typed getters because payload keys are lowercased.
|
|
114
|
+
- Verify multiple subscribers each receive the same published message.
|
|
115
|
+
- Verify sequential subscribers preserve publish order.
|
|
116
|
+
- Verify retry and DLQ behavior with `RegisterTopicSeq`.
|
|
117
|
+
- Verify unsubscribe by publishing after unregister and asserting no new delivery occurs.
|
|
118
|
+
- Verify local `ReplayDLQ` returns the expected store-not-initialized error; verify replay behavior only with Redis configured.
|
|
119
|
+
- Run Redis broker checks only against disposable or explicitly supplied Redis configuration.
|
|
120
|
+
|
|
121
|
+
## SSE Tests
|
|
122
|
+
|
|
123
|
+
For SSE work:
|
|
124
|
+
|
|
125
|
+
- Use `httptest` for header and payload verification.
|
|
126
|
+
- Verify GET streams return `Content-Type: text/event-stream`.
|
|
127
|
+
- Verify non-GET requests return HTTP 405 and the framework JSON body.
|
|
128
|
+
- Verify `SendOK` and `SendError` event shapes.
|
|
129
|
+
- For long-lived streams, cancel the request context and assert the handler exits.
|
|
130
|
+
- For message-to-SSE composition, verify subscriber cleanup on disconnect.
|
|
131
|
+
|
|
132
|
+
## Authentication and Security Tests
|
|
133
|
+
|
|
134
|
+
For auth/security work:
|
|
135
|
+
|
|
136
|
+
- Build a minimal login -> protected route -> logout flow in tests or smoke routes.
|
|
137
|
+
- Use `tokenx.Get(tokenx.Jwt, tokenx.Memory)` for simple local single-process auth tests. Use `tokenx.Get(tokenx.Jwt, tokenx.Redis)` and `httpx.SignRedis()` when the target version includes `mid/tokenx/redis.manager.go` or an equivalent Redis manager implementation and the business needs Redis-backed token state.
|
|
138
|
+
- For Gorig `master` and releases containing `test/tokenx_redis_test.go`, run `go test ./test -run TestRedisTokenManager -v` when Redis is configured. If the test skips with `redis is not configured`, report the missing Redis configuration and rerun after Redis is provided; do not downgrade the capability to memory token unless the user accepts that behavior change.
|
|
139
|
+
- Verify valid token success and that protected handlers read user id from `apix.GetUserID`, not from request input.
|
|
140
|
+
- Verify missing header, malformed `Authorization`, expired JWT through `IsNotExpired`/`IsEffective`, destroyed token, refreshed old token, refreshed new token, and forbidden role/attribute. Also verify protected-route behavior for manager-expired or unrecorded tokens according to the resolved version.
|
|
141
|
+
- Verify middleware writes user id into both gin context and request context, and trace context remains available.
|
|
142
|
+
- Verify CORS `OPTIONS` response status, origin, credentials, and allowed headers.
|
|
143
|
+
- Verify debounce returns HTTP 429 for repeated requests within the window and allows whitelisted paths.
|
|
144
|
+
- Scan generated examples and fixtures for real-looking secrets, raw bearer tokens, production hosts, and passwords.
|
|
145
|
+
|
|
146
|
+
## Outbound HTTP Tests
|
|
147
|
+
|
|
148
|
+
For outbound client work:
|
|
149
|
+
|
|
150
|
+
- Use `httptest.Server` or a controlled local server, not a real third-party API.
|
|
151
|
+
- Assert query parameters for `Get`/`GetHeader`.
|
|
152
|
+
- Assert form body and content type for `PostForm`.
|
|
153
|
+
- Assert JSON body and response parsing for `PostJSONResp` or `PostJSON`.
|
|
154
|
+
- Assert XML body and parse behavior; wrap `ParseXML` when malformed XML is expected.
|
|
155
|
+
- Assert custom headers and intentional `Authorization` forwarding through context-aware helpers.
|
|
156
|
+
- Exercise timeout using a slow handler and a bounded client/helper.
|
|
157
|
+
- Exercise non-success status and malformed JSON/XML response behavior.
|
|
158
|
+
- Exercise `FetchImage` only with a controlled local image response, and document size/content-type/host boundaries when user URLs are accepted.
|
|
159
|
+
|
|
160
|
+
## Delivery Evidence
|
|
161
|
+
|
|
162
|
+
Report:
|
|
163
|
+
|
|
164
|
+
- Exact command.
|
|
165
|
+
- Exit status.
|
|
166
|
+
- Important output or assertion.
|
|
167
|
+
- Environment and dependency version.
|
|
168
|
+
- Skipped checks and reason.
|
|
169
|
+
- Known limitations discovered during verification.
|
|
170
|
+
|
|
171
|
+
"Tests passed" without commands and effect evidence is insufficient.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
set -eu
|
|
3
|
+
|
|
4
|
+
skill_dir=$(CDPATH= cd -- "$(dirname "$0")/.." && pwd)
|
|
5
|
+
online=${1:-}
|
|
6
|
+
|
|
7
|
+
required_files="
|
|
8
|
+
$skill_dir/SKILL.md
|
|
9
|
+
$skill_dir/references/source-policy.md
|
|
10
|
+
$skill_dir/references/onboarding-files.md
|
|
11
|
+
$skill_dir/references/capability-matrix.md
|
|
12
|
+
$skill_dir/references/framework-api.md
|
|
13
|
+
$skill_dir/references/project-bootstrap.md
|
|
14
|
+
$skill_dir/references/configuration.md
|
|
15
|
+
$skill_dir/references/service-lifecycle.md
|
|
16
|
+
$skill_dir/references/testing.md
|
|
17
|
+
$skill_dir/references/source-map.md
|
|
18
|
+
$skill_dir/assets/api-doc-template.md
|
|
19
|
+
$skill_dir/assets/module-readme-template.md
|
|
20
|
+
$skill_dir/scripts/detect-gorig-context.sh
|
|
21
|
+
$skill_dir/scripts/verify-basic-project.sh
|
|
22
|
+
"
|
|
23
|
+
|
|
24
|
+
for file in $required_files; do
|
|
25
|
+
if [ ! -f "$file" ]; then
|
|
26
|
+
echo "missing=$file" >&2
|
|
27
|
+
exit 1
|
|
28
|
+
fi
|
|
29
|
+
done
|
|
30
|
+
|
|
31
|
+
echo "local_sources=ok"
|
|
32
|
+
|
|
33
|
+
if [ "$online" != "--online" ]; then
|
|
34
|
+
echo "online_sources=skipped"
|
|
35
|
+
exit 0
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
if ! command -v curl >/dev/null 2>&1; then
|
|
39
|
+
echo "error=curl is required for --online" >&2
|
|
40
|
+
exit 1
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
urls=$(sed -n 's/.*`\(https:\/\/github\.com\/[^`]*\)`.*/\1/p' "$skill_dir/references/source-map.md")
|
|
44
|
+
printf '%s\n' "$urls" | xargs -n 1 -P 4 sh -c '
|
|
45
|
+
url=$1
|
|
46
|
+
curl --fail --silent --show-error --location --range 0-0 --connect-timeout 10 --max-time 20 "$url" >/dev/null
|
|
47
|
+
echo "online_source=ok $url"
|
|
48
|
+
' _
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
set -eu
|
|
3
|
+
|
|
4
|
+
project_root=${1:-.}
|
|
5
|
+
|
|
6
|
+
if [ ! -d "$project_root" ]; then
|
|
7
|
+
echo "error=project directory not found: $project_root" >&2
|
|
8
|
+
exit 1
|
|
9
|
+
fi
|
|
10
|
+
|
|
11
|
+
project_root=$(cd "$project_root" && pwd)
|
|
12
|
+
go_mod="$project_root/go.mod"
|
|
13
|
+
|
|
14
|
+
if [ ! -f "$go_mod" ]; then
|
|
15
|
+
printf 'project_root=%s\n' "$project_root"
|
|
16
|
+
echo "go_mod=missing"
|
|
17
|
+
exit 2
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
module_name=$(awk '$1 == "module" { print $2; exit }' "$go_mod")
|
|
21
|
+
go_version=$(awk '$1 == "go" { print $2; exit }' "$go_mod")
|
|
22
|
+
gorig_version=$(awk '$1 == "github.com/jom-io/gorig" { print $2; exit }' "$go_mod")
|
|
23
|
+
replace_target=$(awk '
|
|
24
|
+
$1 == "replace" && $2 == "github.com/jom-io/gorig" && $3 == "=>" { print $4; exit }
|
|
25
|
+
in_replace && $1 == "github.com/jom-io/gorig" && $2 == "=>" { print $3; exit }
|
|
26
|
+
$1 == "replace" && $2 == "(" { in_replace = 1; next }
|
|
27
|
+
in_replace && $1 == ")" { in_replace = 0 }
|
|
28
|
+
' "$go_mod")
|
|
29
|
+
|
|
30
|
+
source_kind=unresolved
|
|
31
|
+
source_dir=
|
|
32
|
+
|
|
33
|
+
case "$replace_target" in
|
|
34
|
+
./*|../*|/*)
|
|
35
|
+
if [ "${replace_target#/}" != "$replace_target" ]; then
|
|
36
|
+
candidate=$replace_target
|
|
37
|
+
else
|
|
38
|
+
candidate="$project_root/$replace_target"
|
|
39
|
+
fi
|
|
40
|
+
if [ -d "$candidate" ]; then
|
|
41
|
+
source_kind=replace
|
|
42
|
+
source_dir=$(cd "$candidate" && pwd)
|
|
43
|
+
fi
|
|
44
|
+
;;
|
|
45
|
+
esac
|
|
46
|
+
|
|
47
|
+
if [ -z "$source_dir" ] && [ -n "$gorig_version" ] && command -v go >/dev/null 2>&1; then
|
|
48
|
+
module_cache=$(cd "$project_root" && go env GOMODCACHE 2>/dev/null || true)
|
|
49
|
+
candidate="$module_cache/github.com/jom-io/gorig@$gorig_version"
|
|
50
|
+
if [ -d "$candidate" ]; then
|
|
51
|
+
source_kind=module_cache
|
|
52
|
+
source_dir=$candidate
|
|
53
|
+
fi
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
if [ -z "$source_dir" ] && [ -d "$project_root/../gorig" ]; then
|
|
57
|
+
source_kind=sibling
|
|
58
|
+
source_dir=$(cd "$project_root/../gorig" && pwd)
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
printf 'project_root=%s\n' "$project_root"
|
|
62
|
+
printf 'module=%s\n' "${module_name:-unknown}"
|
|
63
|
+
printf 'go_version=%s\n' "${go_version:-unknown}"
|
|
64
|
+
printf 'gorig_version=%s\n' "${gorig_version:-not_required}"
|
|
65
|
+
printf 'replace=%s\n' "${replace_target:-none}"
|
|
66
|
+
printf 'source_kind=%s\n' "$source_kind"
|
|
67
|
+
printf 'source_dir=%s\n' "${source_dir:-not_found}"
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
set -eu
|
|
3
|
+
|
|
4
|
+
project_root=${1:-.}
|
|
5
|
+
mode=${2:-local}
|
|
6
|
+
|
|
7
|
+
case "$mode" in
|
|
8
|
+
local|dev|prod) ;;
|
|
9
|
+
*)
|
|
10
|
+
echo "error=mode must be local, dev, or prod" >&2
|
|
11
|
+
exit 1
|
|
12
|
+
;;
|
|
13
|
+
esac
|
|
14
|
+
|
|
15
|
+
project_root=$(cd "$project_root" && pwd)
|
|
16
|
+
config="$project_root/_bin/$mode.yaml"
|
|
17
|
+
|
|
18
|
+
if [ ! -f "$project_root/go.mod" ] || [ ! -f "$config" ]; then
|
|
19
|
+
echo "error=not a generated Gorig project or configuration missing" >&2
|
|
20
|
+
exit 1
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
port=$(sed -n 's/^[[:space:]]*addr:[[:space:]]*":\([0-9][0-9]*\)"[[:space:]]*$/\1/p' "$config" | head -n 1)
|
|
24
|
+
if [ -z "$port" ]; then
|
|
25
|
+
echo "error=unable to read api.rest.addr from $config" >&2
|
|
26
|
+
exit 1
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
cache_root=${GOCACHE:-/tmp/gorig-skill-go-cache}
|
|
30
|
+
binary="$project_root/.cache/verify-basic-project"
|
|
31
|
+
log_file="$project_root/.cache/verify-basic-project-$mode.log"
|
|
32
|
+
pid=
|
|
33
|
+
|
|
34
|
+
cleanup() {
|
|
35
|
+
status=$?
|
|
36
|
+
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
|
|
37
|
+
kill -INT "$pid" 2>/dev/null || true
|
|
38
|
+
wait "$pid" 2>/dev/null || true
|
|
39
|
+
fi
|
|
40
|
+
return "$status"
|
|
41
|
+
}
|
|
42
|
+
trap cleanup EXIT INT TERM
|
|
43
|
+
|
|
44
|
+
mkdir -p "$project_root/.cache"
|
|
45
|
+
|
|
46
|
+
unformatted=$(cd "$project_root" && gofmt -l .)
|
|
47
|
+
if [ -n "$unformatted" ]; then
|
|
48
|
+
echo "error=unformatted Go files" >&2
|
|
49
|
+
echo "$unformatted" >&2
|
|
50
|
+
exit 1
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
(cd "$project_root" && GOCACHE="$cache_root" go vet ./...)
|
|
54
|
+
(cd "$project_root" && GOCACHE="$cache_root" go build -o "$binary" ./_cmd)
|
|
55
|
+
(cd "$project_root" && GOCACHE="$cache_root" go test ./... -v)
|
|
56
|
+
|
|
57
|
+
previous_dir=$(pwd)
|
|
58
|
+
cd "$project_root"
|
|
59
|
+
GORIG_SYS_MODE="$mode" "$binary" >"$log_file" 2>&1 &
|
|
60
|
+
pid=$!
|
|
61
|
+
cd "$previous_dir"
|
|
62
|
+
|
|
63
|
+
base_url="http://127.0.0.1:$port"
|
|
64
|
+
ready=false
|
|
65
|
+
ping_response=
|
|
66
|
+
attempt=0
|
|
67
|
+
while [ "$attempt" -lt 40 ]; do
|
|
68
|
+
if ping_response=$(curl --fail --silent --max-time 2 "$base_url/ping" 2>/dev/null); then
|
|
69
|
+
ready=true
|
|
70
|
+
break
|
|
71
|
+
fi
|
|
72
|
+
if ! kill -0 "$pid" 2>/dev/null; then
|
|
73
|
+
echo "error=project exited before becoming ready" >&2
|
|
74
|
+
cat "$log_file" >&2
|
|
75
|
+
exit 1
|
|
76
|
+
fi
|
|
77
|
+
attempt=$((attempt + 1))
|
|
78
|
+
sleep 0.25
|
|
79
|
+
done
|
|
80
|
+
|
|
81
|
+
if [ "$ready" != true ]; then
|
|
82
|
+
echo "error=project did not become ready on $base_url" >&2
|
|
83
|
+
cat "$log_file" >&2
|
|
84
|
+
exit 1
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
hello_response=$(curl --fail --silent --max-time 5 "$base_url/hello?name=Gorig")
|
|
88
|
+
|
|
89
|
+
echo "$ping_response" | grep '"code":200' > /dev/null
|
|
90
|
+
echo "$hello_response" | grep '"code":200' > /dev/null
|
|
91
|
+
echo "$hello_response" | grep "\"mode\":\"$mode\"" > /dev/null
|
|
92
|
+
echo "$hello_response" | grep '"message":"hello Gorig"' > /dev/null
|
|
93
|
+
|
|
94
|
+
kill -INT "$pid"
|
|
95
|
+
if ! wait "$pid"; then
|
|
96
|
+
echo "error=project did not shut down cleanly" >&2
|
|
97
|
+
cat "$log_file" >&2
|
|
98
|
+
exit 1
|
|
99
|
+
fi
|
|
100
|
+
pid=
|
|
101
|
+
|
|
102
|
+
grep 'Shutting down the system \[OK\]' "$log_file" > /dev/null
|
|
103
|
+
|
|
104
|
+
echo "mode=$mode"
|
|
105
|
+
echo "base_url=$base_url"
|
|
106
|
+
echo "ping=$ping_response"
|
|
107
|
+
echo "hello=$hello_response"
|
|
108
|
+
echo "graceful_shutdown=ok"
|