@plinng/ai-code-assistant-tools 1.0.0

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 ADDED
@@ -0,0 +1,100 @@
1
+ # @plinng/ai-code-assistant-tools
2
+
3
+ Versioned, modular AI coding standards for the Plinng platform. Provides
4
+ behavioral and architectural rules for Claude Code and Cursor that encode
5
+ what linters and formatters cannot: architectural intent, error philosophy,
6
+ and design discipline.
7
+
8
+ ---
9
+
10
+ ## What this is
11
+
12
+ These are **not** linter rules. ESLint, Prettier, Ruff, and Biome handle
13
+ formatting and style deterministically at zero LLM token cost. These rules
14
+ encode the decisions that static analysis has no reach into:
15
+
16
+ - Which layer is responsible for what
17
+ - When and how to handle errors
18
+ - Which design patterns to prefer and why.
19
+ - SOLID principles and how to apply them in this codebase.
20
+
21
+ ---
22
+
23
+ ## Rules included
24
+
25
+ | Rule file | Tool | Activated when | Enforces |
26
+ |---|---|---|---|
27
+ | `CLAUDE.md` / `universal.mdc` | Both | Always | How to work, commits, task runner, error + architecture summary |
28
+ | `error-handling.md/mdc` | Both | `**/*.ts`, `**/*.py` | No silent catches; structured boundary logging; propagation discipline |
29
+ | `architecture.md/mdc` | Both | `**/handlers/**`, `**/resolvers/**`, `**/routes/**`, `**/app/**` | Layer ordering; no DB client in handlers; factory injection |
30
+ | `solid-principles.md/mdc` | Both | `**/*.ts`, `**/*.tsx` | SRP, OCP, LSP, ISP, DIP; don't refactor violations unless asked |
31
+ | `clean-architecture.md/mdc` | Both | `**/*.ts`, `**/*.py` | Four-layer model; domain types from repositories; coupling detector |
32
+ | `design-patterns.md/mdc` | Both | Always (Claude) / Agent Requested (Cursor) | Propose pattern + rationale before implementing |
33
+
34
+ ---
35
+
36
+ ## Install
37
+
38
+ ### Interactive CLI
39
+
40
+ ```bash
41
+ npx @plinng/ai-code-assistant-tools
42
+ ```
43
+
44
+ The installer will ask which AI assistant you use (Claude Code / Cursor / Both)
45
+ and, for Cursor, whether to install at project scope or user scope. Existing
46
+ files are backed up automatically as `<file>.backup-<timestamp>`
47
+
48
+ ### Manual install — Claude Code
49
+
50
+ ```bash
51
+ cp claude-code/CLAUDE.md ~/.claude/CLAUDE.md
52
+ cp claude-code/rules/*.md ~/.claude/rules/
53
+ ```
54
+
55
+ ### Manual install — Cursor (project scope)
56
+
57
+ ```bash
58
+ cp -r cursor/rules/ .cursor/rules/
59
+ ```
60
+
61
+ ---
62
+
63
+ ## Cursor scope note
64
+
65
+ **Project scope** (`.cursor/rules/`) is the reliably enforced path for teams.
66
+ Rules installed there are version-controlled and apply to every developer who
67
+ opens the project in Cursor.
68
+
69
+ **User scope** (`~/.cursor/rules/`) is a filesystem convention. Cursor reads
70
+ user rules from its Settings UI (plain text), not from a filesystem path
71
+ directly. To apply user rules from this install, paste the content of each
72
+ `.mdc` file into `Cursor Settings → General → Rules for AI`, or use Cursor
73
+ Team Rules (requires Cursor Team/Enterprise plan) for enforced team standards.
74
+
75
+ ---
76
+
77
+ ## Updating
78
+
79
+ Re-run the installer to get the latest rules. Existing files will be backed up
80
+ before overwriting:
81
+
82
+ ```bash
83
+ npx @plinng/ai-code-assistant-tools
84
+ ```
85
+
86
+ ---
87
+
88
+ ## Contributing
89
+
90
+ Before adding or modifying a rule, verify it meets this checklist:
91
+
92
+ 1. **Cannot be enforced by a linter** — if ESLint/Ruff can catch it, it belongs in tool config, not here
93
+ 2. **Imperative with motivation** — "Use X because Y", not "Consider using X"
94
+ 3. **Both `.md` and `.mdc` updated** — keep Claude Code and Cursor rule content in sync
95
+ 4. **Line count passes** — run `moon run ai-code-assistant-tools:lint-rules`
96
+ 5. **PR to platform team** — rules affect all engineers; review is required
97
+
98
+ ```bash
99
+ moon run ai-code-assistant-tools:lint-rules
100
+ ```
@@ -0,0 +1,28 @@
1
+ # Plinng Platform — AI Coding Standards
2
+
3
+ ## How to work
4
+ - Only make changes directly requested. A bug fix does not need surrounding code cleaned up.
5
+ - Do not design for hypothetical future requirements. Three similar lines beat a premature abstraction.
6
+ - Never push to the remote repository without an explicit human request.
7
+ - Use Conventional Commits: `feat:`, `fix:`, `chore:`, `refactor:`, `docs:`, `test:`.
8
+ - Run `moon run <project>:build` and verify no type errors before committing.
9
+ - Do not add docstrings, comments, or type annotations to code you did not change.
10
+
11
+ ## Error handling
12
+ - Never hide exceptions with fallback returns (`catch (e) { return null }`).
13
+ - At system boundaries (HTTP handlers, queue consumers, cron jobs): log structured metadata `{ operation, identifiers, err }` then re-throw.
14
+ - Inside service and domain layers: let errors propagate — do not catch and re-wrap without adding value.
15
+ - Never add try/catch inside a repository or service unless translating a third-party error into a domain error.
16
+
17
+ ## Architecture
18
+ - Handler → Service → Repository → Data source. Never skip layers.
19
+ - Never import a database client (Prisma, Mongoose, pg) in a resolver, handler, or route file.
20
+ - Use the repository pattern: data access belongs in `*Repository` or `*Store` modules only.
21
+ - Inject dependencies via factory function arguments (`createHandler({ userRepo, logger })`), not global imports.
22
+ - Handlers are stateless coordinators — no business logic, no data transformation beyond shaping the HTTP response
23
+
24
+ ## This monorepo
25
+ - Task runner: Moon (`moon run <project>:<task>`).
26
+ - Python services use `uv` for dependency management.
27
+ - Stack-specific rules load automatically from `~/.claude/rules/` when matching file paths are open.
28
+ - Never modify `moon.yml` task definitions without discussing with the platform team first.
@@ -0,0 +1,60 @@
1
+ ---
2
+ paths: "**/resolvers/**,**/handlers/**,**/routes/**,**/app/**"
3
+ ---
4
+
5
+ # Architecture — handlers, resolvers, and routes
6
+
7
+ The dependency flow is strictly one direction:
8
+ Handler/Resolver → Service → Repository → Data source
9
+
10
+ Never skip or invert layers.
11
+
12
+ ## Handlers are stateless coordinators
13
+
14
+ A handler's only responsibilities are:
15
+ 1. Parse and validate the incoming request
16
+ 2. Call the appropriate service method
17
+ 3. Shape the service result into an HTTP response
18
+
19
+ Handlers must not contain business logic, domain rules, or data transformation
20
+ beyond mapping service output to response shape.
21
+
22
+ ## Never access data sources from handlers or resolvers
23
+
24
+ Never import Prisma, Mongoose, pg, a Redis client, or any external service SDK
25
+ directly into a handler, resolver, or route file.
26
+
27
+ ```typescript
28
+ // Violation — do not do this
29
+ import { prisma } from '../db/client';
30
+
31
+ export async function getOrderHandler(req: Request, res: Response) {
32
+ const order = await prisma.order.findUnique({ where: { id: req.params.id } });
33
+ res.json(order);
34
+ }
35
+
36
+ // Correct — delegate to service, which delegates to repository
37
+ export function createOrderHandler({ orderService }: { orderService: OrderService }) {
38
+ return async (req: Request, res: Response) => {
39
+ const order = await orderService.getOrder(req.params.id);
40
+ res.json(order);
41
+ };
42
+ }
43
+ ```
44
+
45
+ ## Inject dependencies via factory functions
46
+
47
+ Use the `create*` factory pattern to inject services and repositories. Do not
48
+ rely on module-level singletons or global imports for mutable dependencies.
49
+
50
+ ```typescript
51
+ // Factory injection pattern
52
+ export function createUserHandler({ userService, logger }: UserHandlerDeps) {
53
+ return {
54
+ getUser: async (req: Request, res: Response) => { ... },
55
+ createUser: async (req: Request, res: Response) => { ... },
56
+ };
57
+ }
58
+ ```
59
+
60
+ This makes handlers testable without module mocking.
@@ -0,0 +1,45 @@
1
+ ---
2
+ description: Branch naming standard for git branch creation and rename in production-line-microservice
3
+ alwaysApply: true
4
+ ---
5
+
6
+ # Branch Naming
7
+
8
+ ## Format
9
+
10
+ ```
11
+ <prefix>/<short-description>
12
+ ```
13
+
14
+ Use **kebab-case**, all **lowercase**, and aim for **3-6 words** in the description.
15
+
16
+ ## Valid Prefixes
17
+
18
+ | Prefix | Purpose | Example |
19
+ |---|---|---|
20
+ | `feat/` | New feature or capability | `feat/upsell-task-cleanup` |
21
+ | `fix/` | Bug fix | `fix/duplicate-task-assignment` |
22
+ | `refactor/` | Code restructuring (no behavior change) | `refactor/di-container-cleanup` |
23
+ | `docs/` | Documentation only | `docs/update-readme-setup` |
24
+
25
+ ## Rules
26
+
27
+ - **Always use `feat/`** - not `feature/` (historical branches may use `feature/` but new ones must not).
28
+ - Keep descriptions concise but descriptive enough to identify the work.
29
+ - Avoid generic names like `feat/update` or `fix/bug`.
30
+
31
+ ## Quick Validation
32
+
33
+ - Prefix is one of: `feat/`, `fix/`, `refactor/`, `docs/`
34
+ - Description is lowercase kebab-case
35
+ - Description has 3-6 meaningful words
36
+ - No `feature/` prefix in new branches
37
+
38
+ ## Examples
39
+
40
+ ```
41
+ feat/webhook-retry-logic
42
+ fix/task-repository-query-race
43
+ refactor/use-case-error-handling
44
+ docs/api-versioning-guide
45
+ ```
@@ -0,0 +1,57 @@
1
+ ---
2
+ paths: "**/*.ts,**/*.py"
3
+ ---
4
+
5
+ # Clean architecture — layering rules
6
+
7
+ The codebase follows a four-layer architecture. Dependencies point inward only.
8
+
9
+ ```
10
+ Handler / Controller (outermost — HTTP, queues, cron)
11
+
12
+ Service (business rules, orchestration)
13
+
14
+ Repository (data access abstraction)
15
+
16
+ Data source (Prisma, Mongoose, pg, Redis, external APIs)
17
+ ```
18
+
19
+ ## Layer responsibilities
20
+
21
+ **Handler**: HTTP parsing, auth context extraction, input validation, response
22
+ shaping. No business logic. Delegates immediately to a service.
23
+
24
+ **Service**: Business rules, domain validation, orchestration across multiple
25
+ repositories. Receives and returns domain types — never raw DB documents.
26
+
27
+ **Repository**: Encapsulates all queries for a single aggregate. Returns typed
28
+ domain objects. Handles DB-specific errors and translates them to domain errors.
29
+
30
+ **Data source**: The actual client (Prisma, Mongoose). Only imported inside
31
+ repository files.
32
+
33
+ ## Coupling violation detector
34
+
35
+ If a single file imports from both an HTTP framework (`express`, `fastapi`,
36
+ `hono`) and a database client (`prisma`, `mongoose`, `pg`, `motor`), it is a
37
+ coupling violation. Split it along layer boundaries.
38
+
39
+ ```typescript
40
+ // Violation — handler importing DB client directly
41
+ import { Request, Response } from 'express'; // HTTP layer
42
+ import { prisma } from '../db/client'; // Data layer — not allowed here
43
+ ```
44
+
45
+ ## Services receive domain types, not raw DB documents
46
+
47
+ Repositories must map database results to domain types before returning them.
48
+ Services must never access raw Prisma/Mongoose document fields (`_id`,
49
+ `__v`, `createdAt` in raw object form) — only typed domain properties.
50
+
51
+ ```typescript
52
+ // Repository — maps raw result to domain type
53
+ async findById(id: string): Promise<User> {
54
+ const doc = await prisma.user.findUniqueOrThrow({ where: { id } });
55
+ return { id: doc.id, email: doc.email, name: doc.name }; // domain type
56
+ }
57
+ ```
@@ -0,0 +1,42 @@
1
+ # Design patterns
2
+
3
+ Before implementing a non-trivial solution, propose the applicable design
4
+ pattern with a one-sentence rationale explaining why it fits. State the
5
+ pattern name explicitly. Do not propose patterns for simple, single-purpose
6
+ functions — only for solutions involving multiple collaborators, varying
7
+ behavior, or extension points.
8
+
9
+ ## Patterns to consider and when
10
+
11
+ **Repository** — When multiple parts of the codebase need to query the same
12
+ data source. Centralizes query logic and allows the data source to be swapped.
13
+
14
+ **Factory** — When object creation involves conditional logic, multiple
15
+ dependencies, or configuration. Use `createX({ dep1, dep2 })` functions
16
+ instead of constructor-heavy classes.
17
+
18
+ **Strategy** — When a behavior varies based on context (e.g., different
19
+ payment processors, notification channels, export formats). Pass the strategy
20
+ as a dependency rather than branching with `if/switch`.
21
+
22
+ **Observer / Event emitter** — When an action in one part of the system
23
+ should trigger reactions in decoupled parts. Prefer domain events over direct
24
+ coupling between services.
25
+
26
+ **Decorator** — When adding cross-cutting concerns (logging, caching, retry,
27
+ auth) to an existing interface without modifying the underlying implementation.
28
+
29
+ ## Format for pattern proposals
30
+
31
+ Before writing implementation code, state:
32
+
33
+ ```
34
+ Pattern: Repository
35
+ Why: Order data is accessed from three services; centralizing queries
36
+ prevents duplication and lets us swap the ORM in tests.
37
+ ```
38
+
39
+ Then proceed with implementation only after the pattern is clear.
40
+
41
+ Do not propose patterns speculatively — only when there is a concrete,
42
+ present need in the current task.
@@ -0,0 +1,61 @@
1
+ ---
2
+ paths: "**/*.ts,**/*.py"
3
+ ---
4
+
5
+ # Error handling
6
+
7
+ Never catch an error and return null, undefined, or a default value. Silent
8
+ catches hide bugs and make debugging impossible. Always let the error surface.
9
+
10
+ ```typescript
11
+ // Anti-pattern — never do this
12
+ async function getUser(id: string) {
13
+ try {
14
+ return await userRepo.findById(id);
15
+ } catch (e) {
16
+ return null; // caller can't distinguish "not found" from "DB exploded"
17
+ }
18
+ }
19
+
20
+ // Correct — propagate at domain layer
21
+ async function getUser(id: string) {
22
+ return await userRepo.findById(id); // let errors propagate
23
+ }
24
+ ```
25
+
26
+ At system boundaries (HTTP handlers, queue consumers, cron jobs), catch errors
27
+ once, log structured metadata, then re-throw or respond with an error status:
28
+
29
+ ```typescript
30
+ // HTTP handler boundary
31
+ async function handleGetUser(req: Request, res: Response) {
32
+ try {
33
+ const user = await userService.getUser(req.params.id);
34
+ res.json(user);
35
+ } catch (err) {
36
+ logger.error({ operation: 'getUser', userId: req.params.id, err });
37
+ res.status(500).json({ error: 'Internal server error' });
38
+ }
39
+ }
40
+ ```
41
+
42
+ Python equivalent — boundary catch with structured log, then re-raise or
43
+ return an error response:
44
+
45
+ ```python
46
+ # FastAPI route boundary
47
+ @router.get("/users/{user_id}")
48
+ async def get_user(user_id: str, service: UserService = Depends(get_user_service)):
49
+ try:
50
+ return await service.get_user(user_id)
51
+ except Exception as err:
52
+ logger.error({"operation": "get_user", "user_id": user_id, "error": str(err)})
53
+ raise HTTPException(status_code=500, detail="Internal server error")
54
+ ```
55
+
56
+ Do not add try/catch inside services or repositories unless you are
57
+ translating a third-party library error into a typed domain error. In that
58
+ case, wrap once at the outermost repository method and throw a domain error.
59
+
60
+ Only add error handling at system boundaries — one catch per entry point, not
61
+ one catch per function call.
@@ -0,0 +1,44 @@
1
+ ---
2
+ paths: "**/*.ts,**/*.tsx"
3
+ ---
4
+
5
+ # SOLID principles
6
+
7
+ ## Single Responsibility Principle
8
+ A module has one reason to change. A class or function that handles HTTP
9
+ parsing, business logic, AND database access has three reasons to change —
10
+ split it. If you cannot describe a module's purpose without "and", it violates SRP.
11
+
12
+ ## Open/Closed Principle
13
+ Extend behavior via composition, not by modifying existing code. Add new
14
+ capabilities by creating new modules or passing new dependencies — do not
15
+ reach into existing implementations and add branches. Prefer strategy objects
16
+ and dependency injection over `if (featureFlag)` conditions in core logic.
17
+
18
+ ## Liskov Substitution Principle
19
+ Subtypes must honor the behavioral contract of the type they extend. If a
20
+ function accepts a `Repository` interface, every concrete implementation must
21
+ satisfy the same pre/postconditions. Never throw additional errors, accept
22
+ fewer inputs, or return narrower output types than the interface declares.
23
+
24
+ ## Interface Segregation Principle
25
+ Define narrow, role-specific interfaces. A `UserRepository` interface should
26
+ not include email-sending methods. Callers should depend only on the interface
27
+ members they actually use — split large interfaces by caller role.
28
+
29
+ ## Dependency Inversion Principle
30
+ High-level modules (services, domain logic) must depend on abstractions
31
+ (interfaces, type aliases), not on concrete implementations (Prisma client,
32
+ specific HTTP framework). Pass concrete implementations via factory function
33
+ arguments or constructor injection so they can be swapped in tests.
34
+
35
+ ## Legacy code and SOLID violations
36
+ If you encounter existing code that violates SOLID principles, do NOT refactor
37
+ it unless explicitly asked to do so. Add a comment noting the violation and
38
+ continue with the requested change:
39
+
40
+ ```typescript
41
+ // TODO: SRP violation — this handler also contains business logic; refactor when scope permits
42
+ ```
43
+
44
+ Unsolicited refactoring introduces risk and scope creep.
@@ -0,0 +1,48 @@
1
+ ---
2
+ globs: "**/resolvers/**,**/handlers/**,**/routes/**,**/app/**"
3
+ alwaysApply: false
4
+ ---
5
+
6
+ # Architecture — handlers, resolvers, and routes
7
+
8
+ The dependency flow is strictly one direction:
9
+ Handler/Resolver → Service → Repository → Data source
10
+
11
+ Never skip or invert layers.
12
+
13
+ ## Handlers are stateless coordinators
14
+
15
+ A handler's only responsibilities:
16
+ 1. Parse and validate the incoming request
17
+ 2. Call the appropriate service method
18
+ 3. Shape the service result into an HTTP response
19
+
20
+ No business logic, domain rules, or data transformation beyond response shaping.
21
+
22
+ ## Never access data sources from handlers or resolvers
23
+
24
+ Never import Prisma, Mongoose, pg, Redis, or any external service SDK directly
25
+ into a handler, resolver, or route file.
26
+
27
+ ```typescript
28
+ // Violation — do not do this
29
+ import { prisma } from '../db/client';
30
+ export async function getOrderHandler(req, res) {
31
+ const order = await prisma.order.findUnique({ where: { id: req.params.id } });
32
+ res.json(order);
33
+ }
34
+
35
+ // Correct — factory injection, delegate to service
36
+ export function createOrderHandler({ orderService }: { orderService: OrderService }) {
37
+ return async (req: Request, res: Response) => {
38
+ const order = await orderService.getOrder(req.params.id);
39
+ res.json(order);
40
+ };
41
+ }
42
+ ```
43
+
44
+ ## Inject dependencies via factory functions
45
+
46
+ Use the `create*` factory pattern. Do not rely on module-level singletons or
47
+ global imports for mutable dependencies. This makes handlers testable without
48
+ module mocking.
@@ -0,0 +1,49 @@
1
+ ---
2
+ globs: "**/*.ts,**/*.py"
3
+ alwaysApply: false
4
+ ---
5
+
6
+ # Clean architecture — layering rules
7
+
8
+ Four layers, dependencies point inward only:
9
+
10
+ ```
11
+ Handler / Controller (HTTP, queues, cron)
12
+
13
+ Service (business rules, orchestration)
14
+
15
+ Repository (data access abstraction)
16
+
17
+ Data source (Prisma, Mongoose, pg, Redis, external APIs)
18
+ ```
19
+
20
+ ## Layer responsibilities
21
+
22
+ **Handler**: HTTP parsing, auth extraction, input validation, response shaping.
23
+ No business logic. Delegates to a service immediately.
24
+
25
+ **Service**: Business rules, domain validation, orchestration across repositories.
26
+ Receives and returns domain types — never raw DB documents.
27
+
28
+ **Repository**: Encapsulates all queries for one aggregate. Returns typed domain
29
+ objects. Translates DB errors to domain errors.
30
+
31
+ **Data source**: The actual client. Only imported inside repository files.
32
+
33
+ ## Coupling violation detector
34
+
35
+ If a file imports from both an HTTP framework (`express`, `fastapi`, `hono`)
36
+ and a database client (`prisma`, `mongoose`, `pg`, `motor`), it is a coupling
37
+ violation. Split it along layer boundaries.
38
+
39
+ ## Services receive domain types, not raw DB documents
40
+
41
+ Repositories must map database results to domain types before returning them.
42
+
43
+ ```typescript
44
+ // Repository — maps to domain type
45
+ async findById(id: string): Promise<User> {
46
+ const doc = await prisma.user.findUniqueOrThrow({ where: { id } });
47
+ return { id: doc.id, email: doc.email, name: doc.name };
48
+ }
49
+ ```
@@ -0,0 +1,43 @@
1
+ ---
2
+ description: "Design patterns — propose applicable patterns before implementing complex solutions involving multiple collaborators, varying behavior, or extension points"
3
+ alwaysApply: false
4
+ ---
5
+
6
+ # Design patterns
7
+
8
+ Before implementing a non-trivial solution, propose the applicable design
9
+ pattern with a one-sentence rationale explaining why it fits. State the
10
+ pattern name explicitly. Do not propose patterns for simple, single-purpose
11
+ functions.
12
+
13
+ ## Patterns to consider and when
14
+
15
+ **Repository** — Multiple parts of the codebase query the same data source.
16
+ Centralizes query logic and allows the data source to be swapped.
17
+
18
+ **Factory** — Object creation involves conditional logic, multiple dependencies,
19
+ or configuration. Use `createX({ dep1, dep2 })` functions.
20
+
21
+ **Strategy** — Behavior varies based on context (payment processors, notification
22
+ channels, export formats). Pass the strategy as a dependency.
23
+
24
+ **Observer / Event emitter** — An action should trigger reactions in decoupled
25
+ parts. Prefer domain events over direct coupling between services.
26
+
27
+ **Decorator** — Adding cross-cutting concerns (logging, caching, retry, auth)
28
+ to an existing interface without modifying the underlying implementation.
29
+
30
+ ## Format for pattern proposals
31
+
32
+ Before writing implementation code, state:
33
+
34
+ ```
35
+ Pattern: Repository
36
+ Why: Order data is accessed from three services; centralizing queries
37
+ prevents duplication and lets us swap the ORM in tests.
38
+ ```
39
+
40
+ Then proceed with implementation only after the pattern is clear.
41
+
42
+ Do not propose patterns speculatively — only when there is a concrete,
43
+ present need in the current task.
@@ -0,0 +1,45 @@
1
+ ---
2
+ globs: "**/*.ts,**/*.py"
3
+ alwaysApply: false
4
+ ---
5
+
6
+ # Error handling
7
+
8
+ Never catch an error and return null, undefined, or a default value. Silent
9
+ catches hide bugs and make debugging impossible. Always let the error surface.
10
+
11
+ ```typescript
12
+ // Anti-pattern — never do this
13
+ async function getUser(id: string) {
14
+ try {
15
+ return await userRepo.findById(id);
16
+ } catch (e) {
17
+ return null; // caller can't distinguish "not found" from "DB exploded"
18
+ }
19
+ }
20
+
21
+ // Correct — propagate at domain layer
22
+ async function getUser(id: string) {
23
+ return await userRepo.findById(id);
24
+ }
25
+ ```
26
+
27
+ At system boundaries (HTTP handlers, queue consumers, cron jobs), catch once,
28
+ log structured metadata `{ operation, identifiers, err }`, then re-throw or
29
+ respond with an error status.
30
+
31
+ Python boundary example:
32
+
33
+ ```python
34
+ @router.get("/users/{user_id}")
35
+ async def get_user(user_id: str, service: UserService = Depends(get_user_service)):
36
+ try:
37
+ return await service.get_user(user_id)
38
+ except Exception as err:
39
+ logger.error({"operation": "get_user", "user_id": user_id, "error": str(err)})
40
+ raise HTTPException(status_code=500, detail="Internal server error")
41
+ ```
42
+
43
+ Only add error handling at system boundaries — one catch per entry point, not
44
+ one catch per function call. Do not add try/catch inside services or
45
+ repositories unless translating a third-party error into a domain error.
@@ -0,0 +1,40 @@
1
+ ---
2
+ globs: "**/*.ts,**/*.tsx"
3
+ alwaysApply: false
4
+ ---
5
+
6
+ # SOLID principles
7
+
8
+ ## Single Responsibility Principle
9
+ A module has one reason to change. If you cannot describe a module's purpose
10
+ without "and", it violates SRP. Split handler, business logic, and data access
11
+ into separate layers.
12
+
13
+ ## Open/Closed Principle
14
+ Extend behavior via composition, not by modifying existing code. Add new
15
+ capabilities with new modules or dependencies — do not add branches to core
16
+ logic. Prefer strategy objects and dependency injection over feature flags
17
+ inside implementations.
18
+
19
+ ## Liskov Substitution Principle
20
+ Subtypes must honor the behavioral contract of the type they extend. Every
21
+ concrete implementation of a `Repository` interface must satisfy the same
22
+ pre/postconditions. Never throw additional errors or return narrower types
23
+ than the interface declares.
24
+
25
+ ## Interface Segregation Principle
26
+ Define narrow, role-specific interfaces. Callers should depend only on the
27
+ interface members they actually use. Split large interfaces by caller role.
28
+
29
+ ## Dependency Inversion Principle
30
+ High-level modules depend on abstractions (interfaces, type aliases), not on
31
+ concrete implementations. Pass concrete implementations via factory function
32
+ arguments so they can be swapped in tests.
33
+
34
+ ## Legacy code and SOLID violations
35
+ If you encounter existing code that violates SOLID, do NOT refactor it unless
36
+ explicitly asked. Add a comment noting the violation and continue:
37
+
38
+ ```typescript
39
+ // TODO: SRP violation — handler contains business logic; refactor when scope permits
40
+ ```
@@ -0,0 +1,28 @@
1
+ ---
2
+ alwaysApply: true
3
+ ---
4
+
5
+ # Plinng Platform — Universal Rules
6
+
7
+ ## How to work
8
+ - Only make changes directly requested. A bug fix does not need surrounding code cleaned up.
9
+ - Do not design for hypothetical future requirements. Three similar lines beat a premature abstraction.
10
+ - Never push to the remote repository without an explicit human request.
11
+ - Use Conventional Commits: `feat:`, `fix:`, `chore:`, `refactor:`, `docs:`, `test:`.
12
+ - Run `moon run <project>:build` and verify no type errors before committing.
13
+ - Do not add docstrings, comments, or type annotations to code you did not change.
14
+
15
+ ## Task runner
16
+ - This monorepo uses Moon as the task runner: `moon run <project>:<task>`.
17
+ - Python services use `uv` for dependency management.
18
+ - Never modify `moon.yml` task definitions without discussing with the platform team first.
19
+
20
+ ## Error handling summary
21
+ - Never hide exceptions with fallback returns (`catch (e) { return null }`).
22
+ - At system boundaries: log `{ operation, identifiers, err }` then re-throw.
23
+ - Inside service and domain layers: let errors propagate.
24
+
25
+ ## Architecture summary
26
+ - Handler → Service → Repository → Data source. Never skip layers.
27
+ - Never import a database client in a handler, resolver, or route file.
28
+ - Use factory function injection: `createHandler({ userRepo, logger })`.
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@plinng/ai-code-assistant-tools",
3
+ "version": "1.0.0",
4
+ "description": "CLI installer for Plinng platform AI coding standards",
5
+ "bin": {
6
+ "ai-code-assistant-tools": "./bin/install.js"
7
+ },
8
+ "scripts": {
9
+ "build": "tsc -p tsconfig.json && node scripts/add-shebang.js",
10
+ "release": "npm run build && npm publish"
11
+ },
12
+ "files": [
13
+ "bin/",
14
+ "claude-code/",
15
+ "cursor/"
16
+ ],
17
+ "engines": {
18
+ "node": ">=20"
19
+ },
20
+ "publishConfig": {
21
+ "access": "public"
22
+ },
23
+ "devDependencies": {
24
+ "@types/node": "^20.0.0",
25
+ "typescript": "^5.7.0"
26
+ }
27
+ }