19 KiB
19 KiB
Руководство по развёртыванию и чек-лист боевого тестирования Krona Staff
1. Назначение и архитектурные инварианты
Krona Staff — автономно развёртываемый блок Krona Business Platform, отвечающий за учёт рабочего времени, терминалы посещаемости и управленческий расчёт зарплаты.
Ключевые инварианты (AGENTS.md)
- Разделение доменов: Core владеет Tenant, User, Role, SSO, Platform Settings, Files, Notifications. Staff владеет Employee и HR-доменом (
User != Employee). - Изоляция арендаторов: Все таблицы содержат
tenant_id(ULID 26 символов). В PostgreSQL включен и принудительно активирован Row-Level Security (FORCE ROW LEVEL SECURITY). Запросы выполняются через tenant-scoped транзакции с выставлениемapp.tenant_id. - Разделение ролей БД:
krona_migrator— владелец схемы и таблиц, выполняет миграции DDL,NOSUPERUSER NOBYPASSRLS.krona_staff_app— runtime-пользователь приложения с минимальными DML правами (SELECT, INSERT, UPDATE, DELETE на прикладные таблицы; нет прав наschema_migrations, нет прав DDL).
- Типы данных:
- Идентификаторы — ULID (
VARCHAR(26)). - Денежные суммы —
BIGINTв минимальных единицах (копейках/minor units) + ISO 4217 код валюты (например,'RUB'). - Временные метки — UTC (
TIMESTAMPTZ).
- Идентификаторы — ULID (
- Надёжность: Транзакционный Outbox, идемпотентность по
Idempotency-Key, CSRF-защита сессионных cookie (Origin/Sec-Fetch-Site), Rate-limiting ключей входа.
2. Развёртывание и запуск
2.1. Системные требования
- ОС: Linux (Ubuntu 22.04+/Debian 12+) или Windows Server 2022+ / Windows 11 (для сборки терминала).
- Среда выполнения: Node.js 22 LTS, npm 10+.
- База данных: PostgreSQL 17 (поддерживается 17.0+).
- Сеть: Порт 8080 (HTTP) или 8453 (HTTPS пилот).
2.2. Запуск через Docker Compose (рекомендуемый пилот)
# 1. Перейдите в каталог deploy/pilot
cd deploy/pilot
# 2. Задайте ULID организации из Krona Business Platform
export STANDALONE_TENANT_ID="01J0000000000000000000000A"
# 3. Выполните скрипт первичной инициализации:
# - Сгенерирует стойкие пароли БД, токены менеджера и терминала в secrets/
# - Сгенерирует ключи Web Push (VAPID)
# - Создаст самоподписанный TLS-сертификат для терминала
./setup.sh
# 4. Запустите стек (PostgreSQL + мигратор + app)
docker compose up -d --build
# 5. Проверьте запуск контейнеров и миграций
docker compose ps
docker compose logs -f app
2.3. Запуск без Docker (Bare-Metal / Dev стенд)
-
Создайте базу данных и роли в PostgreSQL:
-- Под пользователем postgres (DBA): CREATE ROLE krona_migrator LOGIN PASSWORD 'migrator_secure_password' NOSUPERUSER NOCREATEDB NOCREATEROLE NOBYPASSRLS; CREATE ROLE krona_staff_app LOGIN PASSWORD 'app_secure_password' NOSUPERUSER NOCREATEDB NOCREATEROLE NOINHERIT NOBYPASSRLS; CREATE DATABASE krona_staff OWNER krona_migrator ENCODING 'UTF8'; \c krona_staff ALTER SCHEMA public OWNER TO krona_migrator; REVOKE CREATE ON SCHEMA public FROM PUBLIC; REVOKE ALL ON DATABASE krona_staff FROM PUBLIC; GRANT CONNECT ON DATABASE krona_staff TO krona_staff_app; -
Настройте переменные окружения (
.env):cp .env.example .envУкажите в
.env:PORT=8080 NODE_ENV=production STANDALONE_TENANT_ID=01J0000000000000000000000A STANDALONE_ACTOR_ID=01J00000000000000000000001 STANDALONE_MANAGER_TOKEN=your_secure_manager_token_hex_or_ulid STANDALONE_TERMINAL_TOKEN=your_secure_terminal_token_hex_or_ulid DATABASE_URL=postgres://krona_staff_app:app_secure_password@127.0.0.1:5432/krona_staff DATABASE_MIGRATION_URL=postgres://krona_migrator:migrator_secure_password@127.0.0.1:5432/krona_staff -
Сгенерируйте VAPID ключи:
node scripts/generate-vapid-keys.mjs >> .env -
Примените миграции:
npm run db:migrate -
Соберите и запустите приложение:
npm run build npm run start
3. Чек-лист ручного боевого тестирования владельцем
Каждый шаг должен быть выполнен последовательно. Ожидаемый результат сверяется с фактическим.
| № | Шаг / Сценарий | Действие / HTTP-запрос | Ожидаемый результат | Статус |
|---|---|---|---|---|
| 1 | Системные проверки (Health) | GET /api/v1/staff/liveGET /api/v1/staff/readyGET /api/v1/staff/version |
HTTP 200 на всех эндпоинтах. ready подтверждает соединение с БД под ролью krona_staff_app. version возвращает runtime: standalone и semver. |
[ ] |
| 2 | Контракт OpenAPI | GET /api/v1/staff/openapi.json |
HTTP 200, возвращается валидная спецификация OpenAPI 3.1 со всеми роутами модуля. | [ ] |
| 3 | Защита доступа (401) | GET /api/v1/staff/portal без заголовка Authorization |
HTTP 401 Unauthorized. Ошибки с деталями SQL отсутствуют. | [ ] |
| 4 | Защита от CSRF | POST /api/v1/staff/portal/employees с cookie сессии, но без заголовка Origin или с чужим Origin |
HTTP 403 Forbidden (CSRF token missing/invalid). | [ ] |
| 5 | Защита от перебора паролей (429) | 35 последовательных запросов с неверным токеном/ключом | После исчерпания лимита возвращается HTTP 429 Too Many Requests с заголовком Retry-After. |
[ ] |
| 6 | Создание сотрудника | POST /api/v1/staff/employeesHeaders: Authorization: Bearer <MANAGER_TOKEN>Body: {"personnel_number": "EMP-001", "display_name": "Иванов Иван", "profession_code": "cook"} |
HTTP 201 Created. Создан сотрудник, присвоен ULID, запись зафиксирована в staff_employees. |
[ ] |
| 7 | Проверка справочника профессий | GET /api/v1/staff/professions |
HTTP 200, список активных профессий (cook, cashier, barista, waiter и др.). |
[ ] |
| 8 | Назначение тарифной ставки сотруднику | POST /api/v1/staff/payroll/assignmentsBody: привязка правила (почасовая ставка 350 руб/час = 35000 minor units). |
HTTP 201 Created. Версионированное правило сохранено в staff_pay_assignments. |
[ ] |
| 9 | Отметка прихода через терминал | POST /api/v1/staff/attendance/eventsHeaders: Authorization: Bearer <TERMINAL_TOKEN>Body: {"event_id": "<ULID>", "employee_id": "<EMP_ID>", "event_type": "check_in", "occurred_at": "<NOW_ISO>"} |
HTTP 201 Created. Событие записано в staff_attendance_events. Отправлено событие в outbox. |
[ ] |
| 10 | Идемпотентность отметки | Повтор запроса шага 9 с тем же event_id и source_event_id |
HTTP 200 OK (или 201), дубликат не создаётся, количество записей не удваивается. | [ ] |
| 11 | Отметка ухода через терминал | POST /api/v1/staff/attendance/events с event_type: "check_out" спустя 8 часов |
HTTP 201 Created. Формируется завершённая рабочая смена. | [ ] |
| 12 | Подтверждение смены менеджером | POST /api/v1/staff/work-sessions/:id/confirm |
HTTP 200 OK. Смена переходит в статус confirmed, часы готовы к начислению. |
[ ] |
| 13 | Авторасчёт ведомости зарплаты | POST /api/v1/staff/payroll/runs/auto-calcBody: период с 1 по 15 число месяца. |
HTTP 201 Created. Начислено: 8 ч × 350 руб = 2800 руб (280000 minor units). Сохранена расшифровка формулы расчёта. | [ ] |
| 14 | Согласование ведомости бухгалтером | POST /api/v1/staff/payroll/batches/:id/approve |
HTTP 200 OK. Статус пакета переходит в approved. |
[ ] |
| 15 | Подписание ведомости директором | POST /api/v1/staff/payroll/batches/:id/signBody: {"signature": "director_sign_key", "note": "Выплата за первую половину месяца"} |
HTTP 200 OK. Пакет подписан. Созданы строки начислений в staff_payroll_ledger с полем note (без ошибки 500!). |
[ ] |
| 16 | Проверка реестра выплат (Ledger) | GET /api/v1/staff/payroll/ledger |
HTTP 200 OK. Отображаются начисления и выплаты, сальдо корректно сходится. | [ ] |
| 17 | Web Push уведомления сотруднику | POST /api/v1/staff/portal/push-subscriptions с валидным FCM/W3C endpoint. |
HTTP 201 Created. Подписка сохранена. При наступлении события формируется delivery без ложных блокировок хоста. | [ ] |
| 18 | Уведомления директору без дублей | GET /api/v1/staff/notifications/unread под учётной записью директора |
HTTP 200 OK. Каждому директору отдаются ровно его уведомления без дублирования на каждого получателя. | [ ] |
| 19 | Офлайн-синхронизация: регистрация терминала | POST /api/v1/staff/sync/devices/register с токеном менеджера |
HTTP 201 Created. Возвращается токен устройства kstaff_dev_.... Токен сохраняется в терминале. |
[ ] |
| 20 | Офлайн-синхронизация: начальный Pull (C0) | GET /api/v1/staff/sync/pull с токеном устройства (без курсора) |
HTTP 200 OK. Возвращаются справочники (сотрудники, оргструктура, тарифы) и курсор cursor_ulid. |
[ ] |
| 21 | Офлайн-синхронизация: пакет команд Push | POST /api/v1/staff/sync/push с массивом офлайн-отметок посещаемости |
HTTP 200 OK. Все корректные команды применены, битые команды получают понятную ошибку, статус транзакции не ломает весь пакет. | [ ] |
| 22 | Отзыв прав уволенного сотрудника | Перевод сотрудника в статус fired / деактивация доступа в staff_access_grants |
Попытка входа уволенного сотрудника немедленно возвращает HTTP 401 Unauthorized. | [ ] |
| 23 | Проверка утилиты миграции арендатора (Rehome) | node scripts/rehome-tenant.mjs --dry-run --source <OLD_ULID> --target <NEW_ULID> |
Утилита производит корректное сравнение количества строк по всем таблицам (Number) без сбоев типов и ошибок внешних ключей. |
[ ] |
4. Диагностика и устранение неполадок
- Ошибка
401 Unauthorizedпри запросе от терминала:- Проверьте, передан ли заголовок
Authorization: Bearer <STANDALONE_TERMINAL_TOKEN>или токен зарегистрированного устройства.
- Проверьте, передан ли заголовок
- Ошибка
403 Forbiddenпри запросах из веб-интерфейса:- Убедитесь, что запрос отправляется с доверенного Origin (
localhost,127.0.0.1или IP пилота). Сессионные мутирующие запросы требуют валидный Origin.
- Убедитесь, что запрос отправляется с доверенного Origin (
- Проверка логов транзакций и RLS:
# Просмотр логов контейнера docker compose logs -f app - Проверка состояния миграций БД:
node scripts/check-migrations.mjs