# AGENTS.md — Hotel Staff ERP v2

Входной документ для AI-агентов: краткая карта проекта, стек, команды и обязательные стандарты. Полная версия стандартов — `.kilocode/rules/rules.md`, карта файлов — `.kilocode/rules/map.md` (автогенерация). При расхождениях приоритет у актуального кода.

## Проект

ERP-система для гостиницы: backend (Fastify, Vertical Slice Architecture) + frontend (Vue 3, Feature-Sliced Design) + shared-контракты (Zod). Monorepo:

| Путь | Содержимое |
|---|---|
| `src/server` | Fastify-сервер, фичи (VSA-слайсы), плагины, cron |
| `src/client` | Vue 3 SPA (FSD: app → processes → pages → widgets → features → entities → shared) |
| `src/shared` | Единый источник типов: Zod-контракты, константы, utils. Ничего не дублируется между client/server |
| `drizzle/` | SQL-миграции (drizzle-kit) |

## Стек

- **Core:** Node.js LTS 20+, npm, TypeScript 5.9, tsx (dev-runner), ESLint 9.
- **Backend:** Fastify 5 (ZodTypeProvider + validatorCompiler/serializerCompiler), Zod v4 + drizzle-zod, Drizzle ORM 0.45 (mysql2), drizzle-kit 0.31, MySQL 8 / MariaDB 10.6+, Socket.io 4.8, JWT в HttpOnly Cookie + argon2, Pino (динамические каналы через `loggerService.get()` + `logger-config.json`), node-cron.
- **Frontend:** Vue 3.5 (`<script setup lang="ts">` только), Vite 7, vue-router 5, Pinia 3 + pinia-plugin-persistedstate, Tailwind CSS 4 (CSS-first: `@import "tailwindcss"` + `@tailwindcss/postcss`; `tailwind.config.js` не используется), grid-layout-plus, lucide-vue-next.
- **Utils:** dayjs (utc, timezone, duration, customParseFormat), axios, lodash-es.
- **Псевдонимы импортов:** `@client`, `@server`, `@features`, `@serverShared`, `@shared`.

## Команды

```bash
npm run dev            # сервер (tsx watch :3000) + клиент (Vite :5173, proxy /api → :3000)
npm run dev:server     # только backend
npm run dev:client     # только frontend
npm run build          # build:server (tsc + tsc-alias) + build:client (vite build)
npm run lint           # ESLint (.ts, .vue)
npm run typecheck      # tsc --noEmit (client tsconfig)
npm run db:generate    # drizzle-kit generate (миграции в drizzle/)
npm run db:migrate     # drizzle-kit migrate
npm run db:push        # drizzle-kit push (dev-синк схемы без миграций)
npm run db:studio      # drizzle-kit studio
npm run update:map     # регенерация .kilocode/rules/map.md (после структурных изменений; руками map.md не редактировать)
npm run gen:context    # сборка контекста для архитектора (architect_context.txt)
```

- **Тестов в проекте нет** — минимальная верификация: `npm run lint` + `npm run typecheck` (обязательно перед сдачей задачи).
- `npm run db:seed` сломан (нет `src/server/scripts/seed.ts`) — не использовать.
- Dev-доступ в приложение: `login: root`, `password: root`.

## Архитектура

### Backend (VSA): `src/server/features/<name>/`

Слайс: `db/<name>.table.ts` (Drizzle; обязательно `id`, `createdAt`, `updatedAt`, `archivedAt`) → `schema.ts` (Zod body/params/query + Output DTO) → `service.ts` (бизнес-логика, только DTO на выходе, `BaseServiceFactory` из `src/server/shared/db/base.service.ts`) → `routes.ts` (ZodTypeProvider) → `index.ts` (Fastify-плагин, префикс `/api/<name>`). Крупные фичи — подпапка `lib/` (`<name>.core.ts`, `<name>.drafts.ts`, `<name>.workflow.ts`, `<name>.mapper.ts`, `<name>.notifications.ts`, `<name>.events.ts` — паттерн approval: менеджер черновик → админ approve/reject).

Ключевое:
- **Изоляция слайсов:** никакого импорта `service.ts` чужой фичи. Связь — только `EventEmitter` (`src/server/shared/lib/events.ts`) с **Standard Event Payload** (см. ниже) и Socket.io (Post-Transaction Emit).
- **Регистрация фичи:** `index.ts` слайса + `src/server/config/modules.ts` + таблица `system_modules` (feature toggling). Выключение фичи — только там, не комментированием кода.
- **Ошибки:** `throw new AppError('Message', statusCode, 'CODE')` (`src/server/shared/lib/errors.ts`); глобальный errorHandler в `app.ts`.
- **Логирование:** `loggerService.get('<CHANNEL>')`; в новых слайсах `console.*` запрещён.
- **Cron:** общие джобы в `src/server/shared/cron/`, фичевые — `<name>.cron.ts`.
- **Сессии:** политики по ролям в `role_session_policies`, плагин `session-guard`; контракт — `src/shared/contracts/session.ts`.
- **Транзакции:** внутри `db.transaction` использовать только `tx`. Upsert — `onDuplicateKeyUpdate`, не «delete + insert».

### Frontend (FSD): `src/client/`

Слои (импорт только сверху вниз): `app` (инициализация, роутер-агрегатор) → `processes` (кросс-фичевые процессы: auth, entitySync, навигация по уведомлениям) → `pages` (композиция виджетов, без логики) → `widgets` → `features` (формы, сценарии) → `entities` (Pinia-сторы, базовый UI) → `shared` (UI Kit, api, lib).

Ключевое:
- **Public API:** каждый каталог в `entities`/`features`/`widgets` имеет `index.ts`; импорт внутренностей модуля запрещён.
- **Роуты:** принадлежат странице (`<page>.routes.ts`); агрегатор — `src/client/app/main.ts`. Мета роута: `requiresAuth`, `moduleName`, `resource` + `action`, `publicAllowed` (публичные страницы, например CheckinPage). Guard-логика централизована в `router.beforeEach`.
- **API:** никакого `axios`/`fetch` в компонентах — только репозитории `src/client/shared/api/` (Zod-интерсептор валидирует ответ, кэш 30 сек). `src/client/shared/api.ts` — legacy, не использовать.
- **Сокеты:** `SocketService` (`src/client/shared/api/SocketService.ts`), подключение после auth; в `onUnmounted` обязателен `socket.off(...)`.
- **Права:** `usePermissions().can('resource:action')` (`src/client/shared/lib/usePermissions.ts`); проверки `role === 'admin'` запрещены. Меню/доступ — через `appConfigStore.enabledModules` (backend-driven).
- **Сторы:** Smart Merge (patch, не полный сброс состояния), идемпотентные обработчики событий, Optimistic UI с откатом.
- **UI Kit (`src/client/shared/ui`):** без зависимостей от сторов — только props.
- **Формы:** Zod-контракты + composable `use<Entity>Form` в entity/model (VeeValidate не используется).
- **Тултипы:** только `AppCursorTooltip` + `useMouseFollower()` (`src/client/shared/lib/useMouseFollower.ts`); floating-vue/v-tooltip/title запрещены.
- **Teleport:** внутри обязательно `v-if="isMounted"`.
- **Стили:** Tailwind v4; кастомные стили >10 строк — в `ComponentName.css`.
- **Grid/DnD дашбордов** (NotesBoard, TasksBoard): только `grid-layout-plus`.

### Shared: `src/shared/`

`contracts/` — Zod-схемы и типы (`z.infer`) для обеих сторон; ручное описание DTO на клиенте **запрещено**. `constants/` — роли, статусы. `lib/` — чистые утилиты (например, `sanitize`). Изменение структуры данных начинается с контракта, потом бэкенд, потом фронтенд.

## Обязательные стандарты (дайджест)

1. **Язык:** код — English; UI-тексты и комментарии — Russian.
2. **Заголовок файла:** каждая строка файла начинается с комментария-пути и описания: `// path/to/file.ts` + 1 предложение.
3. **Naming:** Drizzle-таблицы импортируются с суффиксом `Table` (`employeesTable`); маппинг snake_case (БД) ↔ camelCase (API) через `src/server/shared/lib/case.ts`.
4. **Standard Event Payload** (все события Emitter/Socket):
   ```typescript
   { action: string; payload: T; metadata: { timestamp: number; userId: string } }
   ```
5. **Даты:** БД — UTC; backend — `dayjs.tz` (Europe/Moscow, `src/server/shared/lib/dayjs.ts`); фронтенд — локальный показ.
6. **Soft delete:** вместо `DELETE` — `archivedAt`; выборки с `isNull(table.archivedAt)`.
7. **Маппинг DTO:** никакого `{ ...row }` — Boolean/Date/null приводятся явно в mapper'е.
8. **Auth:** HttpOnly Cookie (не Bearer); пароли — только argon2.
9. **RBAC:** реестр прав — `src/shared/contracts/permissions.ts`; backend — `fastify.can('resource:action')`, frontend — `usePermissions()`.
10. **XSS:** `v-html` запрещён; `v-text` или `sanitize` из `@shared/lib/sanitize`; упоминания — `MentionDisplay.vue` (без v-html); текст в тултипы — через `stripMentionTags()`.
11. **Типы:** только `z.infer` из `@shared/contracts`; дублирование типов между слоями запрещено (DRY).

## Прогресс и карта проекта

- После **каждой** задачи — запись в `PROGRESS.md` (формат: заголовок задачи, «✅ Выполнено» со списком изменений и ссылками на файлы, «🎯 Результат»). При переполнении — архивация в `PROGRESS_N.md`.
- После структурных изменений (новые/удалённые файлы) — `npm run update:map` (`.kilocode/rules/map.md` не редактировать руками).

## Переменные окружения

| Переменная | Назначение |
|---|---|
| `APP_ENV` | `development` / `production` |
| `PORT` | Порт Fastify (по умолчанию 3000) |
| `CORS_ORIGIN` | Разрешённые origin (через запятую) |
| `COOKIE_SECURE` / `COOKIE_SAMESITE` | Параметры auth-cookie |
| `TRUST_PROXY` | trustProxy Fastify (за реверс-прокси) |
| `JWT_SECRET` | Секрет подписи JWT |
| `VITE_SOCKET_URL` | URL Socket.io для клиента (по умолчанию `http://localhost:3000`) |

Централизованный доступ к env на сервере — `src/server/shared/lib/env.ts`. Dev-среда: БД `root/root`, клиент `:5173` проксирует `/api` на `:3000`.
