VP
vp-implement-module
Use when creating a new NestJS module in the VoxPopuli backend - covers service, module, spec file, shared types, and AppModule wiring following project conventions
Install
mkdir -p .claude/skills/vp-implement-module && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/13276" && unzip -o skill.zip -d .claude/skills/vp-implement-module && rm skill.zipInstalls to .claude/skills/vp-implement-module
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Use when creating a new NestJS module in the VoxPopuli backend - covers service, module, spec file, shared types, and AppModule wiring following project conventions164 chars✓ has a “when” trigger
About this skill
Implement NestJS Module (VoxPopuli)
Overview
Pattern for creating a new NestJS module in VoxPopuli. Every module follows the same structure: injectable service, NestJS module with exports, Jest spec file, and wiring into AppModule.
When to Use
- Adding a new domain module to
apps/api/src/ - Implementing a Linear epic that introduces a new service
- Not for: modifying existing modules, frontend work, or eval harness
Module Structure
apps/api/src/{module-name}/
{module-name}.service.ts # @Injectable() service
{module-name}.module.ts # NestJS module
{module-name}.service.spec.ts # Jest tests
{module-name}.controller.ts # Only if HTTP endpoints needed
Implementation Checklist
- Shared types first -- Add any new interfaces to
libs/shared-types/src/lib/shared-types.tsand re-export fromindex.ts - Service --
@Injectable(), constructor injection for dependencies, JSDoc on public methods, strict TypeScript (noany) - Module -- Import dependencies, provide service, export service
- Tests -- Jest with
@swc/jest, useTest.createTestingModule(), mock all external dependencies (HTTP, LLM, cache) - Wire up -- Import module in
apps/api/src/app/app.module.ts - Verify --
npx nx test apiandnpx nx build api
Key Conventions
| Convention | Rule |
|---|---|
| DI | Constructor injection only, no direct imports between modules |
| External calls | All go through CacheService.getOrSet<T>() |
| LLM access | Via LlmService.getModel(), never instantiate providers directly |
| Token budgets | Via LlmService.getMaxContextTokens(), not hardcoded |
| SSE events | Only thought, action, observation, answer, error types |
| Test framework | Jest (not Vitest), mocks via jest.fn() |
Common Mistakes
- Importing between NestJS modules directly instead of using DI
- Forgetting to export service from module (other modules can't inject it)
- Using
ConfigModuleimport in module -- it's already global - Hitting real APIs in tests -- always mock HTTP and LLM calls
- Using
vi.fn()(Vitest) in API tests -- the API project uses Jest, usejest.fn() - Not mocking LLM providers in test files that transitively import
LlmServiceorAgentService-- Jest can't resolve@langchain/*ESM packages. Add these mocks at the top of spec files:jest.mock('../llm/providers/groq.provider', () => ({ GroqProvider: jest.fn() })); jest.mock('../llm/providers/claude.provider', () => ({ ClaudeProvider: jest.fn() })); jest.mock('../llm/providers/mistral.provider', () => ({ MistralProvider: jest.fn() }));