用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/mkaraivanov/invoice-processor --skill new-service命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
基于 SOC 职业分类
| name | new-service |
| description | Scaffold a service class for a given domain following project conventions |
| disable-model-invocation | true |
| argument-hint | [domain-name] |
Scaffold a service for the $ARGUMENTS domain.
src/services/$ARGUMENTS.service.tssrc/types/index.ts (add alongside existing schemas)import { ${camelCase}Repository } from '@/repositories/$ARGUMENTS.repository'
import { createInputSchema, type CreateInput } from '@/types'
export const ${camelCase}Service = {
async create(userId: string, input: CreateInput) {
createInputSchema.parse(input) // validate first
return ${camelCase}Repository.create({ ...input, userId })
},
async getById(id: string, userId: string) {
const record = await ${camelCase}Repository.findById(id)
if (!record) throw new Error('Not found')
if (record.userId !== userId) throw new Error('Unauthorized') // AFTER fetch
return record
},
async listForUser(userId: string) {
return ${camelCase}Repository.findMany({ userId })
},
async update(id: string, userId: string, input: CreateInput) {
createInputSchema.parse(input)
const existing = await ${camelCase}Repository.findById(id)
if (!existing) throw new Error('Not found')
if (existing.userId !== userId) throw new Error('Unauthorized')
return ${camelCase}Repository.update(id, input)
},
async delete(id: string, userId: string) {
const existing = await ${camelCase}Repository.findById(id)
if (!existing) throw new Error('Not found')
if (existing.userId !== userId) throw new Error('Unauthorized')
return ${camelCase}Repository.delete(id)
},
}
The check goes AFTER the fetch, not before. This is intentional:
'Not found' (becomes 404)'Unauthorized' (becomes 403)
Checking before the fetch would collapse both cases into 403 and leak that a record exists.userId flows in as a parameterServices do NOT call authService.getUser() internally. The API route retrieves the user from the session and passes userId into every service method. This keeps services testable in isolation.
@/repositories/...@/typesprisma directly — that is the repository's job@prisma/clientDefine in src/types/index.ts:
export const createInvoiceSchema = z.object({ ... })
export type CreateInvoiceInput = z.infer<typeof createInvoiceSchema>
npx tsc --noEmit
Implement a numbered testing strategy phase from docs/testing_strategy_phases/phase_$ARGUMENTS_*.md step by step
Implement a numbered phase from docs/phases/phase-$ARGUMENTS.md step by step
Review changed code for correctness, security, and project conventions. Invoke this skill automatically whenever a complete unit of work is done — a full implementation phase, a complete feature (repository + service + route + component all connected), or just before creating a PR. Do NOT invoke after editing a single file or mid-way through a feature. If the user says "done", "finished", "phase complete", "ready to commit", or similar, trigger this review immediately.