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.
- package/AGENTS.md +23 -1
- package/dist/package.json +1 -1
- package/dist/src/commands/init/init.command.d.ts +1 -0
- package/dist/src/commands/init/init.command.js +34 -1
- package/dist/src/commands/init/init.command.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/skills/doc-gen/SKILL.md +490 -0
- package/skills/doc-gen/scripts/doc_gen.py +911 -0
- package/skills/implement-project/SKILL.md +409 -0
- package/skills/litefront-prototype/SKILL.md +484 -0
- package/skills/start/SKILL.md +319 -0
- package/skills/tech-blueprint/SKILL.md +890 -0
- package/skills/tech-blueprint/scripts/blueprint_validator.py +417 -0
- package/src/commands/init/init.command.ts +43 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
|
@@ -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` должны быть зелёными перед финальным коммитом
|