krona-staff/docs/RUN-MANUAL-TESTING.md

19 KiB
Raw Permalink Blame History

Руководство по развёртыванию и чек-лист боевого тестирования Krona Staff

1. Назначение и архитектурные инварианты

Krona Staff — автономно развёртываемый блок Krona Business Platform, отвечающий за учёт рабочего времени, терминалы посещаемости и управленческий расчёт зарплаты.

Ключевые инварианты (AGENTS.md)

  1. Разделение доменов: Core владеет Tenant, User, Role, SSO, Platform Settings, Files, Notifications. Staff владеет Employee и HR-доменом (User != Employee).
  2. Изоляция арендаторов: Все таблицы содержат tenant_id (ULID 26 символов). В PostgreSQL включен и принудительно активирован Row-Level Security (FORCE ROW LEVEL SECURITY). Запросы выполняются через tenant-scoped транзакции с выставлением app.tenant_id.
  3. Разделение ролей БД:
    • krona_migrator — владелец схемы и таблиц, выполняет миграции DDL, NOSUPERUSER NOBYPASSRLS.
    • krona_staff_app — runtime-пользователь приложения с минимальными DML правами (SELECT, INSERT, UPDATE, DELETE на прикладные таблицы; нет прав на schema_migrations, нет прав DDL).
  4. Типы данных:
    • Идентификаторы — ULID (VARCHAR(26)).
    • Денежные суммы — BIGINT в минимальных единицах (копейках/minor units) + ISO 4217 код валюты (например, 'RUB').
    • Временные метки — UTC (TIMESTAMPTZ).
  5. Надёжность: Транзакционный 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 стенд)

  1. Создайте базу данных и роли в 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;
    
  2. Настройте переменные окружения (.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
    
  3. Сгенерируйте VAPID ключи:

    node scripts/generate-vapid-keys.mjs >> .env
    
  4. Примените миграции:

    npm run db:migrate
    
  5. Соберите и запустите приложение:

    npm run build
    npm run start
    

3. Чек-лист ручного боевого тестирования владельцем

Каждый шаг должен быть выполнен последовательно. Ожидаемый результат сверяется с фактическим.

№ Шаг / Сценарий Действие / HTTP-запрос Ожидаемый результат Статус
1 Системные проверки (Health) GET /api/v1/staff/live
GET /api/v1/staff/ready
GET /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/employees
Headers: 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/assignments
Body: привязка правила (почасовая ставка 350 руб/час = 35000 minor units).
HTTP 201 Created. Версионированное правило сохранено в staff_pay_assignments. [ ]
9 Отметка прихода через терминал POST /api/v1/staff/attendance/events
Headers: 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-calc
Body: период с 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/sign
Body: {"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. Диагностика и устранение неполадок

  1. Ошибка 401 Unauthorized при запросе от терминала:
    • Проверьте, передан ли заголовок Authorization: Bearer <STANDALONE_TERMINAL_TOKEN> или токен зарегистрированного устройства.
  2. Ошибка 403 Forbidden при запросах из веб-интерфейса:
    • Убедитесь, что запрос отправляется с доверенного Origin (localhost, 127.0.0.1 или IP пилота). Сессионные мутирующие запросы требуют валидный Origin.
  3. Проверка логов транзакций и RLS:
    # Просмотр логов контейнера
    docker compose logs -f app
    
  4. Проверка состояния миграций БД:
    node scripts/check-migrations.mjs