@shahmilsaari/memory-core 0.2.10 → 0.2.12

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 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
- | Next.js | Next.js 13+ with server components and server actions |
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
- // NEXT.JS APP ROUTER
335
+ // GO REST API
336
336
  // ══════════════════════════════════════════════════════════════════════════
337
- // ── Rendering Strategy ───────────────────────────────────────────────────
338
- { type: "rule", scope: "global", architecture: "nextjs", title: "Server Components by default", content: 'Every component is a Server Component unless it requires interactivity (onClick, useState, useEffect). Add "use client" only when necessary, as low in the tree as possible.', tags: ["server-components", "nextjs"] },
339
- { type: "rule", scope: "global", architecture: "nextjs", title: "Fetch in Server Components", content: "Fetch data directly in async Server Components. Never use useEffect, SWR, or React Query for initial server-side data. Client-side fetching is for user-triggered updates only.", tags: ["data-fetching", "nextjs"] },
340
- { type: "rule", scope: "global", architecture: "nextjs", title: "Server Actions for mutations", content: "All form submissions and data mutations use Server Actions. API routes are only for third-party webhooks or browser clients that cannot use Server Actions.", tags: ["server-actions", "mutations", "nextjs"] },
341
- { type: "rule", scope: "global", architecture: "nextjs", title: "Static by default, dynamic when needed", content: 'Pages are statically rendered unless they use cookies(), headers(), or searchParams. Opt into dynamic rendering explicitly with export const dynamic = "force-dynamic".', tags: ["rendering", "performance", "nextjs"] },
342
- { type: "pattern", scope: "global", architecture: "nextjs", title: "Suspense boundaries for streaming", content: "Wrap slow data-fetching sections in <Suspense fallback={<Skeleton />}>. This enables streaming and progressive hydration. Do not block the entire page on one slow query.", tags: ["suspense", "streaming", "nextjs"] },
343
- { type: "pattern", scope: "global", architecture: "nextjs", title: "Parallel data fetching", content: "Use Promise.all() for independent data fetches in the same Server Component. Sequential awaits in a single component waterfall unnecessarily.", tags: ["performance", "data-fetching", "nextjs"] },
344
- // ── Structure ─────────────────────────────────────────────────────────────
345
- { type: "rule", scope: "global", architecture: "nextjs", title: "Thin page.tsx files", content: "page.tsx fetches data and passes it to a feature component. No JSX logic, no conditionals, no business logic in page files.", tags: ["structure", "nextjs"] },
346
- { type: "rule", scope: "global", architecture: "nextjs", title: "Colocate by route", content: "Components used only by one route live next to that route. Components used across 3+ routes move to src/components/. Utils used across routes go to src/lib/.", tags: ["structure", "colocation", "nextjs"] },
347
- { type: "rule", scope: "global", architecture: "nextjs", title: "Route groups for organization", content: "Use (groupName) folders to organize routes without affecting URLs. Group by concern: (marketing), (dashboard), (auth). Each group can have its own layout.", tags: ["route-groups", "structure", "nextjs"] },
348
- { type: "rule", scope: "global", architecture: "nextjs", title: "loading.tsx and error.tsx always", content: "Every dynamic route segment must have a loading.tsx (Suspense fallback) and error.tsx (error boundary). Never let routes fail or hang without user feedback.", tags: ["loading", "error-handling", "nextjs"] },
349
- // ── Security & Config ────────────────────────────────────────────────────
350
- { type: "rule", scope: "global", architecture: "nextjs", title: "No secrets in NEXT_PUBLIC_", content: "NEXT_PUBLIC_ variables are embedded in the client bundle. Never put API keys, tokens, or DB credentials there. Server-only secrets stay in Server Components and Actions.", tags: ["security", "env", "nextjs"] },
351
- { type: "rule", scope: "global", architecture: "nextjs", title: "Auth in middleware.ts", content: "Route protection and session validation happens in middleware.ts at the edge. Never rely on page-level checks as the only auth guard.", tags: ["auth", "middleware", "security", "nextjs"] },
352
- { type: "rule", scope: "global", architecture: "nextjs", title: "Validate Server Action inputs", content: "Always validate and sanitize inputs inside Server Actions using zod or similar. Server Actions are public endpoints \u2014 treat them like API routes.", tags: ["validation", "server-actions", "security", "nextjs"] },
353
- // ── Performance ──────────────────────────────────────────────────────────
354
- { type: "rule", scope: "global", architecture: "nextjs", title: "next/image for all images", content: "Use next/image for all images. It provides automatic WebP conversion, lazy loading, and size optimization. Never use raw <img> tags.", tags: ["performance", "images", "nextjs"] },
355
- { type: "rule", scope: "global", architecture: "nextjs", title: "next/font for typography", content: "Use next/font for fonts. It eliminates layout shift, self-hosts, and applies font-display: swap automatically. Never load fonts from Google Fonts CDN directly.", tags: ["performance", "fonts", "nextjs"] },
356
- { type: "rule", scope: "global", architecture: "nextjs", title: "Cache fetch calls with tags", content: 'Tag fetch() calls with cache tags: fetch(url, { next: { tags: ["products"] } }). Revalidate by tag on mutation with revalidateTag("products").', tags: ["caching", "performance", "nextjs"] },
357
- { type: "pattern", scope: "global", architecture: "nextjs", title: "ISR for semi-static pages", content: "Use Incremental Static Regeneration for pages that change infrequently: export const revalidate = 3600. Combine with revalidatePath() on writes.", tags: ["isr", "performance", "nextjs"] },
358
- { type: "rule", scope: "global", architecture: "nextjs", title: "Metadata API for SEO", content: "Define page metadata using the Metadata API (export const metadata) or generateMetadata(). Never use next/head or raw <Head> in App Router.", tags: ["seo", "metadata", "nextjs"] },
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 = ["Next.js", "Nuxt.js"].includes(detected.framework) ? "fullstack" : ["React", "Vue.js", "Svelte"].includes(detected.framework) ? "frontend" : "backend";
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shahmilsaari/memory-core",
3
- "version": "0.2.10",
3
+ "version": "0.2.12",
4
4
  "description": "Universal AI memory core — generate AI context files from architecture profiles with RAG support",
5
5
  "type": "module",
6
6
  "bin": {
@@ -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 at each layer boundary using fmt.Errorf with the %w verb — this chains errors so errors.Is and errors.As work across layers
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
@@ -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