kodu 2.1.2 → 2.1.3

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.
@@ -0,0 +1,409 @@
1
+ ---
2
+ name: implement-project
3
+ description: Реализует полный проект по готовым документации, ТЗ и прототипу. Инициализирует бэкенд (liteend-init) и фронтенд (litefront-init), реализует все сущности/операции/страницы, покрывает тестами, верифицирует соответствие документам. Запускай когда VISION.md + SPEC.md готовы и tech-blueprint утверждён. НЕ запускай если ТЗ ещё черновик или проект уже частично реализован.
4
+ license: MIT
5
+ compatibility: opencode
6
+ metadata:
7
+ level: multi
8
+ output: папка projects/<ИмяПроекта>/
9
+ ---
10
+
11
+ ## Назначение
12
+
13
+ Скилл берёт готовые артефакты проектирования и **реализует проект от нуля до работающего состояния с тестами**:
14
+ - Инициализирует бэкенд и фронтенд из стартовых шаблонов
15
+ - Имплементирует всю бизнес-логику строго по ТЗ
16
+ - Покрывает тестами согласно TESTING_PLAN.md
17
+ - Верифицирует соответствие документации и запускает полный прогон проверок
18
+
19
+ **Когда запускать:**
20
+ - `docs/<name>/` и `blueprint/<name>/3_TECH_BLUEPRINT/` готовы и утверждены
21
+ - ТЗ прошло валидацию `blueprint_validator.py` без ошибок
22
+ - Команда готова к разработке
23
+
24
+ **Когда НЕ запускать:**
25
+ - ТЗ в черновике или не прошло валидацию
26
+ - Проект уже частично реализован (это не скилл для рефакторинга)
27
+ - Задача — добавить одну фичу, а не построить проект с нуля
28
+
29
+ ---
30
+
31
+ ## Входные данные
32
+
33
+ Перед началом **обязательно прочитать** все документы:
34
+
35
+ ```
36
+ docs/<ИмяПроекта>/
37
+ ├── 1_PRODUCT_VISION/VISION.md ← бизнес-цели, границы, роли
38
+ └── 2_PRODUCT_SPEC/SPEC.md ← сущности, операции, страницы, бизнес-правила
39
+
40
+ blueprint/<ИмяПроекта>/3_TECH_BLUEPRINT/
41
+ ├── IMPLEMENTATION_GUIDE.md ← стек, что уже готово, команды запуска
42
+ ├── DATABASE_MODEL.md ← Prisma-схема всех моделей
43
+ ├── API_CONTRACTS.md ← GraphQL-схема, guards, пагинация
44
+ ├── ARCHITECTURE.md ← NestJS-модули, FSD-слайсы, состояние
45
+ └── TESTING_PLAN.md ← unit-тесты, E2E-сценарии, coverage
46
+
47
+ prototype/ ← UI-прототип (только для понимания UX-потоков)
48
+ ```
49
+
50
+ Если любой из первых шести документов отсутствует — **остановиться** и сообщить пользователю какого файла не хватает. Прототип опционален.
51
+
52
+ ---
53
+
54
+ ## Структура вывода
55
+
56
+ ```
57
+ projects/<ИмяПроекта>/
58
+ ├── backend/ ← NestJS + Fastify API (инициализируется через liteend-init)
59
+ └── frontend/ ← React SPA (инициализируется через litefront-init)
60
+ ```
61
+
62
+ Создать корневую папку до инициализации:
63
+ ```bash
64
+ mkdir -p projects/<ИмяПроекта>
65
+ ```
66
+
67
+ ---
68
+
69
+ ## Процесс реализации
70
+
71
+ ### Шаг 0. Анализ документации
72
+
73
+ 1. Прочитать все документы целиком
74
+ 2. Составить внутренний рабочий список:
75
+ - Prisma-модели из DATABASE_MODEL.md (без Profile/ProfileRole — они уже в шаблоне)
76
+ - GraphQL-операции по доменам из API_CONTRACTS.md (без `me`, `updateProfile`, `profileUpdated`, `debug`, `echo`)
77
+ - NestJS-модули из ARCHITECTURE.md §Backend
78
+ - FSD-слайсы для реализации из ARCHITECTURE.md §Frontend (без `features/auth`, `widgets/Header`, `pages/404`, `shared/api/graphql-client`)
79
+ - Тест-сценарии из TESTING_PLAN.md
80
+ 3. Зафиксировать: всё из стартовых шаблонов — **не трогать и не дублировать**
81
+
82
+ ---
83
+
84
+ ### Шаг 1. Инициализация бэкенда
85
+
86
+ Запустить скилл **liteend-init** (`~/.config/opencode/skills/liteend-init/SKILL.md`):
87
+
88
+ ```
89
+ project_name: projects/<ИмяПроекта>/backend
90
+ use_docker: true
91
+ install_deps: true
92
+ ```
93
+
94
+ После завершения:
95
+ - Прочитать `projects/<ИмяПроекта>/backend/AGENTS.md` — понять доступные команды проекта
96
+ - Убедиться что `GET /health` отвечает 200 (бэкенд запустился)
97
+
98
+ ---
99
+
100
+ ### Шаг 2. Реализация бэкенда
101
+
102
+ **2.1. Схема базы данных**
103
+
104
+ Открыть `backend/prisma/schema.prisma` и **добавить** новые модели из DATABASE_MODEL.md к существующим:
105
+ - Существующие модели `Profile`, `ProfileRole` — не изменять
106
+ - Для связи новых сущностей с пользователем: `profileId Int` + `@relation(fields: [profileId], references: [id], onDelete: Cascade)`
107
+ - Все связи — с явным `onDelete`; все перечислимые значения — только через `enum`
108
+
109
+ Применить миграцию:
110
+ ```bash
111
+ # внутри backend/
112
+ npm run db:migrations:apply
113
+ ```
114
+
115
+ **2.2. NestJS-модули**
116
+
117
+ Для каждого модуля из ARCHITECTURE.md §Backend создать структуру:
118
+ ```
119
+ src/modules/<domain>/
120
+ ├── <domain>.module.ts ← @Module({ imports, providers, exports })
121
+ ├── <domain>.resolver.ts ← @Resolver() с GraphQL-операциями
122
+ ├── <domain>.service.ts ← бизнес-логика, Prisma-запросы
123
+ └── dto/
124
+ └── <entity>.input.ts ← ZodDto или class-validator Input для мутаций
125
+ ```
126
+
127
+ Правила реализации резолверов:
128
+ - Guards соответствуют директивам доступа из API_CONTRACTS.md:
129
+ ```typescript
130
+ @UseGuards(JwtAuthGuard) // # @auth в API_CONTRACTS.md
131
+ @UseGuards(JwtOptionalAuthGuard) // # @auth? в API_CONTRACTS.md
132
+ @Roles(ProfileRole.ADMIN) // # @auth @hasRole(ADMIN)
133
+ // без guard // # @public
134
+ ```
135
+ - Текущий пользователь: `@CurrentUser() profile: Profile`
136
+ - Ошибки: выбрасывать `HttpException` или `ZodValidationException` — `gqlErrorFormatter` сам преобразует
137
+ - Soft delete: при `deletedAt DateTime?` в модели → фильтровать `{ deletedAt: null }` во **всех** запросах Prisma
138
+ - Пагинация: все списочные операции принимают `limit`/`offset` и возвращают `{ items, total, hasMore }`
139
+
140
+ **2.3. Subscriptions**
141
+
142
+ Если в API_CONTRACTS.md есть Subscription-операции — реализовывать через Redis pub/sub (уже настроен). Не добавлять новых transport-зависимостей.
143
+
144
+ **2.4. Коммит бэкенда**
145
+ ```bash
146
+ git add .
147
+ git commit -m "feat(backend): реализация бизнес-логики <ИмяПроекта>"
148
+ ```
149
+
150
+ ---
151
+
152
+ ### Шаг 3. Инициализация фронтенда
153
+
154
+ Запустить скилл **litefront-init** (`~/.config/opencode/skills/litefront-init/SKILL.md`):
155
+
156
+ ```
157
+ project_name: projects/<ИмяПроекта>/frontend
158
+ install_deps: true
159
+ setup_env: true
160
+ run_dev: false
161
+ ```
162
+
163
+ Настроить `.env` фронтенда:
164
+ ```
165
+ VITE_GRAPHQL_API_URL=http://localhost:<PORT>/graphql
166
+ VITE_BASE_URL=http://localhost:<FRONT_PORT>
167
+ VITE_OIDC_AUTHORITY=<из IMPLEMENTATION_GUIDE.md>
168
+ VITE_OIDC_CLIENT_ID=<из IMPLEMENTATION_GUIDE.md>
169
+ ```
170
+
171
+ Запустить бэкенд в фоне и сгенерировать GraphQL-типы:
172
+ ```bash
173
+ # в backend/:
174
+ npm run start:dev &
175
+
176
+ # в frontend/:
177
+ npm run gen
178
+ ```
179
+
180
+ Прочитать `projects/<ИмяПроекта>/frontend/AGENTS.md` — понять доступные команды.
181
+
182
+ **3.5. Корневой AGENTS.md проекта**
183
+
184
+ Создать `projects/<ИмяПроекта>/AGENTS.md`:
185
+
186
+ ```markdown
187
+ # <ИмяПроекта>
188
+
189
+ ## Структура проекта
190
+
191
+ - `backend/` — NestJS + Fastify API
192
+ - `frontend/` — React SPA
193
+
194
+ ## Важно
195
+
196
+ При работе с бэкендом **обязательно прочитать** `backend/AGENTS.md`.
197
+ При работе с фронтендом **обязательно прочитать** `frontend/AGENTS.md`.
198
+
199
+ Каждый подпроект содержит специфичные команды, соглашения и особенности среды,
200
+ которые необходимо знать перед внесением изменений.
201
+ ```
202
+
203
+ ---
204
+
205
+ ### Шаг 4. Реализация фронтенда
206
+
207
+ **4.1. FSD-слайсы (только новые)**
208
+
209
+ Для каждого слайса из ARCHITECTURE.md §Frontend: FSD-слайсы создать структуру:
210
+ ```
211
+ src/
212
+ ├── entities/<name>/
213
+ │ ├── api/ ← URQL useQuery / useMutation с типами из npm run gen
214
+ │ └── model/ ← TypeScript-типы, трансформации данных
215
+ ├── features/<name>/
216
+ │ ├── ui/ ← React-компоненты
217
+ │ └── model/ ← Zustand-стор или локальное состояние
218
+ └── widgets/<name>/
219
+ └── ui/
220
+ ```
221
+
222
+ Правила:
223
+ - GraphQL-запросы: только через URQL, типы из `npm run gen` — без `any`
224
+ - Zustand-стор: `create(devtools<MyStore>((set, get) => ({ ... })))` — только UI-состояние, не дублировать серверные данные
225
+ - Компоненты: из прототипа брать только UX-логику (потоки, формы), не копировать код
226
+ - **Тема и стиль:** взять из прототипа как базовую основу — цветовая схема, типографика, отступы, визуальный язык. Реальные компоненты должны выглядеть узнаваемо по сравнению с прототипом
227
+ - **Никаких замоканных данных в production-коде:** все данные получаются через GraphQL-запросы к бэкенду. Хардкод данных и `mockData`-константы допустимы только в тестах (`*.test.ts`, `*.spec.ts`, `tests/`)
228
+
229
+ **4.2. Страницы и роутинг**
230
+
231
+ Для каждой страницы из ARCHITECTURE.md §Pages создать файл в `src/routes/`:
232
+
233
+ ```typescript
234
+ // Защищённая страница (паттерн beforeLoad):
235
+ export const Route = createFileRoute('/my-page')({
236
+ beforeLoad: ({ context: { auth } }) => {
237
+ if (!auth.isAuthenticated) throw redirect({ to: '/' })
238
+ },
239
+ component: () => <AuthGuard><MyPage /></AuthGuard>,
240
+ })
241
+
242
+ // Публичная страница:
243
+ export const Route = createFileRoute('/public-page')({
244
+ component: MyPublicPage,
245
+ })
246
+ ```
247
+
248
+ **4.3. Переменные окружения**
249
+
250
+ Добавить в `.env` переменные из ARCHITECTURE.md §Переменные окружения (только бизнес-специфичные).
251
+
252
+ **4.4. i18n**
253
+
254
+ Если ARCHITECTURE.md §Frontend: локализация содержит namespace'ы — создать файлы переводов в `messages/`.
255
+
256
+ **4.5. Коммит фронтенда**
257
+ ```bash
258
+ git add .
259
+ git commit -m "feat(frontend): реализация <ИмяПроекта>"
260
+ ```
261
+
262
+ ---
263
+
264
+ ### Шаг 5. Тесты
265
+
266
+ Реализовать все сценарии из TESTING_PLAN.md. **Не пропускать сценарии** — каждый описан в документе.
267
+
268
+ **Backend E2E (Vitest + E2EClient):**
269
+ ```typescript
270
+ describe('<Domain>Resolver', () => {
271
+ let client: E2EClient
272
+
273
+ beforeEach(async () => {
274
+ await clearDatabase()
275
+ await clearRedis()
276
+ client = await createTestClient()
277
+ })
278
+
279
+ it('успешный сценарий', async () => {
280
+ const profile = await createTestProfile()
281
+ await client.loginAs(profile)
282
+ const result = await client.requestGraphQL<QueryType>(QUERY, vars)
283
+ expect(result.data).toBeDefined()
284
+ })
285
+
286
+ it('негативный сценарий — нет прав', async () => {
287
+ const result = await client.requestGraphQL<QueryType>(QUERY, vars)
288
+ expect(result.errors?.[0].message).toContain('Unauthorized')
289
+ })
290
+ })
291
+ ```
292
+
293
+ **Backend unit (Vitest + NestJS Testing Module):**
294
+ ```typescript
295
+ describe('<Domain>Service.complexMethod', () => {
296
+ it('корректно рассчитывает ...', () => {
297
+ const result = service.complexMethod(input)
298
+ expect(result).toEqual(expected)
299
+ })
300
+ })
301
+ ```
302
+
303
+ **Frontend component (Vitest + React Testing Library):**
304
+ ```typescript
305
+ describe('<ComponentName>', () => {
306
+ it('отображает состояние загрузки', () => {
307
+ render(<MyComponent loading />)
308
+ expect(screen.getByRole('progressbar')).toBeInTheDocument()
309
+ })
310
+ })
311
+ // OIDC автоматически замокан через tests/setup.ts — дополнительная настройка не нужна
312
+ ```
313
+
314
+ **Frontend E2E (Playwright):**
315
+ ```typescript
316
+ // Запускать с VITE_MOCK_AUTH=true — MockAuthProvider авторизует автоматически
317
+ test('критический путь: <название>', async ({ page }) => {
318
+ await page.goto('/target-page')
319
+ await page.getByRole('button', { name: 'Действие' }).click()
320
+ await expect(page.getByText('Успех')).toBeVisible()
321
+ })
322
+ ```
323
+
324
+ **Коммит тестов:**
325
+ ```bash
326
+ git add .
327
+ git commit -m "test(<ИмяПроекта>): покрытие по TESTING_PLAN.md"
328
+ ```
329
+
330
+ ---
331
+
332
+ ### Шаг 6. Верификация (обязательна — не пропускать)
333
+
334
+ **6.1. Автоматические проверки**
335
+
336
+ Запустить в обоих проектах:
337
+ ```bash
338
+ # Бэкенд:
339
+ cd projects/<ИмяПроекта>/backend && npm run check && npm run test:all
340
+
341
+ # Фронтенд:
342
+ cd projects/<ИмяПроекта>/frontend && npm run check && npm run test:all
343
+ ```
344
+
345
+ **Если хотя бы одна команда завершается с ошибкой — устранить причину и запустить повторно.** Проект не считается реализованным, пока все проверки не зелёные.
346
+
347
+ **6.2. Ручной чеклист по документам**
348
+
349
+ Сверить реализацию с каждым документом:
350
+
351
+ **DATABASE_MODEL.md:**
352
+ - [ ] Каждая Prisma-модель из документа существует в `schema.prisma`
353
+ - [ ] Все миграции применены — `prisma migrate status` без pending
354
+ - [ ] Индексы `@@index`, уникальные ограничения `@@unique` соответствуют документу
355
+ - [ ] Каскадные операции `onDelete`/`onUpdate` соответствуют документу
356
+
357
+ **API_CONTRACTS.md:**
358
+ - [ ] Каждая Query/Mutation/Subscription реализована в соответствующем резолвере
359
+ - [ ] Guards соответствуют директивам (`# @auth` → `JwtAuthGuard`, `# @public` → без guard)
360
+ - [ ] Типы возвращаемых значений совпадают (включая wrapper-типы пагинации)
361
+ - [ ] Input-типы мутаций соответствуют схеме
362
+
363
+ **ARCHITECTURE.md:**
364
+ - [ ] Все NestJS-модули из §Backend реализованы и зарегистрированы в AppModule
365
+ - [ ] Все FSD-слайсы из §Frontend реализованы (кроме boilerplate-слайсов)
366
+ - [ ] Все страницы из §Pages существуют и маршрутизируются корректно
367
+ - [ ] Серверный стейт управляется через URQL, UI-стейт — через Zustand
368
+
369
+ **TESTING_PLAN.md:**
370
+ - [ ] Все сценарии из §Unit-тесты реализованы
371
+ - [ ] Все сценарии из §E2E-сценарии реализованы
372
+ - [ ] Все сценарии из §Критические пути покрыты
373
+ - [ ] Все сценарии из §Негативные сценарии покрыты
374
+ - [ ] Coverage: statements / functions / lines ≥ 80%, branches ≥ 70%
375
+
376
+ **SPEC.md:**
377
+ - [ ] Все бизнес-сущности из §Сущности присутствуют в коде
378
+ - [ ] Все бизнес-правила из §Ключевые операции реализованы и соблюдены
379
+ - [ ] Все страницы из §Страницы реализованы
380
+
381
+ **Прототип:**
382
+ - [ ] Ключевые UX-потоки прототипа воспроизводятся в готовом продукте
383
+ - [ ] Формы, действия и обратная связь пользователю соответствуют прототипу
384
+ - [ ] Визуальный стиль (цвета, типографика, компоновка) соответствует прототипу
385
+ - [ ] В production-коде нет замоканных данных, хардкод-констант и `TODO: replace with API`
386
+
387
+ ---
388
+
389
+ ### Шаг 7. Финальный коммит
390
+
391
+ ```bash
392
+ git add .
393
+ git commit -m "feat(<ИмяПроекта>): полная реализация — все тесты зелёные"
394
+ ```
395
+
396
+ ---
397
+
398
+ ## Ключевые ограничения
399
+
400
+ - **Не дублировать стартовый шаблон:** модель `Profile`, операции `me`/`updateProfile`/`profileUpdated`, слайсы `features/auth`, `widgets/Header`, `pages/404`, `shared/api/graphql-client` — уже готовы, не трогать
401
+ - **Только типизированный код:** TypeScript без `any`; GraphQL-типы — только из `npm run gen`
402
+ - **Soft delete:** при `deletedAt DateTime?` → фильтровать `{ deletedAt: null }` во всех Prisma-запросах
403
+ - **Пагинация:** все списочные операции возвращают `{ items: [...], total: Int, hasMore: Boolean }`
404
+ - **Тесты обязательны** для каждого сценария из TESTING_PLAN.md — не пропускать, не заглушать
405
+ - **Читать AGENTS.md** обоих проектов — там могут быть специфичные команды и соглашения
406
+ - **Порядок имплементации:** бэкенд → фронтенд (генерация GraphQL-типов требует работающего бэкенда)
407
+ - **Нет замоканным данным в production:** `mockData`, хардкод-массивы, `TODO: replace with API` — запрещены в production-коде; допустимы только в тестовых файлах
408
+ - **Тема берётся из прототипа:** реальный UI должен воспроизводить визуальный язык прототипа — цвета, типографику, компоновку
409
+ - **Верификация блокирующая:** `npm run check && npm run test:all` должны быть зелёными перед финальным коммитом