From e140863049c371f62ac5b0fe6ba67107986f7047 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 17 Mar 2026 22:33:36 +0000 Subject: [PATCH 1/2] Add Node.js backend architecture option (Express 5 + tRPC + Drizzle) Adds a new "nodejs-backend" architecture option to the catalog with four inline skills (architecture, design, code, testing) covering layered architecture patterns, tRPC routers, Drizzle ORM conventions, and Vitest testing strategies. Includes docsets for tRPC, Drizzle ORM, Express, and Zod. https://claude.ai/code/session_01JtoE1wqSCbgs48KNdA2Ggh --- packages/core/src/catalog/catalog.spec.ts | 49 ++++++ .../core/src/catalog/facets/architecture.ts | 141 ++++++++++++++++++ 2 files changed, 190 insertions(+) diff --git a/packages/core/src/catalog/catalog.spec.ts b/packages/core/src/catalog/catalog.spec.ts index 9fbaaf1..b5fc681 100644 --- a/packages/core/src/catalog/catalog.spec.ts +++ b/packages/core/src/catalog/catalog.spec.ts @@ -90,6 +90,55 @@ describe("catalog", () => { }); }); + describe("nodejs-backend option", () => { + it("has nodejs-backend option with skills for architecture, design, code, and testing", () => { + const catalog = getDefaultCatalog(); + const architecture = getFacet(catalog, "architecture")!; + const nodejsBackend = getOption(architecture, "nodejs-backend"); + + expect(nodejsBackend).toBeDefined(); + const skillsProvisions = nodejsBackend!.recipe.filter( + (p) => p.writer === "skills" + ); + expect(skillsProvisions).toHaveLength(1); + + const skills = ( + skillsProvisions[0].config as { skills: { name: string }[] } + ).skills; + const names = skills.map((s) => s.name); + expect(names).toContain("nodejs-backend-architecture"); + expect(names).toContain("nodejs-backend-design"); + expect(names).toContain("nodejs-backend-code"); + expect(names).toContain("nodejs-backend-testing"); + }); + + it("nodejs-backend option declares docsets for tRPC, Drizzle, Express, and Zod", () => { + const catalog = getDefaultCatalog(); + const architecture = getFacet(catalog, "architecture")!; + const nodejsBackend = getOption(architecture, "nodejs-backend")!; + + expect(nodejsBackend.docsets).toBeDefined(); + const ids = nodejsBackend.docsets!.map((d) => d.id); + expect(ids).toContain("trpc-docs"); + expect(ids).toContain("drizzle-orm-docs"); + expect(ids).toContain("express-docs"); + expect(ids).toContain("zod-docs"); + }); + + it("each nodejs-backend docset has required fields", () => { + const catalog = getDefaultCatalog(); + const architecture = getFacet(catalog, "architecture")!; + const nodejsBackend = getOption(architecture, "nodejs-backend")!; + + for (const docset of nodejsBackend.docsets!) { + expect(docset.id).toBeTruthy(); + expect(docset.label).toBeTruthy(); + expect(docset.origin).toMatch(/^https:\/\//); + expect(docset.description).toBeTruthy(); + } + }); + }); + describe("architecture facet docsets", () => { it("tanstack option declares docsets for Router, Query, Form, and Table", () => { const catalog = getDefaultCatalog(); diff --git a/packages/core/src/catalog/facets/architecture.ts b/packages/core/src/catalog/facets/architecture.ts index 5462250..df329cf 100644 --- a/packages/core/src/catalog/facets/architecture.ts +++ b/packages/core/src/catalog/facets/architecture.ts @@ -143,6 +143,147 @@ export const architectureFacet: Facet = { description: "Headless table and datagrid utilities" } ] + }, + { + id: "nodejs-backend", + label: "Node.js Backend", + description: "Type-safe API server with Express 5, tRPC, and Drizzle ORM", + recipe: [ + { + writer: "skills", + config: { + skills: [ + { + name: "nodejs-backend-architecture", + description: + "Architecture conventions for Node.js backend applications", + body: [ + "# Node.js Backend Architecture Conventions", + "", + "## Project Structure", + "- Layered architecture: `routes/` → `procedures/` → `services/` → `repositories/`", + "- Organize by feature, not by type (e.g. `features/users/`, `features/orders/`)", + "- Each feature exports its tRPC router via `index.ts`", + "- Shared code in `lib/` (db client, logger, error classes)", + "- Entry point: `src/server.ts` creates Express app and mounts tRPC adapter via `express.createHandler`", + "", + "## Module Boundaries", + "- Features must not import from other features' internals", + "- Services never touch `req`/`res` — they receive typed inputs and return plain objects", + "- Repositories are thin wrappers around Drizzle queries", + "- Dependency injection via function parameters, not DI containers", + "", + "## Configuration", + "- Config via environment variables (12-factor app)", + "- Validate all env vars at startup with a Zod schema", + "- Single `config.ts` module exports the validated config object" + ].join("\n") + }, + { + name: "nodejs-backend-design", + description: "Design patterns for Node.js backend applications", + body: [ + "# Node.js Backend Design Patterns", + "", + "## tRPC Patterns", + "- Define one tRPC router per feature: `export const usersRouter = router({ ... })`", + "- Merge feature routers into a root `appRouter` in `src/router.ts`", + "- Export `type AppRouter = typeof appRouter` for client type inference", + "- Use Zod schemas for `.input()` and `.output()` on every procedure", + "- Use `publicProcedure` and `protectedProcedure` base procedures with middleware", + "", + "## Middleware", + "- Auth middleware: validate tokens, attach user context via tRPC context", + "- Logging middleware: structured JSON logs with request ID, duration, status", + "- Error handling: throw `TRPCError` with typed codes (`NOT_FOUND`, `UNAUTHORIZED`, etc.)", + "", + "## Database Patterns", + "- Drizzle schema files colocated with features (`features/users/schema.ts`)", + "- Repository functions take the Drizzle `db` instance as first parameter", + "- Use Drizzle transactions for multi-table operations", + "- Migrations managed via `drizzle-kit` (`drizzle/migrations/` directory)" + ].join("\n") + }, + { + name: "nodejs-backend-code", + description: + "Code style conventions for Node.js backend applications", + body: [ + "# Node.js Backend Code Conventions", + "", + "## TypeScript", + "- Enable strict mode in tsconfig", + "- Never use `any` — prefer `unknown` and narrow with Zod or type guards", + "- Infer types from Drizzle schema (`typeof users.$inferSelect`) and tRPC (`inferRouterInputs`, `inferRouterOutputs`)", + "- Use `satisfies` operator for config and constant objects", + "", + "## Naming", + "- tRPC routers: `*.router.ts` (e.g. `users.router.ts`)", + "- Services: `*.service.ts` (e.g. `users.service.ts`)", + "- Repositories: `*.repository.ts` (e.g. `users.repository.ts`)", + "- Drizzle table schemas: `*.schema.ts` (e.g. `users.schema.ts`)", + "", + "## Imports", + "- Use path aliases for project imports (`@/features/...`, `@/lib/...`)", + "- Prefer named exports over default exports", + "- Barrel files (`index.ts`) per feature for public API only" + ].join("\n") + }, + { + name: "nodejs-backend-testing", + description: + "Testing conventions for Node.js backend applications", + body: [ + "# Node.js Backend Testing Conventions", + "", + "## Unit Tests", + "- Test services with mocked repositories using `vi.mock()`", + "- Test Zod schemas independently with valid and invalid inputs", + "- Test file colocation: `*.spec.ts` next to source file", + "", + "## Integration Tests", + "- Test tRPC procedures using `createCaller` — no HTTP needed", + "- Database tests against a real test database", + "- Use transaction rollback per test for isolation", + "- Run Drizzle migrations before the test suite", + "", + "## Patterns", + "- Use Vitest as test runner and assertion library", + "- Do not mock tRPC internals — test through the caller API", + "- Factory functions for test data (avoid fixtures with implicit state)", + "- Assert on returned data and side effects, not internal implementation" + ].join("\n") + } + ] + } + } + ], + docsets: [ + { + id: "trpc-docs", + label: "tRPC", + origin: "https://github.com/trpc/trpc.git", + description: "End-to-end type-safe APIs, routers, and procedures" + }, + { + id: "drizzle-orm-docs", + label: "Drizzle ORM", + origin: "https://github.com/drizzle-team/drizzle-orm.git", + description: "Type-safe SQL schema, queries, and migrations" + }, + { + id: "express-docs", + label: "Express", + origin: "https://github.com/expressjs/express.git", + description: "HTTP server, routing, and middleware" + }, + { + id: "zod-docs", + label: "Zod", + origin: "https://github.com/colinhacks/zod.git", + description: "TypeScript-first schema validation" + } + ] } ] }; From c2100b38b560b5307f8441eae8da2820578b039f Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 17 Mar 2026 22:38:00 +0000 Subject: [PATCH 2/2] Add Java backend architecture option (Spring Boot 3 + JPA + Gradle + Lombok) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a new "java-backend" architecture option to the catalog with four inline skills covering layered architecture (controller → service → repository), Spring Boot design patterns with JPA/Hibernate, Lombok conventions, and testing with JUnit 5, MockMvc, and Testcontainers. Includes docsets for Spring Boot, Spring Data JPA, Spring Security, and Lombok. https://claude.ai/code/session_01JtoE1wqSCbgs48KNdA2Ggh --- packages/core/src/catalog/catalog.spec.ts | 49 ++++++ .../core/src/catalog/facets/architecture.ts | 149 ++++++++++++++++++ 2 files changed, 198 insertions(+) diff --git a/packages/core/src/catalog/catalog.spec.ts b/packages/core/src/catalog/catalog.spec.ts index b5fc681..3c80d23 100644 --- a/packages/core/src/catalog/catalog.spec.ts +++ b/packages/core/src/catalog/catalog.spec.ts @@ -139,6 +139,55 @@ describe("catalog", () => { }); }); + describe("java-backend option", () => { + it("has java-backend option with skills for architecture, design, code, and testing", () => { + const catalog = getDefaultCatalog(); + const architecture = getFacet(catalog, "architecture")!; + const javaBackend = getOption(architecture, "java-backend"); + + expect(javaBackend).toBeDefined(); + const skillsProvisions = javaBackend!.recipe.filter( + (p) => p.writer === "skills" + ); + expect(skillsProvisions).toHaveLength(1); + + const skills = ( + skillsProvisions[0].config as { skills: { name: string }[] } + ).skills; + const names = skills.map((s) => s.name); + expect(names).toContain("java-backend-architecture"); + expect(names).toContain("java-backend-design"); + expect(names).toContain("java-backend-code"); + expect(names).toContain("java-backend-testing"); + }); + + it("java-backend option declares docsets for Spring Boot, Spring Data JPA, Spring Security, and Lombok", () => { + const catalog = getDefaultCatalog(); + const architecture = getFacet(catalog, "architecture")!; + const javaBackend = getOption(architecture, "java-backend")!; + + expect(javaBackend.docsets).toBeDefined(); + const ids = javaBackend.docsets!.map((d) => d.id); + expect(ids).toContain("spring-boot-docs"); + expect(ids).toContain("spring-data-jpa-docs"); + expect(ids).toContain("spring-security-docs"); + expect(ids).toContain("lombok-docs"); + }); + + it("each java-backend docset has required fields", () => { + const catalog = getDefaultCatalog(); + const architecture = getFacet(catalog, "architecture")!; + const javaBackend = getOption(architecture, "java-backend")!; + + for (const docset of javaBackend.docsets!) { + expect(docset.id).toBeTruthy(); + expect(docset.label).toBeTruthy(); + expect(docset.origin).toMatch(/^https:\/\//); + expect(docset.description).toBeTruthy(); + } + }); + }); + describe("architecture facet docsets", () => { it("tanstack option declares docsets for Router, Query, Form, and Table", () => { const catalog = getDefaultCatalog(); diff --git a/packages/core/src/catalog/facets/architecture.ts b/packages/core/src/catalog/facets/architecture.ts index df329cf..3d19834 100644 --- a/packages/core/src/catalog/facets/architecture.ts +++ b/packages/core/src/catalog/facets/architecture.ts @@ -284,6 +284,155 @@ export const architectureFacet: Facet = { description: "TypeScript-first schema validation" } ] + }, + { + id: "java-backend", + label: "Java Backend", + description: + "Production-grade API server with Spring Boot 3, JPA/Hibernate, Gradle, and Lombok", + recipe: [ + { + writer: "skills", + config: { + skills: [ + { + name: "java-backend-architecture", + description: + "Architecture conventions for Spring Boot backend applications", + body: [ + "# Java Backend Architecture Conventions", + "", + "## Project Structure", + "- Layered architecture: `controller/` → `service/` → `repository/`", + "- Organize by feature, not by layer (e.g. `com.app.user/`, `com.app.order/`)", + "- Each feature package contains its own controller, service, repository, DTOs, and entity classes", + "- Shared code in a `common/` or `shared/` package (exceptions, base entities, utilities)", + "- Entry point: `@SpringBootApplication` class in root package", + "", + "## Module Boundaries", + "- Controllers handle HTTP concerns only — delegate to services immediately", + "- Services contain business logic, call repositories, never touch `HttpServletRequest`/`HttpServletResponse`", + "- Repositories extend `JpaRepository` or `CrudRepository` — no business logic", + "- Cross-feature communication goes through service interfaces, not direct repository access", + "", + "## Configuration", + "- Use `application.yml` with Spring profiles (`dev`, `test`, `prod`)", + "- Externalize secrets via environment variables with `${ENV_VAR}` placeholders", + "- Type-safe config with `@ConfigurationProperties` classes annotated with `@Validated`", + "- Gradle build with Kotlin DSL (`build.gradle.kts`)" + ].join("\n") + }, + { + name: "java-backend-design", + description: + "Design patterns for Spring Boot backend applications", + body: [ + "# Java Backend Design Patterns", + "", + "## REST API Patterns", + "- Use `@RestController` with `@RequestMapping` per feature (e.g. `/api/v1/users`)", + "- DTOs for request/response — never expose JPA entities directly", + "- Use `@Valid` with Jakarta Bean Validation annotations on request DTOs", + "- Return `ResponseEntity` for explicit status codes, or direct objects for 200 OK", + "- Use `@ControllerAdvice` with `@ExceptionHandler` for centralized error handling", + "", + "## JPA/Hibernate Patterns", + "- Entities use Lombok `@Data`, `@Builder`, `@NoArgsConstructor`, `@AllArgsConstructor`", + "- Use `@Entity` with explicit `@Table(name = ...)` and `@Column` mappings", + "- Prefer `FetchType.LAZY` for associations — use `@EntityGraph` or join fetch for eager loading when needed", + "- Database migrations managed by Flyway (`db/migration/V1__description.sql`)", + "- Use Spring Data JPA derived queries or `@Query` with JPQL", + "", + "## Middleware & Cross-Cutting", + "- Security with Spring Security filter chain — JWT or session-based", + "- Structured logging with SLF4J + Logback, MDC for request correlation", + "- Use `@Transactional` on service methods, read-only where appropriate" + ].join("\n") + }, + { + name: "java-backend-code", + description: + "Code style conventions for Spring Boot backend applications", + body: [ + "# Java Backend Code Conventions", + "", + "## Lombok Usage", + "- Use `@Data` for DTOs, `@Value` for immutable objects", + "- Use `@Builder` for entities and complex DTOs", + "- Use `@RequiredArgsConstructor` for constructor injection (preferred over `@Autowired`)", + "- Use `@Slf4j` for logger injection", + "", + "## Naming", + "- Controllers: `*Controller.java` (e.g. `UserController.java`)", + "- Services: `*Service.java` interface + `*ServiceImpl.java`", + "- Repositories: `*Repository.java` (e.g. `UserRepository.java`)", + "- Entities: singular noun (e.g. `User.java`, `Order.java`)", + "- DTOs: `*Request.java`, `*Response.java` (e.g. `CreateUserRequest.java`)", + "", + "## Dependency Injection", + "- Constructor injection via `@RequiredArgsConstructor` — never field injection", + "- Declare dependencies as `private final` fields", + "- Program to interfaces for services (e.g. inject `UserService`, not `UserServiceImpl`)" + ].join("\n") + }, + { + name: "java-backend-testing", + description: + "Testing conventions for Spring Boot backend applications", + body: [ + "# Java Backend Testing Conventions", + "", + "## Unit Tests", + "- Test services with mocked repositories using `@ExtendWith(MockitoExtension.class)`", + "- Use `@Mock` for dependencies and `@InjectMocks` for the class under test", + "- Test DTOs and validation annotations independently", + "- Follow `given/when/then` structure with descriptive method names", + "", + "## Integration Tests", + "- Use `@SpringBootTest` with `@AutoConfigureMockMvc` for controller tests", + "- Test through `MockMvc` — assert on status, headers, and JSON body", + "- Use `@DataJpaTest` for repository tests with an embedded H2 database", + "- Use `@Testcontainers` for integration tests against real databases (PostgreSQL, MySQL)", + "- Use `@Transactional` on test classes for automatic rollback", + "", + "## Patterns", + "- JUnit 5 as test framework, AssertJ for fluent assertions", + "- Test file location: `src/test/java/` mirroring main source structure", + "- Factory methods or builders for test data — avoid shared mutable fixtures", + "- Use `@WithMockUser` for security-aware controller tests" + ].join("\n") + } + ] + } + } + ], + docsets: [ + { + id: "spring-boot-docs", + label: "Spring Boot", + origin: "https://github.com/spring-projects/spring-boot.git", + description: "Spring Boot framework, auto-configuration, and actuator" + }, + { + id: "spring-data-jpa-docs", + label: "Spring Data JPA", + origin: "https://github.com/spring-projects/spring-data-jpa.git", + description: "JPA repositories, derived queries, and specifications" + }, + { + id: "spring-security-docs", + label: "Spring Security", + origin: "https://github.com/spring-projects/spring-security.git", + description: "Authentication, authorization, and security filters" + }, + { + id: "lombok-docs", + label: "Lombok", + origin: "https://github.com/projectlombok/lombok.git", + description: + "Boilerplate reduction with annotations for getters, builders, and constructors" + } + ] } ] };