@shahmilsaari/memory-core 0.2.10 → 0.2.11
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 +1 -1
- package/dist/cli.js +29 -29
- package/package.json +1 -1
- package/profiles/go-api.yml +43 -0
- package/profiles/nextjs.yml +0 -32
package/README.md
CHANGED
|
@@ -518,7 +518,7 @@ Pick the one that matches how your project is structured.
|
|
|
518
518
|
| Modular Monolith | You're building feature modules that might become microservices later |
|
|
519
519
|
| MVC | Standard web app with controllers and services |
|
|
520
520
|
| Hexagonal | You want ports and adapters for maximum testability |
|
|
521
|
-
|
|
|
521
|
+
| Go REST API | Go backend API with idiomatic error handling and clean package structure |
|
|
522
522
|
| Laravel | Laravel with service-repository pattern |
|
|
523
523
|
| NestJS | Modules, guards, pipes, DTOs, repository pattern |
|
|
524
524
|
|
package/dist/cli.js
CHANGED
|
@@ -332,30 +332,34 @@ var seeds = [
|
|
|
332
332
|
{ type: "rule", scope: "global", architecture: "hexagonal", title: "Port naming convention", content: "Name ports as I + [Action] + [Resource]: ICreateUser, IFindOrderById, ISendEmail. Adapters use the technology name: PostgresCreateUser, StripeCharge.", tags: ["naming", "ports", "hexagonal"] },
|
|
333
333
|
{ type: "decision", scope: "global", architecture: "hexagonal", title: "Test core without infrastructure", content: "Core unit tests run in milliseconds with no DB or network. Integration tests add adapters one at a time. E2E tests use real infrastructure.", tags: ["testing", "hexagonal"] },
|
|
334
334
|
// ══════════════════════════════════════════════════════════════════════════
|
|
335
|
-
//
|
|
335
|
+
// GO REST API
|
|
336
336
|
// ══════════════════════════════════════════════════════════════════════════
|
|
337
|
-
// ──
|
|
338
|
-
{ type: "rule", scope: "global", architecture: "
|
|
339
|
-
{ type: "rule", scope: "global", architecture: "
|
|
340
|
-
{ type: "rule", scope: "global", architecture: "
|
|
341
|
-
{ type: "rule", scope: "global", architecture: "
|
|
342
|
-
|
|
343
|
-
{ type: "
|
|
344
|
-
|
|
345
|
-
{ type: "rule", scope: "global", architecture: "
|
|
346
|
-
{ type: "
|
|
347
|
-
|
|
348
|
-
{ type: "rule", scope: "global", architecture: "
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
{ type: "rule", scope: "global", architecture: "
|
|
352
|
-
{ type: "rule", scope: "global", architecture: "
|
|
353
|
-
// ──
|
|
354
|
-
{ type: "rule", scope: "global", architecture: "
|
|
355
|
-
{ type: "rule", scope: "global", architecture: "
|
|
356
|
-
|
|
357
|
-
{ type: "
|
|
358
|
-
{ type: "
|
|
337
|
+
// ── Package Structure ────────────────────────────────────────────────────
|
|
338
|
+
{ type: "rule", scope: "global", architecture: "go-api", title: "cmd/internal/pkg layout", content: "Organize code into cmd/ (main packages), internal/ (private app code), pkg/ (reusable public packages). cmd/api/main.go is the only entry point. Never put business logic in main.go.", tags: ["structure", "packages", "go"] },
|
|
339
|
+
{ type: "rule", scope: "global", architecture: "go-api", title: "Thin HTTP handlers", content: "Handlers parse the request, call a service method, and write the response. No business logic, no DB calls, no conditional branching beyond input validation in handlers.", tags: ["handler", "structure", "go"] },
|
|
340
|
+
{ type: "rule", scope: "global", architecture: "go-api", title: "Service layer owns business logic", content: "Services accept and return domain types, not http.Request or http.ResponseWriter. Services are fully testable without starting an HTTP server.", tags: ["service", "business-logic", "go"] },
|
|
341
|
+
{ type: "rule", scope: "global", architecture: "go-api", title: "Repository layer for data access", content: "All database calls live in a repository layer. Services depend on repository interfaces, never on database drivers (database/sql, pgx, gorm) directly.", tags: ["repository", "database", "go"] },
|
|
342
|
+
// ── Error Handling ───────────────────────────────────────────────────────
|
|
343
|
+
{ type: "rule", scope: "global", architecture: "go-api", title: "Always return errors explicitly", content: "Return errors as the last return value. Never use panic in library, service, or handler code. Reserve panic only for unrecoverable failures at startup (e.g., missing config).", tags: ["error-handling", "go"] },
|
|
344
|
+
{ type: "rule", scope: "global", architecture: "go-api", title: "Wrap errors with context", content: 'Wrap errors at each layer boundary: fmt.Errorf("createUser: %w", err). This preserves the original error for errors.Is/errors.As and adds context to stack traces.', tags: ["error-handling", "wrapping", "go"] },
|
|
345
|
+
{ type: "rule", scope: "global", architecture: "go-api", title: "Never ignore returned errors", content: "Every returned error must be handled or explicitly discarded with a comment. Silently assigning to _ hides bugs. Lint with errcheck to enforce this.", tags: ["error-handling", "go"] },
|
|
346
|
+
{ type: "pattern", scope: "global", architecture: "go-api", title: "Sentinel errors for known cases", content: 'Define sentinel errors (var ErrNotFound = errors.New("not found")) for expected failure cases. Callers use errors.Is() to check. Never compare error strings.', tags: ["error-handling", "sentinel", "go"] },
|
|
347
|
+
// ── Interfaces & Types ───────────────────────────────────────────────────
|
|
348
|
+
{ type: "rule", scope: "global", architecture: "go-api", title: "Small interfaces at the point of use", content: "Define interfaces where they are consumed, not where implementations live. Prefer single-method interfaces. A 10-method interface is a sign the consumer needs too much.", tags: ["interfaces", "design", "go"] },
|
|
349
|
+
{ type: "rule", scope: "global", architecture: "go-api", title: "Request/response structs for all handlers", content: "Define explicit request and response structs for every handler. Never bind directly to domain models. This decouples API shape from internal representation.", tags: ["dto", "handler", "go"] },
|
|
350
|
+
// ── Context & Concurrency ────────────────────────────────────────────────
|
|
351
|
+
{ type: "rule", scope: "global", architecture: "go-api", title: "context.Context as first parameter", content: "Every function that may block, make a network call, or query a database accepts context.Context as its first parameter. Never store Context in a struct.", tags: ["context", "concurrency", "go"] },
|
|
352
|
+
{ type: "rule", scope: "global", architecture: "go-api", title: "Graceful shutdown", content: "Catch SIGINT and SIGTERM via signal.NotifyContext. Call server.Shutdown(ctx) to drain in-flight requests before exiting. Never call os.Exit(1) directly in the server loop.", tags: ["shutdown", "reliability", "go"] },
|
|
353
|
+
// ── Configuration & Logging ──────────────────────────────────────────────
|
|
354
|
+
{ type: "rule", scope: "global", architecture: "go-api", title: "Config struct loaded at startup", content: "Read all configuration from environment variables into a validated Config struct in main.go before starting the server. Fail fast on missing required values. Never read env vars inside handlers or services.", tags: ["config", "go"] },
|
|
355
|
+
{ type: "rule", scope: "global", architecture: "go-api", title: "Structured logging only", content: "Use slog (stdlib) or zerolog for all logging. Log with key-value fields, not format strings. Never use fmt.Println or log.Printf in production paths.", tags: ["logging", "observability", "go"] },
|
|
356
|
+
// ── Testing ──────────────────────────────────────────────────────────────
|
|
357
|
+
{ type: "rule", scope: "global", architecture: "go-api", title: "Table-driven tests", content: "Write unit tests as table-driven tests using t.Run(). Each test case has a name, input, and expected output. This keeps tests readable and easy to extend.", tags: ["testing", "go"] },
|
|
358
|
+
{ type: "pattern", scope: "global", architecture: "go-api", title: "Test handlers with httptest", content: "Test HTTP handlers using httptest.NewRecorder() and httptest.NewRequest(). Never spin up a real server in unit tests.", tags: ["testing", "handler", "go"] },
|
|
359
|
+
{ type: "rule", scope: "global", architecture: "go-api", title: "Mock with interfaces, not libraries", content: "Inject mock implementations via interfaces rather than using reflection-based mock libraries. Write mocks by hand or use mockery \u2014 keep them simple.", tags: ["testing", "mocking", "go"] },
|
|
360
|
+
// ── Middleware & Security ────────────────────────────────────────────────
|
|
361
|
+
{ type: "rule", scope: "global", architecture: "go-api", title: "Middleware registered at router level", content: "Register all middleware (auth, logging, CORS, recovery) at the router, not inside individual handlers. Middleware wraps the handler chain \u2014 it should never be called manually.", tags: ["middleware", "structure", "go"] },
|
|
362
|
+
{ type: "rule", scope: "global", architecture: "go-api", title: "Validate all incoming data", content: "Validate and sanitize all request inputs before passing to the service layer. Return 400 Bad Request with a structured error body for invalid input. Never trust client data.", tags: ["validation", "security", "go"] },
|
|
359
363
|
// ══════════════════════════════════════════════════════════════════════════
|
|
360
364
|
// LARAVEL SERVICE REPOSITORY
|
|
361
365
|
// ══════════════════════════════════════════════════════════════════════════
|
|
@@ -568,9 +572,6 @@ function detectProject(cwd = process.cwd()) {
|
|
|
568
572
|
return {};
|
|
569
573
|
}
|
|
570
574
|
};
|
|
571
|
-
if (has("next.config.js") || has("next.config.ts") || has("next.config.mjs")) {
|
|
572
|
-
return { language: "TypeScript", framework: "Next.js" };
|
|
573
|
-
}
|
|
574
575
|
if (has("artisan") && has("composer.json")) {
|
|
575
576
|
return { language: "PHP", framework: "Laravel" };
|
|
576
577
|
}
|
|
@@ -1697,7 +1698,7 @@ program.command("init").description("Initialize memory-core in the current proje
|
|
|
1697
1698
|
message: "Project name?",
|
|
1698
1699
|
default: process.cwd().split("/").pop() ?? "my-project"
|
|
1699
1700
|
});
|
|
1700
|
-
const inferredProjectType = ["
|
|
1701
|
+
const inferredProjectType = ["Nuxt.js"].includes(detected.framework) ? "fullstack" : ["React", "Vue.js", "Svelte"].includes(detected.framework) ? "frontend" : "backend";
|
|
1701
1702
|
const projectType = quick ? inferredProjectType : await select({
|
|
1702
1703
|
message: "Project type?",
|
|
1703
1704
|
choices: [
|
|
@@ -1709,7 +1710,7 @@ program.command("init").description("Initialize memory-core in the current proje
|
|
|
1709
1710
|
let backendArchitecture;
|
|
1710
1711
|
if (projectType === "backend" || projectType === "fullstack") {
|
|
1711
1712
|
if (quick) {
|
|
1712
|
-
backendArchitecture = detected.framework === "NestJS" ? "nestjs" : detected.framework === "Laravel" ? "laravel-service-repository" : "clean-architecture";
|
|
1713
|
+
backendArchitecture = detected.framework === "NestJS" ? "nestjs" : detected.framework === "Laravel" ? "laravel-service-repository" : detected.framework === "Go" ? "go-api" : "clean-architecture";
|
|
1713
1714
|
} else {
|
|
1714
1715
|
const backendProfiles = listProfiles("backend");
|
|
1715
1716
|
backendArchitecture = await select({
|
|
@@ -1725,7 +1726,6 @@ program.command("init").description("Initialize memory-core in the current proje
|
|
|
1725
1726
|
if (projectType === "frontend" || projectType === "fullstack") {
|
|
1726
1727
|
if (quick) {
|
|
1727
1728
|
const frameworkMap = {
|
|
1728
|
-
"Next.js": "nextjs",
|
|
1729
1729
|
"Nuxt.js": "nuxt",
|
|
1730
1730
|
React: "react",
|
|
1731
1731
|
"Vue.js": "vue",
|
package/package.json
CHANGED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
name: go-api
|
|
2
|
+
displayName: Go REST API
|
|
3
|
+
layer: backend
|
|
4
|
+
description: Go REST API with clean package structure, idiomatic error handling, and testability
|
|
5
|
+
|
|
6
|
+
rules:
|
|
7
|
+
- Organize code into cmd/, internal/, and pkg/ — cmd/ holds main packages, internal/ holds private packages, pkg/ holds public packages
|
|
8
|
+
- HTTP handlers are thin — parse request, call service, write response. No business logic.
|
|
9
|
+
- Services own all business logic — they accept and return domain types, not HTTP types
|
|
10
|
+
- Always pass context.Context as the first parameter for cancellation and deadline propagation
|
|
11
|
+
- Return errors explicitly — never panic in library or service code. Reserve panic only for unrecoverable startup failures.
|
|
12
|
+
- Wrap errors with context using fmt.Errorf("operation: %w", err) to preserve the original error
|
|
13
|
+
- Define small, single-method interfaces at the point of use, not at the point of implementation
|
|
14
|
+
- Use struct-based request/response types for all handler inputs and outputs
|
|
15
|
+
- Validate all incoming request data before passing to the service layer
|
|
16
|
+
- Configuration comes from environment variables — use a dedicated Config struct loaded at startup with validation
|
|
17
|
+
- Use structured logging (slog or zerolog) — never log with fmt.Println in production code
|
|
18
|
+
- Implement graceful shutdown — catch SIGINT/SIGTERM and drain in-flight requests before exiting
|
|
19
|
+
- Use table-driven tests with t.Run() for all unit tests
|
|
20
|
+
- Register middleware at the router level — never call middleware logic inside handlers
|
|
21
|
+
- Database calls live in a repository layer — services never import database drivers directly
|
|
22
|
+
|
|
23
|
+
folders:
|
|
24
|
+
- cmd/api/
|
|
25
|
+
- cmd/api/main.go
|
|
26
|
+
- internal/handler/
|
|
27
|
+
- internal/service/
|
|
28
|
+
- internal/repository/
|
|
29
|
+
- internal/domain/
|
|
30
|
+
- internal/middleware/
|
|
31
|
+
- internal/config/
|
|
32
|
+
- pkg/
|
|
33
|
+
- api/
|
|
34
|
+
|
|
35
|
+
avoid:
|
|
36
|
+
- Global mutable state outside of the DI wiring in main.go
|
|
37
|
+
- Business logic inside HTTP handlers
|
|
38
|
+
- Direct database calls in service layer
|
|
39
|
+
- Ignoring returned errors (assign to _ only when truly safe)
|
|
40
|
+
- Naked returns in functions longer than a few lines
|
|
41
|
+
- Using init() for configuration — use explicit constructors instead
|
|
42
|
+
- Panicking in non-main code
|
|
43
|
+
- Mixing HTTP concerns with domain logic
|
package/profiles/nextjs.yml
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
name: nextjs
|
|
2
|
-
displayName: Next.js App Router
|
|
3
|
-
layer: fullstack
|
|
4
|
-
description: Next.js 13+ App Router with server components, server actions, and colocation
|
|
5
|
-
|
|
6
|
-
rules:
|
|
7
|
-
- Use Server Components by default — add 'use client' only when interactivity is required
|
|
8
|
-
- Data fetching happens in Server Components, not client hooks
|
|
9
|
-
- Use Server Actions for form mutations and data writes
|
|
10
|
-
- Keep page.tsx files thin — delegate to feature components
|
|
11
|
-
- Colocate components, hooks, and utilities near the route that uses them
|
|
12
|
-
- Shared UI lives in src/components/, shared logic in src/lib/
|
|
13
|
-
- API routes are for external integrations only — prefer Server Actions for internal mutations
|
|
14
|
-
- Use Route Groups to organize without affecting URL structure
|
|
15
|
-
- Environment variables exposed to client must be prefixed NEXT_PUBLIC_
|
|
16
|
-
|
|
17
|
-
folders:
|
|
18
|
-
- app/(routes)
|
|
19
|
-
- app/api
|
|
20
|
-
- src/components/ui
|
|
21
|
-
- src/components/features
|
|
22
|
-
- src/lib/utils
|
|
23
|
-
- src/lib/actions
|
|
24
|
-
- src/lib/db
|
|
25
|
-
- src/types
|
|
26
|
-
|
|
27
|
-
avoid:
|
|
28
|
-
- Data fetching in Client Components (use Server Components instead)
|
|
29
|
-
- useEffect for data loading
|
|
30
|
-
- Business logic inside page.tsx
|
|
31
|
-
- Mixing server and client code in the same file
|
|
32
|
-
- Exposing secrets via NEXT_PUBLIC_ variables
|