From 421da722c00e23f7575f5cc1f1fd1d37955fbc3e Mon Sep 17 00:00:00 2001 From: grok Date: Sat, 26 Sep 2026 14:35:19 +0700 Subject: [PATCH] =?UTF-8?q?docs(e2e):=20REPORT.md=20(=D0=BE=D0=BF=D0=B8?= =?UTF-8?q?=D1=81=D0=B0=D0=BD=D0=B8=D0=B5=20PR)=20=D0=B8=20=D1=81=D0=B2?= =?UTF-8?q?=D0=B5=D0=B6=D0=B8=D0=B5=20evidence=20=D0=BF=D1=80=D0=BE=D0=B3?= =?UTF-8?q?=D0=BE=D0=BD=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Зачем: PR в Forgejo создать нельзя (нет API-токена), поэтому описание изменений, таблица green/red по ID с командами и фактическим выводом, итог N5 до/после, валидация CI и N13 лежат в репозитории рядом с тестами. Evidence перезаписаны финальным прогоном ./scripts/test/ci-local.sh, чтобы отчёт ссылался на те же числа, что в файлах (38 red / 9 green, храповик OK, format красный из-за F14). Число файлов F14 в комментарии ci.yml и в заметках уточнено до 23 по этому замеру. --- .forgejo/workflows/ci.yml | 2 +- tests/e2e/NOTES-FOR-EXECUTORS.md | 2 +- tests/e2e/REPORT.md | 225 +++++ tests/e2e/evidence/ci-local.txt | 1138 ++++++++++++++++++++++ tests/e2e/evidence/e2e-results.json | 669 +++++++++++++ tests/e2e/evidence/e2e-run.txt | 941 ++++++++++++++++++ tests/e2e/evidence/e2e-table.md | 44 + tests/e2e/evidence/server-no-tokens.txt | 11 + tests/e2e/evidence/server-rate-limit.txt | 93 ++ tests/e2e/evidence/server-secured.txt | 279 ++++++ 10 files changed, 3402 insertions(+), 2 deletions(-) create mode 100644 tests/e2e/REPORT.md create mode 100644 tests/e2e/evidence/ci-local.txt create mode 100644 tests/e2e/evidence/e2e-results.json create mode 100644 tests/e2e/evidence/e2e-run.txt create mode 100644 tests/e2e/evidence/e2e-table.md create mode 100644 tests/e2e/evidence/server-no-tokens.txt create mode 100644 tests/e2e/evidence/server-rate-limit.txt create mode 100644 tests/e2e/evidence/server-secured.txt diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml index a543a37..054899a 100644 --- a/.forgejo/workflows/ci.yml +++ b/.forgejo/workflows/ci.yml @@ -48,7 +48,7 @@ jobs: npm run check - run: npm audit --audit-level=high - # Отдельная задача: prettier сейчас красный по 25 файлам (F14), и это не должно + # Отдельная задача: prettier сейчас красный по 23 файлам (F14; замер 2026-09-26), и это не должно # маскировать статус verify/e2e. format: runs-on: docker diff --git a/tests/e2e/NOTES-FOR-EXECUTORS.md b/tests/e2e/NOTES-FOR-EXECUTORS.md index 4becfbb..321099e 100644 --- a/tests/e2e/NOTES-FOR-EXECUTORS.md +++ b/tests/e2e/NOTES-FOR-EXECUTORS.md @@ -117,7 +117,7 @@ OWN-03..09 дополнительно упрутся в N2 (подтвержде - Задаче `docker-build` нужен раннер с меткой `docker-host` (Docker daemon). Без него задача ждёт в очереди; остальные задачи не блокируются. -- `format` красная, пока не исправлен F14 (25 файлов, в основном `src/`, `docs/`, `tests/unit/`). +- `format` красная, пока не исправлен F14 (23 файла на замер 2026-09-26, в основном `src/`, `docs/`, `tests/unit/`). - Реальный Forgejo-раннер мной не запускался (нет API-токена) — не проверено. ## 5. N13 (гонка первого расчёта) и утечка текста ошибок БД diff --git a/tests/e2e/REPORT.md b/tests/e2e/REPORT.md new file mode 100644 index 0000000..455a996 --- /dev/null +++ b/tests/e2e/REPORT.md @@ -0,0 +1,225 @@ +# PR: e2e-стенд на реальной PostgreSQL 17 и независимая приёмка (grok/e2e-harness) + +База: `codex/bootstrap-platform-foundation` @ `778ba2d`. Сравнение: + + +Изменены только `tests/e2e/**`, `tests/integration/tenant-isolation.test.ts`, +`.forgejo/workflows/ci.yml`, `scripts/test/**`. `src/`, `apps/`, `migrations/`, `deploy/`, +`package.json` не тронуты. Всё, что требует правки продукта, — в +[`NOTES-FOR-EXECUTORS.md`](NOTES-FOR-EXECUTORS.md). + +## Зачем + +156 зелёных тестов на поддельной БД не заметили, что создание сотрудника, +подтверждение смены и расчёт зарплаты на реальной PostgreSQL падают всегда. Этот PR +добавляет стенд, где реальный сервер (`tsx src/server.ts`) работает с реальной +PostgreSQL 17 под ролью приложения без привилегий, миграции применяет мигратор без +SUPERUSER, а все токены и пароли случайные (`crypto.randomBytes`). Каждый сценарий +проверяет **правильное** поведение, поэтому красный цвет означает открытый дефект. + +## Источник ID + +Файлы владельца (`AUDIT.md`, `live-audit.mjs`, `live-sync.mjs`) до конца работы в +`/workspace/uploads/krona-staff-owner/` не появились. Сценарии написаны по моему +аудиту `2026-09-26_full-project-audit_grok_3e20544.md` (ID `F*`/`N*`) и по коду. ID владельца +K1, K3, K4, K5, K6, K10, K11, K12, S1, S2, S9, A4 **не сопоставлены — не проверено**. +Синхронизация помечена `SYNC-*` (мои ID, вероятно пересекаются с S1–S9 владельца). +Когда файлы владельца будут доступны, достаточно переименовать теги в названиях +тестов (например `[K3/N1]`) и ключи в `known-defects.json`. + +## Коммиты + +| SHA | Что | +| --------- | ------------------------------------------------------------------------------------- | +| `29fefc1` | `scripts/test/provision-pg.mjs`, `migrate-roundtrip.mjs`: роли как в pilot, roundtrip | +| `88fc749` | N5: очистка tenant-isolation ролью мигратора | +| `d7e9008` | prettier для tenant-isolation.test.ts | +| `cf7f6f4` | стенд e2e: global-setup, клиент, фикстуры, храповик `run-e2e.mjs` | +| `518494d` | сценарии основного API (N1–N4, N9–N12, F2–F4, F7, F10) | +| `32ced4b` | сценарии `/sync/*` (SYNC-A…L) | +| `9bdfb66` | форматирование сгенерированных evidence | +| `f59be3a` | CI: PostgreSQL 17, роли, roundtrip, e2e, docker-build отдельно, SHA-пины | +| `a19c06b` | проверка `deploy/pilot/compose.yaml` (PILOT-1..3) | +| `1e325a6` | сценарии решений владельца (OWN-01..11) + заметки исполнителям | +| `3388b90` | N13: гонка первого расчёта (скрипт и замер) | +| (этот) | REPORT.md и свежие evidence | + +## Как запустить + +```sh +# PostgreSQL 17, bootstrap-админ нужен только для создания ролей и БД +export E2E_PG_ADMIN_URL=postgres://:@127.0.0.1:55433/postgres +node scripts/test/run-e2e.mjs # храповик known-defects (как в CI) +node scripts/test/run-e2e.mjs --no-known-defects # строго: любой красный = exit 1 +E2E_MIGRATIONS=roundtrip node scripts/test/run-e2e.mjs +./scripts/test/ci-local.sh # локальный эквивалент всех задач CI +``` + +Роли (`provision-pg.mjs`): `krona_migrator` — NOSUPERUSER NOCREATEDB NOCREATEROLE, +владелец БД и схемы `public`; `krona_staff_app` — NOSUPERUSER NOBYPASSRLS, права выдают +миграции 0003/0004. Пароли случайные, пишутся в env-файл 0600 во временном каталоге, +который удаляется после запуска. + +## Таблица green/red по ID + +Команда: `E2E_MIGRATIONS=roundtrip node scripts/test/run-e2e.mjs` (в составе +`./scripts/test/ci-local.sh`), 2026-09-26 14:33 (UTC+7), PostgreSQL 17.11. Фактический вывод: +[`evidence/e2e-run.txt`](evidence/e2e-run.txt), [`evidence/ci-local.txt`](evidence/ci-local.txt), +JSON — [`evidence/e2e-results.json`](evidence/e2e-results.json), логи серверов — `evidence/server-*.txt`. + +```text + Test Files 4 failed | 1 passed (5) + Tests 38 failed | 9 passed (47) +[run-e2e] OK: стенд работает, все красные сценарии — известные открытые дефекты +``` + +| ID | Цвет | Что проверяется (правильное поведение) | Фактически (из вывода) | +| ------------ | ----- | -------------------------------------------------------------------- | ----------------------------------------------------------------- | +| HARNESS (×5) | GREEN | live/ready, PG17, app-роль без SUPERUSER/BYPASSRLS, токены, терминал | 5/5 passed | +| CTRL (×2) | GREEN | RBAC терминала/сотрудника, уволенный теряет доступ | 2/2 passed | +| N1 | RED | POST /employees → 201 | 500 `42P08 inconsistent types deduced for parameter $2` | +| N2 | RED | подтверждение смены, расчёт, утверждение → 200 | 500 `23502 null value in column "occurred_at" of "staff_outbox"` | +| N4 | RED | пересекающиеся расчёты не начисляют смену дважды | блокирован N2 (500 23502 на предусловии) — сам N4 **не проверен** | +| N3 | RED | push на внутренний адрес отклоняется, соединений нет | 201 и 1 входящее соединение на 127.0.0.1 | +| N9 | RED | чужой push-endpoint не перепривязывается | 201 | +| N10 | RED | терминал не читает справочники (403) | professions 200, org-units 200 | +| N11 | RED | импорт с неверным kind → 400 | 500 `23514` check constraint staff_payroll_ledger | +| N12 | RED | лишние поля/нереальные суммы → 400 | 200 | +| F2 | RED | процесс без токенов не даёт прав анониму (401) | /portal 200, /payroll 200, POST /professions 201 | +| F3 | RED | cookie без сырого токена, logout отзывает | `rawTokenInCookie: true` | +| F4 | RED | 429 не позже 30 неверных входов | все 401, 429 нет | +| F7 | RED | повтор Idempotency-Key с другим телом не создаёт событие | второе событие создано (201) | +| F10 | RED | мутация по cookie без Origin → 403 | 201 | +| SYNC-A | RED | устройство не подтверждает смену | `applied` | +| SYNC-B | RED | устройство не утверждает табель | `applied` | +| SYNC-C0 | RED | bootstrap pull без курсора → 200 | 500 `42703 column "status" does not exist` (новая находка) | +| SYNC-C | RED | bootstrap >100 сущностей постранично без потерь | 500 42703 (блокирован SYNC-C0) | +| SYNC-D | RED | изменения из портала видны в инкрементальном pull | изменения нет | +| SYNC-E | RED | отметка уволенного через sync отклоняется | `applied` | +| SYNC-F | RED | точка устройства сохраняется, чужая точка в payload не принимается | `applied`, точка не сохранена | +| SYNC-G | RED | битая команда отклоняется по отдельности | 500 `22007` на весь пакет | +| SYNC-H | RED | регистрация устройства по cookie с чужим Origin → 403 | 201 | +| SYNC-I | RED | без токенов анонимно устройство не регистрируется | 201 | +| SYNC-J | RED | отметка 2001 года через sync отклоняется | `applied` | +| SYNC-K | RED | ack курсора из будущего → 400 | 200 | +| SYNC-L | GREEN | отозванное устройство не синхронизируется (403) | 403 (позитивный контроль) | +| OWN-01 | RED | менеджер точки A считает зарплату точки B → 403 | 404 `Route POST:/api/v1/staff/access-grants not found` (нет API) | +| OWN-02 | RED | менеджер отправляет пакет на согласование → 403 | 404 access-grants (нет API) | +| OWN-03 | RED | бухгалтер отправляет пакет → успех, каждому директору 1 уведомление | 404 access-grants (нет API) | +| OWN-04 | RED | бухгалтер подписывает пакет → 403 | 404 access-grants (нет API) | +| OWN-05 | RED | до подписи в ledger нет начислений/выплат | 404 access-grants (нет API) | +| OWN-06 | RED | подпись директора → ledger, пакет и смены неизменяемы | 404 access-grants (нет API) | +| OWN-07 | RED | смена изменена после отправки → 409, пакет у бухгалтера | 404 access-grants (нет API) | +| OWN-08 | RED | возврат с комментарием → пакет у бухгалтера, комментарий сохранён | 404 access-grants (нет API) | +| OWN-09 | RED | смена сотрудника A в точке B → в расчёт точки B | 404 access-grants (нет API) | +| OWN-10 | RED | без согласия на биометрию → терминалу «регистрация запрещена» | 404 `GET .../terminal/employees/:id/enrollment` (нет API) | +| OWN-11 | RED | согласие отозвано → статус для терминала меняется | 404 `PUT .../biometric-consent` (нет API) | +| PILOT-1 | RED | все подстановки в pilot compose — `${VAR:?}` | 14 переменных без `:?` (первая — `STANDALONE_MANAGER_TOKEN`) | +| PILOT-2 | RED | нет `NODE_ENV=development` | сервис `app` | +| PILOT-3 | GREEN | у `app` нет кредов мигратора | passed | +| N13 | — | гонка первого расчёта (скрипт, не vitest) | см. ниже: как есть 15/15 → 500 (N2); с обходом N2 — 0/30 гонок | +| N5 | GREEN | tenant-isolation на живой БД | до: FAIL; после: 2/2 прогона exit=0 (см. ниже) | + +Предполагаемые контракты для OWN-01..11 (C1 роли точки/бухгалтера/директора, C2 пакет +зарплаты и согласование, C3 согласие на биометрию) описаны в `NOTES-FOR-EXECUTORS.md` §1. + +### Механизм для красных сценариев (храповик) + +Выбран список `tests/e2e/known-defects.json` и одна задача `e2e`, а не отдельная +задача «allowed to fail». Причины: задача с `continue-on-error` зеленеет при любом +сбое, включая сломанный стенд, а храповик различает три случая: (1) стенд сломан +(`[HARNESS]`/`[CTRL]` красные или тест без ID) → exit 1; (2) новый красный ID не из +списка (регрессия) → exit 1; (3) ID из списка стал зелёным → exit 1 с просьбой +вычеркнуть его (исправление фиксируется, откат снова станет красным). Строгий режим +`--no-known-defects` показывает полную картину. + +## N5: tenant-isolation до/после + +До (база 778ba2d, `DATABASE_TEST_URL` = роль приложения), [`evidence/n5-before.txt`](evidence/n5-before.txt): + +```text + FAIL tests/integration/tenant-isolation.test.ts > PostgreSQL tenant isolation +error: permission denied for table staff_employees + ❯ tests/integration/tenant-isolation.test.ts:40:7 + Test Files 1 failed (1) + Tests 1 passed (1) +exit=1 +``` + +После (очистка соединением мигратора `DATABASE_TEST_MIGRATION_URL`, с +`app.tenant_id` из-за FORCE RLS, до и после теста), [`evidence/n5-after.txt`](evidence/n5-after.txt): + +```text +== run 1 ... Test Files 1 passed (1) Tests 1 passed (1) exit=0 +== run 2 ... Test Files 1 passed (1) Tests 1 passed (1) exit=0 +``` + +Полный `npm run check` с тестовой БД (задача verify в `ci-local.sh`): +`Test Files 19 passed (19)`, `Tests 188 passed (188)`. + +## CI (`.forgejo/workflows/ci.yml`) + +- `verify`: сервис `postgres:17-alpine@sha256:18cfe3ef…` (bootstrap-пользователь только + для provision), роли как в pilot (мигратор без SUPERUSER, app без BYPASSRLS), + миграции `up → откат всех 11 → up → up (no-op)`, `npm run check` с + `DATABASE_TEST_URL`/`DATABASE_TEST_MIGRATION_URL` (tenant-isolation реально + выполняется), `npm audit --audit-level=high`. +- `format`: отдельно, чтобы F14 (23 файла вне моих путей) не маскировал остальное. +- `e2e`: тот же сервис PostgreSQL 17, `E2E_MIGRATIONS=roundtrip`, храповик. +- `docker-build`: отдельная задача на метке `docker-host`, `needs: verify`, только push. +- Все actions закреплены SHA (F13): `actions/checkout@11d5960a… # v4.4.0`, + `actions/setup-node@49933ea5… # v4.4.0` (SHA получены `git ls-remote`, совпадают на + github.com и code.forgejo.org). + +Валидация: `actionlint -config-file actionlint.yaml .forgejo/workflows/ci.yml` (1.7.12, +метки `docker`, `docker-host`) → 0 замечаний, exit 0. Локальный эквивалент +`./scripts/test/ci-local.sh` ([`evidence/ci-local.txt`](evidence/ci-local.txt)): + +```text +::: [migrate-roundtrip] OK (== roundtrip OK: rolledBack=11 reapplied=11) +::: [check] OK (Test Files 19 passed, Tests 188 passed) +::: [audit] OK (found 0 vulnerabilities) +::: [format-check] FAIL exit=1 (Code style issues found in 23 files — F14) +::: [e2e] OK (храповик: все красные — известные дефекты) +=== итог: status=1 (только из-за format) +``` + +## Проверка pilot compose (PILOT-1..3) + +`tests/e2e/40-compose-pilot.e2e.ts` читает `deploy/pilot/compose.yaml` (только чтение). +Положен в `tests/e2e/`, а не рядом с существующим тестом корневого compose +(`tests/unit/deployment.test.ts`), потому что `tests/unit/` вне разрешённых путей. +Результат: PILOT-1 RED (14 подстановок без `:?`), PILOT-2 RED (`NODE_ENV: development` в +`app`; конфликт с запретом standalone в production в `config.ts` описан в заметках), +PILOT-3 GREEN. + +## N13: гонка первого расчёта + +`node scripts/test/n13-race.mjs` — 10/25/50 параллельных первых `POST /payroll/calculate`, +5 попыток на размер, каждая попытка на новой точке. Вывод: [`evidence/n13-race.txt`](evidence/n13-race.txt). + +```text +[n13] ИТОГ mode=as-is sessions=false: попыток 15, некорректных 15 (все 500: N2, occurred_at) +[n13] ИТОГ mode=n2-bypass sessions=false: попыток 15, некорректных 0 (200×N, 1 run_id, 1 расчёт) +[n13] ИТОГ mode=n2-bypass sessions=true: попыток 15, некорректных 0 (с подтверждённой сменой, db_lines=1) +``` + +`n2-bypass` — диагностика: в одноразовой БД скрипта мигратор ставит +`DEFAULT now()` для `staff_outbox.occurred_at`; продукт и миграции не меняются. +Вердикт: **гонка не воспроизведена (0 из 30 попыток при 10/25/50)**, совпадает с +«N13 not reproduced» владельца. Вероятная причина (из кода, отдельно не проверено): +upsert `ensureDefaultPayRules` в начале расчёта случайно сериализует расчёты одного +тенанта. Окно в коде остаётся — рекомендация в заметках §5. + +## Не проверено + +- Реальный Forgejo-раннер: workflow не запускался на сервере (нет API-токена, задачи + выполнены локально эквивалентным скриптом). Раннера с меткой `docker-host` может не быть. +- `docker build` не запускался (на этой машине нет Docker). +- Windows-only: DPAPI, ACL каталога данных, установщик, WinUI, реальный named pipe — + не проверено; см. тесты Codex в `apps/KronaStaffTerminal.Tests`. +- Сопоставление с ID владельца K1/K3/K4/K5/K6/K10/K11/K12, S1/S2/S9, A4 и сверка с его + `live-audit.mjs`/`live-sync.mjs` — файлов нет. +- N4 и SYNC-C по существу: блокированы N2 и SYNC-C0 соответственно. +- OWN-01..11 проверяют предполагаемый контракт; реальный контракт Codex может отличаться. +- Причина невоспроизводимости N13 — гипотеза по коду. diff --git a/tests/e2e/evidence/ci-local.txt b/tests/e2e/evidence/ci-local.txt new file mode 100644 index 0000000..f3a0f1c --- /dev/null +++ b/tests/e2e/evidence/ci-local.txt @@ -0,0 +1,1138 @@ +=== job verify +::: [npm-ci] npm ci --no-audit --no-fund +npm warn deprecated eslint@9.39.5: This version is no longer supported. Please see https://eslint.org/version-support for other options. + +added 236 packages in 1s +::: [npm-ci] OK +::: [provision] node scripts/test/provision-pg.mjs --out /tmp/tmp.FbBHYTGgXb/db.env --db krona_staff +provisioned database=krona_staff server_version=17.11 +role=krona_migrator super=false createrole=false createdb=false bypassrls=false +role=krona_staff_app super=false createrole=false createdb=false bypassrls=false +::: [provision] OK +::: [migrate-roundtrip] with_db_env node scripts/test/migrate-roundtrip.mjs roundtrip +== migrate up (1) +applied 0001_infrastructure.up.sql +applied 0002_security_hardening.up.sql +applied 0003_app_role_privileges.up.sql +applied 0004_revoke_broad_default_privileges.up.sql +applied 0005_attendance_portal.up.sql +applied 0006_payroll_foundation.up.sql +applied 0007_work_session_trace.up.sql +applied 0008_employee_access.up.sql +applied 0009_professions.up.sql +applied 0010_employee_push_notifications.up.sql +applied 0011_offline_sync_backend.up.sql +== rollback all (applied now: 11) +rolled back 0011_offline_sync_backend.down.sql +rolled back 0010_employee_push_notifications.down.sql +rolled back 0009_professions.down.sql +rolled back 0008_employee_access.down.sql +rolled back 0007_work_session_trace.down.sql +rolled back 0006_payroll_foundation.down.sql +rolled back 0005_attendance_portal.down.sql +rolled back 0004_revoke_broad_default_privileges.down.sql +rolled back 0003_app_role_privileges.down.sql +rolled back 0002_security_hardening.down.sql +rolled back 0001_infrastructure.down.sql +no migration to roll back +== rolled back 11 migrations +== migrate up (2) +applied 0001_infrastructure.up.sql +applied 0002_security_hardening.up.sql +applied 0003_app_role_privileges.up.sql +applied 0004_revoke_broad_default_privileges.up.sql +applied 0005_attendance_portal.up.sql +applied 0006_payroll_foundation.up.sql +applied 0007_work_session_trace.up.sql +applied 0008_employee_access.up.sql +applied 0009_professions.up.sql +applied 0010_employee_push_notifications.up.sql +applied 0011_offline_sync_backend.up.sql +== migrate up (3, must be no-op) +== roundtrip OK: rolledBack=11 reapplied=11 +::: [migrate-roundtrip] OK +::: [check] with_db_env npm run check + +> @krona/staff@0.3.2 check +> npm run lint && npm run typecheck && npm run test && npm run check:migrations && npm run check:contracts && npm run build + + +> @krona/staff@0.3.2 lint +> eslint . + + +> @krona/staff@0.3.2 typecheck +> tsc --noEmit + + +> @krona/staff@0.3.2 test +> vitest run + + + RUN v5.0.1 /workspace/krona-staff + + + Test Files 19 passed (19) + Tests 188 passed (188) + Start at 14:33:25 + Duration 1.00s (tests 46%, transform 31%, import 22%, worker 1%) + + +> @krona/staff@0.3.2 check:migrations +> node scripts/check-migrations.mjs + +validated 11 reversible migration(s) + +> @krona/staff@0.3.2 check:contracts +> node scripts/check-contracts.mjs + + + ╔═══════════════════════════════════════════════════════╗ + ║ ║ + ║ A new version of Redocly CLI (2.54.3) is available. ║ + ║ Update now: `npm i -g @redocly/cli@latest`. ║ + ║ Changelog: https://redocly.com/docs/cli/changelog/ ║ + ║ ║ + ╚═══════════════════════════════════════════════════════╝ + +No configurations were provided -- using built in recommended configuration by default. + +validating api/openapi.yaml... +api/openapi.yaml: validated in 45ms + +Woohoo! Your API description is valid. 🎉 + +module manifest, settings schema and OpenAPI contract validated + +> @krona/staff@0.3.2 build +> tsc -p tsconfig.build.json + +::: [check] OK +::: [audit] npm audit --audit-level=high +found 0 vulnerabilities +::: [audit] OK +=== job format +::: [format-check] npm run format:check + +> @krona/staff@0.3.2 format:check +> prettier --check . + +Checking formatting... +[warn] api/openapi.yaml +[warn] apps/KronaStaffService/README.md +[warn] deploy/pilot/compose.yaml +[warn] docs/DRIVER-DISTRIBUTION.md +[warn] docs/HARDWARE-TEST-SLK20R.md +[warn] docs/OFFLINE-SYNC-PROTOCOL.md +[warn] docs/TERMINAL-API-REQUIREMENTS.md +[warn] scripts/check-migrations.mjs +[warn] src/adapters/identity.ts +[warn] src/app.ts +[warn] src/config.ts +[warn] src/domain/attendance/work-session.ts +[warn] src/domain/notification/web-push.ts +[warn] src/domain/sync/cursor.ts +[warn] src/domain/sync/service.ts +[warn] src/portal.ts +[warn] src/sync.ts +[warn] tests/unit/config.test.ts +[warn] tests/unit/employee-push.test.ts +[warn] tests/unit/portal-ui.test.ts +[warn] tests/unit/sync.test.ts +[warn] tests/unit/tenant-sql.test.ts +[warn] tests/unit/work-session.test.ts +[warn] Code style issues found in 23 files. Run Prettier with --write to fix. +::: [format-check] FAIL exit=1 +=== job e2e +::: [e2e] env E2E_MIGRATIONS=roundtrip node scripts/test/run-e2e.mjs + + RUN v5.0.1 /workspace/krona-staff + +[e2e] provision: +provisioned database=krona_staff_e2e server_version=17.11 +role=krona_migrator super=false createrole=false createdb=false bypassrls=false +role=krona_staff_app super=false createrole=false createdb=false bypassrls=false +[e2e] migrations (roundtrip) as krona_migrator: +== migrate up (1) +applied 0001_infrastructure.up.sql +applied 0002_security_hardening.up.sql +applied 0003_app_role_privileges.up.sql +applied 0004_revoke_broad_default_privileges.up.sql +applied 0005_attendance_portal.up.sql +applied 0006_payroll_foundation.up.sql +applied 0007_work_session_trace.up.sql +applied 0008_employee_access.up.sql +applied 0009_professions.up.sql +applied 0010_employee_push_notifications.up.sql +applied 0011_offline_sync_backend.up.sql +== rollback all (applied now: 11) +rolled back 0011_offline_sync_backend.down.sql +rolled back 0010_employee_push_notifications.down.sql +rolled back 0009_professions.down.sql +rolled back 0008_employee_access.down.sql +rolled back 0007_work_session_trace.down.sql +rolled back 0006_payroll_foundation.down.sql +rolled back 0005_attendance_portal.down.sql +rolled back 0004_revoke_broad_default_privileges.down.sql +rolled back 0003_app_role_privileges.down.sql +rolled back 0002_security_hardening.down.sql +rolled back 0001_infrastructure.down.sql +no migration to roll back +== rolled back 11 migrations +== migrate up (2) +applied 0001_infrastructure.up.sql +applied 0002_security_hardening.up.sql +applied 0003_app_role_privileges.up.sql +applied 0004_revoke_broad_default_privileges.up.sql +applied 0005_attendance_portal.up.sql +applied 0006_payroll_foundation.up.sql +applied 0007_work_session_trace.up.sql +applied 0008_employee_access.up.sql +applied 0009_professions.up.sql +applied 0010_employee_push_notifications.up.sql +applied 0011_offline_sync_backend.up.sql +== migrate up (3, must be no-op) +== roundtrip OK: rolledBack=11 reapplied=11 +[e2e] server secured ready at http://127.0.0.1:35389 (log: tests/e2e/evidence/server-secured.txt) +[e2e] server no-tokens ready at http://127.0.0.1:33821 (log: tests/e2e/evidence/server-no-tokens.txt) +[e2e] server rate-limit ready at http://127.0.0.1:36299 (log: tests/e2e/evidence/server-rate-limit.txt) + × tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [N1] менеджер создаёт сотрудника через POST /employees → 201 38ms + → HTTP 500 {"statusCode":500,"code":"42P08","error":"Internal Server Error","message":"inconsistent types deduced for parameter $2"}: expected 500 to be 201 // Object.is equality + × tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [N2] подтверждение смены, расчёт и утверждение зарплаты проходят (200) и начисляют 8 ч × ставка 111ms + → подтверждение смены: HTTP 500 {"statusCode":500,"code":"23502","error":"Internal Server Error","message":"null value in column \"occurred_at\" of relation \"staff_outbox\" violates not-null constraint"}: expected 500 to be 200 // Object.is equality + × tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [N4] пересекающиеся расчёты не начисляют одну смену дважды 66ms + → подтверждение смены (предусловие, см. N2): HTTP 500 {"statusCode":500,"code":"23502","error":"Internal Server Error","message":"null value in column \"occurred_at\" of relation \"staff_outbox\" violates not-null constraint"}: expected 500 to be 200 // Object.is equality + × tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [N3] push-подписка на внутренний адрес отклоняется, сервер не подключается к 127.0.0.1 2544ms + → подписка: HTTP 201 {"id":"01M3EA4FH3FG4Q3YEKXYQ8Y4Q5","endpoint":"https://127.0.0.1:36027/e2e-internal-admin"}: expected { status: 201, connections: 1 } to deeply equal { status: toSatisfy{…}, …(1) } + × tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [N9] чужой push-endpoint нельзя перепривязать к другому сотруднику 44ms + → HTTP 201 {"id":"01M3EA4J0JSPFRDF22J6E2CEY1","endpoint":"https://fcm.googleapis.com/fcm/send/e2e-d464594734e6ddf8569ec571f5832dbf"}: expected { status: 201, …(1) } to deeply equal { status: toSatisfy{…}, …(1) } + × tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [N12] PUT pay-assignment отвергает лишние поля и нереальные суммы (400) 31ms + → HTTP 200 {"id":"01M3EA4J1PHXWHFMAMYYVRMK3E","employee_id":"01M3EA4J151B1H9D5AKAR29AN9","org_unit_id":null,"pay_rule_id":"01M3EA4FCDRQSS6V8H5Q6XS615","pay_rule_code":"hourly","pay_rule_name":"Почасовая (стажёр, дополнительный сотрудник)","rate_minor":12345,"percent_bp":0,"guarantee_minor":0,"pool_weight_bp":0… | HTTP 200 {"id":"01M3EA4J1PHXWHFMAMYYVRMK3E","employee_id":"01M3EA4J151B1H9D5AKAR29AN9","org_unit_id":null,"pay_rule_id":"01M3EA4FCDRQSS6V8H5Q6XS615","pay_rule_code":"hourly","pay_rule_name":"Почасовая (стажёр, дополнительный сотрудник)","rate_minor":9007199254740991,"percent_bp":0,"guarantee_minor":900719925…: expected { extra: 200, huge: 200 } to deeply equal { extra: 400, huge: 400 } + × tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [N10] терминальный токен не читает справочники профессий и точек (403) 4ms + → expected { professions: 200, units: 200 } to deeply equal { professions: 403, units: 403 } + × tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [F2] standalone без токенов не выдаёт права менеджера анонимному запросу (401) 20ms + → expected { portal: 200, payroll: 200, …(1) } to deeply equal { portal: 401, payroll: 401, …(1) } + × tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [F3] cookie сессии не содержит сырой токен и отзывается при выходе 8ms + → expected { rawTokenInCookie: true, …(1) } to deeply equal { rawTokenInCookie: false, …(1) } + × tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [F10] мутация по cookie без Origin отклоняется (CSRF, 403) 5ms + → HTTP 201 {"id":"01M3EA4J31CEM99Y9708PNVE90","code":"profession-01m3ea4j31cem99y9708pnve90","name":"E2E-CSRF-профессия-c30803","status":"active"}: expected 201 to be 403 // Object.is equality + × tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [F7] повтор Idempotency-Key с другим телом не создаёт второе событие 31ms + → expected { first: 201, secondCreated: true } to deeply equal { first: 201, secondCreated: false } + × tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [N11] импорт с неверным kind начисления → 400, а не 500 25ms + → HTTP 500 {"statusCode":500,"code":"23514","error":"Internal Server Error","message":"new row for relation \"staff_payroll_ledger\" violates check constraint \"staff_payroll_ledger_kind_check\""}: expected 500 to be 400 // Object.is equality + × tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [F4] перебор ключей входа ограничивается (429 не позже 30 неверных попыток) 75ms + → статусы: 401: expected false to be true // Object.is equality + × tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-01] менеджер точки A запускает расчёт для точки B → 403 110ms + → C1 POST /access-grants (point_manager): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + × tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-02] менеджер точки отправляет пакет на согласование → 403 64ms + → C1 POST /access-grants (point_manager): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + × tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-03] бухгалтер отправляет пакет → успех, каждый директор получает ровно одно уведомление 2ms + → C1 POST /access-grants (accountant): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + × tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-04] бухгалтер пытается подписать пакет → 403 2ms + → C1 POST /access-grants (accountant): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + × tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-05] до подписи директора в ledger нет начислений и выплат 2ms + → C1 POST /access-grants (accountant): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + × tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-06] подпись директора → начисления и выплаты в ledger, пакет и смены неизменяемы 2ms + → C1 POST /access-grants (accountant): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + × tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-07] смена изменена после отправки → подписать нельзя (409), пакет возвращён бухгалтеру 1ms + → C1 POST /access-grants (accountant): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + × tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-08] возврат с комментарием → пакет у бухгалтера, комментарий сохранён 2ms + → C1 POST /access-grants (accountant): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + × tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-09] сотрудник точки A отработал смену в точке B → смена попадает в зарплату точки B 2ms + → C1 POST /access-grants (accountant): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + × tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-10] сотрудник без согласия на биометрию → сервер сообщает терминалу «регистрация запрещена» 15ms + → C3: HTTP 404 {"message":"Route GET:/api/v1/staff/terminal/employees/01M3EA4JGPPB7M0G78QQBQBJ1M/enrollment not found","error":"Not Found","statusCode":404}: expected 404 to be 200 // Object.is equality + × tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-11] согласие отозвано → статус для терминала меняется 15ms + → C3 PUT biometric-consent: HTTP 404 {"message":"Route PUT:/api/v1/staff/employees/01M3EA4JH57XZ361XBC2Z7SA6J/biometric-consent not found","error":"Not Found","statusCode":404}: expected 404 to be 200 // Object.is equality + × tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-A] устройство не может само подтвердить смену (status=confirmed отклоняется) 87ms + → HTTP 200 {"results":[{"idempotency_key":"e2e-01M3EA4JPXC3E39GZMHFH33H92","command_type":"upsert_work_session","status":"applied","result":{"id":"01M3EA4JPXQPVQDPGEA3YVFPXV","revision":1,"status":"applied"}}]}: expected { http: 200, result: 'applied', …(1) } to deeply equal { http: 200, result: 'rejected', …(1) } + × tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-B] устройство не может утвердить табель (status=approved отклоняется) 32ms + → HTTP 200 {"results":[{"idempotency_key":"e2e-01M3EA4JR4CST4PE643FC043K9","command_type":"upsert_timesheet_entry","status":"applied","result":{"id":"01M3EA4JR43V65BMVJVX5DHSV0","revision":1,"status":"applied"}}]}: expected { result: 'applied', …(1) } to deeply equal { result: 'rejected', stored: null } + × tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-C0] начальная загрузка (pull без курсора) работает на реальной БД (200) 39ms + → HTTP 500 {"statusCode":500,"code":"42703","error":"Internal Server Error","message":"column \"status\" does not exist"}: expected 500 to be 200 // Object.is equality + × tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-C] начальная загрузка >100 сущностей отдаёт все сущности постранично 55ms + → HTTP 500 {"statusCode":500,"code":"42703","error":"Internal Server Error","message":"column \"status\" does not exist"}: expected 500 to be 200 // Object.is equality + × tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-D] изменения, сделанные через портал, попадают в инкрементальный pull 41ms + → expected false to be true // Object.is equality + × tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-E] отметка уволенного сотрудника через sync отклоняется 24ms + → HTTP 200 {"results":[{"idempotency_key":"e2e-01M3EA4JXB10Y1W7WAT3QXPJXR","command_type":"attendance_event","status":"applied","result":{"event_id":"01M3EA4JXD7TMSBAMMAK6HMXK2","status":"accepted"}}]}: expected 'applied' to be 'rejected' // Object.is equality + × tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-F] отметка через sync сохраняет точку устройства; чужая точка в payload отклоняется 42ms + → HTTP 200 {"results":[{"idempotency_key":"e2e-01M3EA4JYFDZ0AAZYVEF6G72T2","command_type":"attendance_event","status":"applied","result":{"event_id":"01M3EA4JYH12S10KQ4NWN232FM","status":"accepted"}},{"idempotency_key":"e2e-01M3EA4JYFDXJXPH923SG1E832","command_type":"attendance_event","status":"applied","resul…: expected { Object (ownOrgUnit, foreign) } to deeply equal { …(2) } + × tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-G] битая команда в пакете отклоняется по отдельности, остальные применяются (не 500) 21ms + → HTTP 500 {"statusCode":500,"code":"22007","error":"Internal Server Error","message":"invalid input syntax for type timestamp with time zone: \"e2e-not-a-timestamp\""}: expected { http: 500, statuses: [] } to deeply equal { http: 200, statuses: [ …(2) ] } + × tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-H] регистрация устройства по cookie с чужим Origin отклоняется (CSRF, 403) 9ms + → HTTP 201 {"device":{"id":"01M3EA4JZKVD04KCMNCGGW1EAH","tenant_id":"01M3EA4DJNEY3HRCYSBSX43XW0","device_code":"E2E-5J7EDPFQV6","name":"E2E-CSRF-терминал-34e01a","token_hint":"kstaff_dev_01M3E","status":"active","allowed_scopes":["attendance:sync"],"registered_at":"2026-09-26T07:33:38.935Z","created_by":"01M3E…: expected 201 to be 403 // Object.is equality + × tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-I] без настроенных токенов анонимный запрос не регистрирует устройство (401) 7ms + → HTTP 201 {"device":{"id":"01M3EA4JZWQF4S3SXWCX77J9ST","tenant_id":"01M3EA4DJNEY3HRCYSBSX43XW0","device_code":"E2E-KS5GF18F83","name":"E2E-Анонимный терминал-75d36d","token_hint":"kstaff_dev_01M3E","status":"active","allowed_scopes":["attendance:sync"],"registered_at":"2026-09-26T07:33:38.940Z","created_by":"…: expected 201 to be 401 // Object.is equality + × tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-J] отметка через sync вне окна времени (2001 год) отклоняется, как в POST /attendance/events 24ms + → HTTP 200 {"results":[{"idempotency_key":"e2e-01M3EA4K0JQNMDJTDAM1PZ1J8K","command_type":"attendance_event","status":"applied","result":{"event_id":"01M3EA4K0NB5RS8GACHWC7N2C2","status":"accepted"}}]}: expected 'applied' to be 'rejected' // Object.is equality + × tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-K] ack курсора из будущего (больше выданного сервером) отклоняется (400) 7ms + → HTTP 200 {"acknowledged":true,"cursor":"cur_999999999_fd163ccb01a6","acknowledged_at":"2026-09-26T07:33:38.972Z"}: expected 200 to be 400 // Object.is equality + ✓ tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-L] отозванное устройство не может синхронизироваться (403) — позитивный контроль 8ms + ✓ tests/e2e/00-harness.e2e.ts > HARNESS: реальный сервер + PostgreSQL 17 > [HARNESS] сервер отвечает live/ready (ready проверяет БД) 32ms + ✓ tests/e2e/00-harness.e2e.ts > HARNESS: реальный сервер + PostgreSQL 17 > [HARNESS] БД: PostgreSQL 17, приложение под ролью без SUPERUSER/BYPASSRLS, мигратор без SUPERUSER 14ms + ✓ tests/e2e/00-harness.e2e.ts > HARNESS: реальный сервер + PostgreSQL 17 > [HARNESS] миграции применены мигратором, app-роль не видит schema_migrations 14ms + ✓ tests/e2e/00-harness.e2e.ts > HARNESS: реальный сервер + PostgreSQL 17 > [HARNESS] токены: без токена 401, случайный токен 401, manager-токен 200 14ms + ✓ tests/e2e/00-harness.e2e.ts > HARNESS: реальный сервер + PostgreSQL 17 > [HARNESS] терминал: отметка сотрудника из импорта принимается (201) 25ms + ✓ tests/e2e/00-harness.e2e.ts > HARNESS: реальный сервер + PostgreSQL 17 > [CTRL] RBAC: терминал не видит портал и не создаёт сотрудников; сотрудник видит только себя 24ms + ✓ tests/e2e/00-harness.e2e.ts > HARNESS: реальный сервер + PostgreSQL 17 > [CTRL] уволенный сотрудник теряет доступ (401) 23ms + × tests/e2e/40-compose-pilot.e2e.ts > deploy/pilot/compose.yaml > [PILOT-1] все подставляемые переменные обязательны: ${VAR:?сообщение} 6ms + → переменные без :? — пустое значение молча попадёт в контейнер: expected [ 'STANDALONE_MANAGER_TOKEN', …(13) ] to deeply equal [] + × tests/e2e/40-compose-pilot.e2e.ts > deploy/pilot/compose.yaml > [PILOT-2] ни один сервис не запускается с NODE_ENV=development 1ms + → expected [ 'app' ] to deeply equal [] + ✓ tests/e2e/40-compose-pilot.e2e.ts > deploy/pilot/compose.yaml > [PILOT-3] у сервиса app нет учётных данных мигратора 1ms + +⎯⎯⎯⎯⎯⎯ Failed Tests 38 ⎯⎯⎯⎯⎯⎯⎯ + + FAIL tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [N1] менеджер создаёт сотрудника через POST /employees → 201 +AssertionError: HTTP 500 {"statusCode":500,"code":"42P08","error":"Internal Server Error","message":"inconsistent types deduced for parameter $2"}: expected 500 to be 201 // Object.is equality + +- Expected ++ Received + +- 201 ++ 500 + + ❯ tests/e2e/10-core-defects.e2e.ts:55:57 + 53| }, + 54| }); + 55| expect(response.status, describeResponse(response)).toBe(201); + | ^ + 56| const rows = await dbQuery('SELECT id FROM staff_employees WHERE p… + 57| number, + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/38]⎯ + + FAIL tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [N2] подтверждение смены, расчёт и утверждение зарплаты проходят (200) и начисляют 8 ч × ставка +AssertionError: подтверждение смены: HTTP 500 {"statusCode":500,"code":"23502","error":"Internal Server Error","message":"null value in column \"occurred_at\" of relation \"staff_outbox\" violates not-null constraint"}: expected 500 to be 200 // Object.is equality + +- Expected ++ Received + +- 200 ++ 500 + + ❯ tests/e2e/10-core-defects.e2e.ts:73:81 + 71| body: { status: 'confirmed' }, + 72| }); + 73| expect(confirm.status, `подтверждение смены: ${describeResponse(co… + | ^ + 74| + 75| const calculate = await api('POST', '/payroll/calculate', { + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/38]⎯ + + FAIL tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [N4] пересекающиеся расчёты не начисляют одну смену дважды +AssertionError: подтверждение смены (предусловие, см. N2): HTTP 500 {"statusCode":500,"code":"23502","error":"Internal Server Error","message":"null value in column \"occurred_at\" of relation \"staff_outbox\" violates not-null constraint"}: expected 500 to be 200 // Object.is equality + +- Expected ++ Received + +- 200 ++ 500 + + ❯ tests/e2e/10-core-defects.e2e.ts:104:7 + 102| confirm.status, + 103| `подтверждение смены (предусловие, см. N2): ${describeResponse(c… + 104| ).toBe(200); + | ^ + 105| + 106| const month = monthOf(day); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[3/38]⎯ + + FAIL tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [N3] push-подписка на внутренний адрес отклоняется, сервер не подключается к 127.0.0.1 +AssertionError: подписка: HTTP 201 {"id":"01M3EA4FH3FG4Q3YEKXYQ8Y4Q5","endpoint":"https://127.0.0.1:36027/e2e-internal-admin"}: expected { status: 201, connections: 1 } to deeply equal { status: toSatisfy{…}, …(1) } + +- Expected ++ Received + + { +- "connections": 0, +- "status": toSatisfy<[Function anonymous]>, ++ "connections": 1, ++ "status": 201, + } + + ❯ tests/e2e/10-core-defects.e2e.ts:161:9 + 159| { status: subscribe.status, connections }, + 160| `подписка: ${describeResponse(subscribe)}`, + 161| ).toEqual({ + | ^ + 162| status: expect.toSatisfy((s: number) => s === 400 || s === 422… + 163| connections: 0, + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[4/38]⎯ + + FAIL tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [N9] чужой push-endpoint нельзя перепривязать к другому сотруднику +AssertionError: HTTP 201 {"id":"01M3EA4J0JSPFRDF22J6E2CEY1","endpoint":"https://fcm.googleapis.com/fcm/send/e2e-d464594734e6ddf8569ec571f5832dbf"}: expected { status: 201, …(1) } to deeply equal { status: toSatisfy{…}, …(1) } + +- Expected ++ Received + + { + "owner": [ +- "01M3EA4HZSY982GYTPDAVP0Z0Q", ++ "01M3EA4HZTSZ12MKP3SV134FKS", + ], +- "status": toSatisfy<[Function anonymous]>, ++ "status": 201, + } + + ❯ tests/e2e/10-core-defects.e2e.ts:191:7 + 189| { status: second.status, owner: owner.map((row) => row.employee_… + 190| describeResponse(second), + 191| ).toEqual({ + | ^ + 192| status: expect.toSatisfy((s: number) => s === 409 || s === 403), + 193| owner: [employeeA!.id], + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[5/38]⎯ + + FAIL tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [N12] PUT pay-assignment отвергает лишние поля и нереальные суммы (400) +AssertionError: HTTP 200 {"id":"01M3EA4J1PHXWHFMAMYYVRMK3E","employee_id":"01M3EA4J151B1H9D5AKAR29AN9","org_unit_id":null,"pay_rule_id":"01M3EA4FCDRQSS6V8H5Q6XS615","pay_rule_code":"hourly","pay_rule_name":"Почасовая (стажёр, дополнительный сотрудник)","rate_minor":12345,"percent_bp":0,"guarantee_minor":0,"pool_weight_bp":0… | HTTP 200 {"id":"01M3EA4J1PHXWHFMAMYYVRMK3E","employee_id":"01M3EA4J151B1H9D5AKAR29AN9","org_unit_id":null,"pay_rule_id":"01M3EA4FCDRQSS6V8H5Q6XS615","pay_rule_code":"hourly","pay_rule_name":"Почасовая (стажёр, дополнительный сотрудник)","rate_minor":9007199254740991,"percent_bp":0,"guarantee_minor":900719925…: expected { extra: 200, huge: 200 } to deeply equal { extra: 400, huge: 400 } + +- Expected ++ Received + + { +- "extra": 400, +- "huge": 400, ++ "extra": 200, ++ "huge": 200, + } + + ❯ tests/e2e/10-core-defects.e2e.ts:215:7 + 213| { extra: extra.status, huge: huge.status }, + 214| `${describeResponse(extra)} | ${describeResponse(huge)}`, + 215| ).toEqual({ + | ^ + 216| extra: 400, + 217| huge: 400, + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[6/38]⎯ + + FAIL tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [N10] терминальный токен не читает справочники профессий и точек (403) +AssertionError: expected { professions: 200, units: 200 } to deeply equal { professions: 403, units: 403 } + +- Expected ++ Received + + { +- "professions": 403, +- "units": 403, ++ "professions": 200, ++ "units": 200, + } + + ❯ tests/e2e/10-core-defects.e2e.ts:224:70 + 222| const professions = await api('GET', '/professions', { token: ctx(… + 223| const units = await api('GET', '/org-units', { token: ctx().termin… + 224| expect({ professions: professions.status, units: units.status }).t… + | ^ + 225| professions: 403, + 226| units: 403, + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[7/38]⎯ + + FAIL tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [F2] standalone без токенов не выдаёт права менеджера анонимному запросу (401) +AssertionError: expected { portal: 200, payroll: 200, …(1) } to deeply equal { portal: 401, payroll: 401, …(1) } + +- Expected ++ Received + + { +- "payroll": 401, +- "portal": 401, +- "write": 401, ++ "payroll": 200, ++ "portal": 200, ++ "write": 201, + } + + ❯ tests/e2e/10-core-defects.e2e.ts:237:85 + 235| body: { name: synthetic('Профессия') }, + 236| }); + 237| expect({ portal: portal.status, payroll: payroll.status, write: wr… + | ^ + 238| portal: 401, + 239| payroll: 401, + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[8/38]⎯ + + FAIL tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [F3] cookie сессии не содержит сырой токен и отзывается при выходе +AssertionError: expected { rawTokenInCookie: true, …(1) } to deeply equal { rawTokenInCookie: false, …(1) } + +- Expected ++ Received + + { +- "afterLogout": 401, +- "rawTokenInCookie": false, ++ "afterLogout": 200, ++ "rawTokenInCookie": true, + } + + ❯ tests/e2e/10-core-defects.e2e.ts:255:91 + 253| expect(logout.status).toBe(204); + 254| const reuse = await api('GET', '/portal', { headers: { cookie } }); + 255| expect({ rawTokenInCookie: value === ctx().managerToken, afterLogo… + | ^ + 256| rawTokenInCookie: false, + 257| afterLogout: 401, + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[9/38]⎯ + + FAIL tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [F10] мутация по cookie без Origin отклоняется (CSRF, 403) +AssertionError: HTTP 201 {"id":"01M3EA4J31CEM99Y9708PNVE90","code":"profession-01m3ea4j31cem99y9708pnve90","name":"E2E-CSRF-профессия-c30803","status":"active"}: expected 201 to be 403 // Object.is equality + +- Expected ++ Received + +- 403 ++ 201 + + ❯ tests/e2e/10-core-defects.e2e.ts:269:57 + 267| body: { name: synthetic('CSRF-профессия') }, + 268| }); + 269| expect(response.status, describeResponse(response)).toBe(403); + | ^ + 270| }); + 271| + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[10/38]⎯ + + FAIL tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [F7] повтор Idempotency-Key с другим телом не создаёт второе событие +AssertionError: expected { first: 201, secondCreated: true } to deeply equal { first: 201, secondCreated: false } + +- Expected ++ Received + + { + "first": 201, +- "secondCreated": false, ++ "secondCreated": true, + } + + ❯ tests/e2e/10-core-defects.e2e.ts:288:75 + 286| const first = await send(`e2e-${randomUlid()}`); + 287| const second = await send(`e2e-${randomUlid()}`); + 288| expect({ first: first.status, secondCreated: second.status === 201… + | ^ + 289| first: 201, + 290| secondCreated: false, + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[11/38]⎯ + + FAIL tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [N11] импорт с неверным kind начисления → 400, а не 500 +AssertionError: HTTP 500 {"statusCode":500,"code":"23514","error":"Internal Server Error","message":"new row for relation \"staff_payroll_ledger\" violates check constraint \"staff_payroll_ledger_kind_check\""}: expected 500 to be 400 // Object.is equality + +- Expected ++ Received + +- 400 ++ 500 + + ❯ tests/e2e/10-core-defects.e2e.ts:311:57 + 309| }, + 310| }); + 311| expect(response.status, describeResponse(response)).toBe(400); + | ^ + 312| }); + 313| + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[12/38]⎯ + + FAIL tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [F4] перебор ключей входа ограничивается (429 не позже 30 неверных попыток) +AssertionError: статусы: 401: expected false to be true // Object.is equality + +- Expected ++ Received + +- true ++ false + + ❯ tests/e2e/10-core-defects.e2e.ts:324:84 + 322| if (response.status === 429) break; + 323| } + 324| expect(statuses.includes(429), `статусы: ${[...new Set(statuses)].… + | ^ + 325| }); + 326| }); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[13/38]⎯ + + FAIL tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-A] устройство не может само подтвердить смену (status=confirmed отклоняется) +AssertionError: HTTP 200 {"results":[{"idempotency_key":"e2e-01M3EA4JPXC3E39GZMHFH33H92","command_type":"upsert_work_session","status":"applied","result":{"id":"01M3EA4JPXQPVQDPGEA3YVFPXV","revision":1,"status":"applied"}}]}: expected { http: 200, result: 'applied', …(1) } to deeply equal { http: 200, result: 'rejected', …(1) } + +- Expected ++ Received + + { + "http": 200, +- "result": "rejected", +- "stored": null, ++ "result": "applied", ++ "stored": "confirmed", + } + + ❯ tests/e2e/20-sync-defects.e2e.ts:86:7 + 84| }, + 85| describeResponse(response), + 86| ).toEqual({ http: 200, result: 'rejected', stored: null }); + | ^ + 87| }); + 88| + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[14/38]⎯ + + FAIL tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-B] устройство не может утвердить табель (status=approved отклоняется) +AssertionError: HTTP 200 {"results":[{"idempotency_key":"e2e-01M3EA4JR4CST4PE643FC043K9","command_type":"upsert_timesheet_entry","status":"applied","result":{"id":"01M3EA4JR43V65BMVJVX5DHSV0","revision":1,"status":"applied"}}]}: expected { result: 'applied', …(1) } to deeply equal { result: 'rejected', stored: null } + +- Expected ++ Received + + { +- "result": "rejected", +- "stored": null, ++ "result": "applied", ++ "stored": "approved", + } + + ❯ tests/e2e/20-sync-defects.e2e.ts:109:7 + 107| { result: response.body?.results?.[0]?.status, stored: stored[0]… + 108| describeResponse(response), + 109| ).toEqual({ result: 'rejected', stored: null }); + | ^ + 110| }); + 111| + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[15/38]⎯ + + FAIL tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-C0] начальная загрузка (pull без курсора) работает на реальной БД (200) +AssertionError: HTTP 500 {"statusCode":500,"code":"42703","error":"Internal Server Error","message":"column \"status\" does not exist"}: expected 500 to be 200 // Object.is equality + +- Expected ++ Received + +- 200 ++ 500 + + ❯ tests/e2e/20-sync-defects.e2e.ts:120:57 + 118| body: { cursor: null }, + 119| }); + 120| expect(response.status, describeResponse(response)).toBe(200); + | ^ + 121| const types = new Set( + 122| (response.body.changes as Array<{ entity_type: string }>).map((c… + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[16/38]⎯ + + FAIL tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-C] начальная загрузка >100 сущностей отдаёт все сущности постранично +AssertionError: HTTP 500 {"statusCode":500,"code":"42703","error":"Internal Server Error","message":"column \"status\" does not exist"}: expected 500 to be 200 // Object.is equality + +- Expected ++ Received + +- 200 ++ 500 + + ❯ pullAll tests/e2e/20-sync-defects.e2e.ts:51:57 + 49| body: { cursor: next, limit: 100 }, + 50| }); + 51| expect(response.status, describeResponse(response)).toBe(200); + | ^ + 52| changes.push(...(response.body.changes as Array<{ entity_type: str… + 53| next = response.body.next_cursor as string; + ❯ tests/e2e/20-sync-defects.e2e.ts:130:25 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[17/38]⎯ + + FAIL tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-D] изменения, сделанные через портал, попадают в инкрементальный pull +AssertionError: expected false to be true // Object.is equality + +- Expected ++ Received + +- true ++ false + + ❯ tests/e2e/20-sync-defects.e2e.ts:151:95 + 149| expect(patch.status, describeResponse(patch)).toBe(200); + 150| const { changes } = await pullAll(device, cursor); + 151| expect(changes.some((c) => c.entity_type === 'employee' && c.entit… + | ^ + 152| true, + 153| ); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[18/38]⎯ + + FAIL tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-E] отметка уволенного сотрудника через sync отклоняется +AssertionError: HTTP 200 {"results":[{"idempotency_key":"e2e-01M3EA4JXB10Y1W7WAT3QXPJXR","command_type":"attendance_event","status":"applied","result":{"event_id":"01M3EA4JXD7TMSBAMMAK6HMXK2","status":"accepted"}}]}: expected 'applied' to be 'rejected' // Object.is equality + +Expected: "rejected" +Received: "applied" + + ❯ tests/e2e/20-sync-defects.e2e.ts:171:77 + 169| }), + 170| ]); + 171| expect(response.body?.results?.[0]?.status, describeResponse(respo… + | ^ + 172| }); + 173| + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[19/38]⎯ + + FAIL tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-F] отметка через sync сохраняет точку устройства; чужая точка в payload отклоняется +AssertionError: HTTP 200 {"results":[{"idempotency_key":"e2e-01M3EA4JYFDZ0AAZYVEF6G72T2","command_type":"attendance_event","status":"applied","result":{"event_id":"01M3EA4JYH12S10KQ4NWN232FM","status":"accepted"}},{"idempotency_key":"e2e-01M3EA4JYFDXJXPH923SG1E832","command_type":"attendance_event","status":"applied","resul…: expected { Object (ownOrgUnit, foreign) } to deeply equal { …(2) } + +- Expected ++ Received + + { +- "foreign": "rejected", +- "ownOrgUnit": "01M3EA4JXPPT6RXP11RKV1VY20", ++ "foreign": "applied", ++ "ownOrgUnit": null, + } + + ❯ tests/e2e/20-sync-defects.e2e.ts:202:7 + 200| }, + 201| describeResponse(response), + 202| ).toEqual({ ownOrgUnit: unitA!.id, foreign: 'rejected' }); + | ^ + 203| }); + 204| + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[20/38]⎯ + + FAIL tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-G] битая команда в пакете отклоняется по отдельности, остальные применяются (не 500) +AssertionError: HTTP 500 {"statusCode":500,"code":"22007","error":"Internal Server Error","message":"invalid input syntax for type timestamp with time zone: \"e2e-not-a-timestamp\""}: expected { http: 500, statuses: [] } to deeply equal { http: 200, statuses: [ …(2) ] } + +- Expected ++ Received + + { +- "http": 200, +- "statuses": [ +- "applied", +- "rejected", +- ], ++ "http": 500, ++ "statuses": [], + } + + ❯ tests/e2e/20-sync-defects.e2e.ts:225:7 + 223| }, + 224| describeResponse(response), + 225| ).toEqual({ http: 200, statuses: ['applied', 'rejected'] }); + | ^ + 226| }); + 227| + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[21/38]⎯ + + FAIL tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-H] регистрация устройства по cookie с чужим Origin отклоняется (CSRF, 403) +AssertionError: HTTP 201 {"device":{"id":"01M3EA4JZKVD04KCMNCGGW1EAH","tenant_id":"01M3EA4DJNEY3HRCYSBSX43XW0","device_code":"E2E-5J7EDPFQV6","name":"E2E-CSRF-терминал-34e01a","token_hint":"kstaff_dev_01M3E","status":"active","allowed_scopes":["attendance:sync"],"registered_at":"2026-09-26T07:33:38.935Z","created_by":"01M3E…: expected 201 to be 403 // Object.is equality + +- Expected ++ Received + +- 403 ++ 201 + + ❯ tests/e2e/20-sync-defects.e2e.ts:236:57 + 234| body: { device_code: `E2E-${randomUlid().slice(-10)}`, name: syn… + 235| }); + 236| expect(response.status, describeResponse(response)).toBe(403); + | ^ + 237| }); + 238| + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[22/38]⎯ + + FAIL tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-I] без настроенных токенов анонимный запрос не регистрирует устройство (401) +AssertionError: HTTP 201 {"device":{"id":"01M3EA4JZWQF4S3SXWCX77J9ST","tenant_id":"01M3EA4DJNEY3HRCYSBSX43XW0","device_code":"E2E-KS5GF18F83","name":"E2E-Анонимный терминал-75d36d","token_hint":"kstaff_dev_01M3E","status":"active","allowed_scopes":["attendance:sync"],"registered_at":"2026-09-26T07:33:38.940Z","created_by":"…: expected 201 to be 401 // Object.is equality + +- Expected ++ Received + +- 401 ++ 201 + + ❯ tests/e2e/20-sync-defects.e2e.ts:247:57 + 245| }, + 246| }); + 247| expect(response.status, describeResponse(response)).toBe(401); + | ^ + 248| }); + 249| + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[23/38]⎯ + + FAIL tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-J] отметка через sync вне окна времени (2001 год) отклоняется, как в POST /attendance/events +AssertionError: HTTP 200 {"results":[{"idempotency_key":"e2e-01M3EA4K0JQNMDJTDAM1PZ1J8K","command_type":"attendance_event","status":"applied","result":{"event_id":"01M3EA4K0NB5RS8GACHWC7N2C2","status":"accepted"}}]}: expected 'applied' to be 'rejected' // Object.is equality + +Expected: "rejected" +Received: "applied" + + ❯ tests/e2e/20-sync-defects.e2e.ts:260:77 + 258| }), + 259| ]); + 260| expect(response.body?.results?.[0]?.status, describeResponse(respo… + | ^ + 261| }); + 262| + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[24/38]⎯ + + FAIL tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-K] ack курсора из будущего (больше выданного сервером) отклоняется (400) +AssertionError: HTTP 200 {"acknowledged":true,"cursor":"cur_999999999_fd163ccb01a6","acknowledged_at":"2026-09-26T07:33:38.972Z"}: expected 200 to be 400 // Object.is equality + +- Expected ++ Received + +- 400 ++ 200 + + ❯ tests/e2e/20-sync-defects.e2e.ts:275:57 + 273| body: { cursor: `cur_${seq}_${hash}` }, + 274| }); + 275| expect(response.status, describeResponse(response)).toBe(400); + | ^ + 276| }); + 277| + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[25/38]⎯ + + FAIL tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-01] менеджер точки A запускает расчёт для точки B → 403 +AssertionError: C1 POST /access-grants (point_manager): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + +- Expected ++ Received + +- 201 ++ 404 + + ❯ grant tests/e2e/30-owner-decisions.e2e.ts:28:94 + 26| body: { role, org_unit_ids: orgUnitIds, display_name: synthetic(ro… + 27| }); + 28| expect(response.status, `C1 POST /access-grants (${role}): ${describ… + | ^ + 29| 201, + 30| ); + ❯ tests/e2e/30-owner-decisions.e2e.ts:94:22 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[26/38]⎯ + + FAIL tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-02] менеджер точки отправляет пакет на согласование → 403 +AssertionError: C1 POST /access-grants (point_manager): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + +- Expected ++ Received + +- 201 ++ 404 + + ❯ grant tests/e2e/30-owner-decisions.e2e.ts:28:94 + 26| body: { role, org_unit_ids: orgUnitIds, display_name: synthetic(ro… + 27| }); + 28| expect(response.status, `C1 POST /access-grants (${role}): ${describ… + | ^ + 29| 201, + 30| ); + ❯ tests/e2e/30-owner-decisions.e2e.ts:105:22 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[27/38]⎯ + + FAIL tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-03] бухгалтер отправляет пакет → успех, каждый директор получает ровно одно уведомление +AssertionError: C1 POST /access-grants (accountant): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + +- Expected ++ Received + +- 201 ++ 404 + + ❯ grant tests/e2e/30-owner-decisions.e2e.ts:28:94 + 26| body: { role, org_unit_ids: orgUnitIds, display_name: synthetic(ro… + 27| }); + 28| expect(response.status, `C1 POST /access-grants (${role}): ${describ… + | ^ + 29| 201, + 30| ); + ❯ tests/e2e/30-owner-decisions.e2e.ts:118:24 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[28/38]⎯ + + FAIL tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-04] бухгалтер пытается подписать пакет → 403 +AssertionError: C1 POST /access-grants (accountant): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + +- Expected ++ Received + +- 201 ++ 404 + + ❯ grant tests/e2e/30-owner-decisions.e2e.ts:28:94 + 26| body: { role, org_unit_ids: orgUnitIds, display_name: synthetic(ro… + 27| }); + 28| expect(response.status, `C1 POST /access-grants (${role}): ${describ… + | ^ + 29| 201, + 30| ); + ❯ tests/e2e/30-owner-decisions.e2e.ts:133:24 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[29/38]⎯ + + FAIL tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-05] до подписи директора в ledger нет начислений и выплат +AssertionError: C1 POST /access-grants (accountant): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + +- Expected ++ Received + +- 201 ++ 404 + + ❯ grant tests/e2e/30-owner-decisions.e2e.ts:28:94 + 26| body: { role, org_unit_ids: orgUnitIds, display_name: synthetic(ro… + 27| }); + 28| expect(response.status, `C1 POST /access-grants (${role}): ${describ… + | ^ + 29| 201, + 30| ); + ❯ tests/e2e/30-owner-decisions.e2e.ts:141:24 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[30/38]⎯ + + FAIL tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-06] подпись директора → начисления и выплаты в ledger, пакет и смены неизменяемы +AssertionError: C1 POST /access-grants (accountant): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + +- Expected ++ Received + +- 201 ++ 404 + + ❯ grant tests/e2e/30-owner-decisions.e2e.ts:28:94 + 26| body: { role, org_unit_ids: orgUnitIds, display_name: synthetic(ro… + 27| }); + 28| expect(response.status, `C1 POST /access-grants (${role}): ${describ… + | ^ + 29| 201, + 30| ); + ❯ tests/e2e/30-owner-decisions.e2e.ts:148:24 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[31/38]⎯ + + FAIL tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-07] смена изменена после отправки → подписать нельзя (409), пакет возвращён бухгалтеру +AssertionError: C1 POST /access-grants (accountant): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + +- Expected ++ Received + +- 201 ++ 404 + + ❯ grant tests/e2e/30-owner-decisions.e2e.ts:28:94 + 26| body: { role, org_unit_ids: orgUnitIds, display_name: synthetic(ro… + 27| }); + 28| expect(response.status, `C1 POST /access-grants (${role}): ${describ… + | ^ + 29| 201, + 30| ); + ❯ tests/e2e/30-owner-decisions.e2e.ts:173:24 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[32/38]⎯ + + FAIL tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-08] возврат с комментарием → пакет у бухгалтера, комментарий сохранён +AssertionError: C1 POST /access-grants (accountant): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + +- Expected ++ Received + +- 201 ++ 404 + + ❯ grant tests/e2e/30-owner-decisions.e2e.ts:28:94 + 26| body: { role, org_unit_ids: orgUnitIds, display_name: synthetic(ro… + 27| }); + 28| expect(response.status, `C1 POST /access-grants (${role}): ${describ… + | ^ + 29| 201, + 30| ); + ❯ tests/e2e/30-owner-decisions.e2e.ts:195:24 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[33/38]⎯ + + FAIL tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-09] сотрудник точки A отработал смену в точке B → смена попадает в зарплату точки B +AssertionError: C1 POST /access-grants (accountant): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + +- Expected ++ Received + +- 201 ++ 404 + + ❯ grant tests/e2e/30-owner-decisions.e2e.ts:28:94 + 26| body: { role, org_unit_ids: orgUnitIds, display_name: synthetic(ro… + 27| }); + 28| expect(response.status, `C1 POST /access-grants (${role}): ${describ… + | ^ + 29| 201, + 30| ); + ❯ tests/e2e/30-owner-decisions.e2e.ts:213:24 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[34/38]⎯ + + FAIL tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-10] сотрудник без согласия на биометрию → сервер сообщает терминалу «регистрация запрещена» +AssertionError: C3: HTTP 404 {"message":"Route GET:/api/v1/staff/terminal/employees/01M3EA4JGPPB7M0G78QQBQBJ1M/enrollment not found","error":"Not Found","statusCode":404}: expected 404 to be 200 // Object.is equality + +- Expected ++ Received + +- 200 ++ 404 + + ❯ tests/e2e/30-owner-decisions.e2e.ts:241:66 + 239| token: ctx().terminalToken, + 240| }); + 241| expect(response.status, `C3: ${describeResponse(response)}`).toBe(… + | ^ + 242| expect(response.body).toMatchObject({ registration_allowed: false,… + 243| }); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[35/38]⎯ + + FAIL tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-11] согласие отозвано → статус для терминала меняется +AssertionError: C3 PUT biometric-consent: HTTP 404 {"message":"Route PUT:/api/v1/staff/employees/01M3EA4JH57XZ361XBC2Z7SA6J/biometric-consent not found","error":"Not Found","statusCode":404}: expected 404 to be 200 // Object.is equality + +- Expected ++ Received + +- 200 ++ 404 + + ❯ tests/e2e/30-owner-decisions.e2e.ts:255:86 + 253| api('GET', `/terminal/employees/${employee!.id}/enrollment`, { t… + 254| const granted = await setConsent('granted'); + 255| expect(granted.status, `C3 PUT biometric-consent: ${describeRespon… + | ^ + 256| const before = await enrollment(); + 257| const revoked = await setConsent('revoked'); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[36/38]⎯ + + FAIL tests/e2e/40-compose-pilot.e2e.ts > deploy/pilot/compose.yaml > [PILOT-1] все подставляемые переменные обязательны: ${VAR:?сообщение} +AssertionError: переменные без :? — пустое значение молча попадёт в контейнер: expected [ 'STANDALONE_MANAGER_TOKEN', …(13) ] to deeply equal [] + +- Expected ++ Received + +- [] ++ [ ++ "STANDALONE_MANAGER_TOKEN", ++ "STANDALONE_TERMINAL_TOKEN", ++ "STANDALONE_TENANT_ID", ++ "STANDALONE_ACTOR_ID", ++ "STANDALONE_TERMINAL_ACTOR_ID", ++ "VAPID_PUBLIC_KEY", ++ "VAPID_PRIVATE_KEY", ++ "VAPID_SUBJECT", ++ "POSTGRES_APP_PASSWORD", ++ "HTTPS_PFX_PASSPHRASE", ++ "POSTGRES_MIGRATION_PASSWORD", ++ "POSTGRES_APP_PASSWORD", ++ "POSTGRES_MIGRATION_PASSWORD", ++ "POSTGRES_MIGRATION_PASSWORD", ++ ] + + ❯ tests/e2e/40-compose-pilot.e2e.ts:34:87 + 32| expect(interpolations.length).toBeGreaterThan(0); + 33| const optional = interpolations.filter((inner) => !/^[A-Z0-9_]+:\?… + 34| expect(optional, 'переменные без :? — пустое значение молча попадё… + | ^ + 35| }); + 36| + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[37/38]⎯ + + FAIL tests/e2e/40-compose-pilot.e2e.ts > deploy/pilot/compose.yaml > [PILOT-2] ни один сервис не запускается с NODE_ENV=development +AssertionError: expected [ 'app' ] to deeply equal [] + +- Expected ++ Received + +- [] ++ [ ++ "app", ++ ] + + ❯ tests/e2e/40-compose-pilot.e2e.ts:41:23 + 39| (service) => environmentOf(service).NODE_ENV === 'development', + 40| ); + 41| expect(offenders).toEqual([]); + | ^ + 42| }); + 43| + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[38/38]⎯ + + + Test Files 4 failed | 1 passed (5) + Tests 38 failed | 9 passed (47) + Start at 14:33:32 + Duration 7.22s (tests 95%, import 3%, transform 2%) + +JSON report written to /workspace/krona-staff/tests/e2e/evidence/e2e-results.json + +[run-e2e] vitest exit=1 +| ID | Цвет | Зелёных/всего | Вердикт | +|---|---|---|---| +| CTRL | GREEN | 2/2 | зелёный | +| F10 | RED | 0/1 | красный (известный дефект) | +| F2 | RED | 0/1 | красный (известный дефект) | +| F3 | RED | 0/1 | красный (известный дефект) | +| F4 | RED | 0/1 | красный (известный дефект) | +| F7 | RED | 0/1 | красный (известный дефект) | +| HARNESS | GREEN | 5/5 | зелёный (позитивный контроль) | +| N1 | RED | 0/1 | красный (известный дефект) | +| N10 | RED | 0/1 | красный (известный дефект) | +| N11 | RED | 0/1 | красный (известный дефект) | +| N12 | RED | 0/1 | красный (известный дефект) | +| N2 | RED | 0/1 | красный (известный дефект) | +| N3 | RED | 0/1 | красный (известный дефект) | +| N4 | RED | 0/1 | красный (известный дефект) | +| N9 | RED | 0/1 | красный (известный дефект) | +| OWN-01 | RED | 0/1 | красный (известный дефект) | +| OWN-02 | RED | 0/1 | красный (известный дефект) | +| OWN-03 | RED | 0/1 | красный (известный дефект) | +| OWN-04 | RED | 0/1 | красный (известный дефект) | +| OWN-05 | RED | 0/1 | красный (известный дефект) | +| OWN-06 | RED | 0/1 | красный (известный дефект) | +| OWN-07 | RED | 0/1 | красный (известный дефект) | +| OWN-08 | RED | 0/1 | красный (известный дефект) | +| OWN-09 | RED | 0/1 | красный (известный дефект) | +| OWN-10 | RED | 0/1 | красный (известный дефект) | +| OWN-11 | RED | 0/1 | красный (известный дефект) | +| PILOT-1 | RED | 0/1 | красный (известный дефект) | +| PILOT-2 | RED | 0/1 | красный (известный дефект) | +| PILOT-3 | GREEN | 1/1 | зелёный | +| SYNC-A | RED | 0/1 | красный (известный дефект) | +| SYNC-B | RED | 0/1 | красный (известный дефект) | +| SYNC-C | RED | 0/1 | красный (известный дефект) | +| SYNC-C0 | RED | 0/1 | красный (известный дефект) | +| SYNC-D | RED | 0/1 | красный (известный дефект) | +| SYNC-E | RED | 0/1 | красный (известный дефект) | +| SYNC-F | RED | 0/1 | красный (известный дефект) | +| SYNC-G | RED | 0/1 | красный (известный дефект) | +| SYNC-H | RED | 0/1 | красный (известный дефект) | +| SYNC-I | RED | 0/1 | красный (известный дефект) | +| SYNC-J | RED | 0/1 | красный (известный дефект) | +| SYNC-K | RED | 0/1 | красный (известный дефект) | +| SYNC-L | GREEN | 1/1 | зелёный | + +[run-e2e] OK: стенд работает, все красные сценарии — известные открытые дефекты +::: [e2e] OK +=== итог: status=1 +ci-local exit=1 diff --git a/tests/e2e/evidence/e2e-results.json b/tests/e2e/evidence/e2e-results.json new file mode 100644 index 0000000..096268b --- /dev/null +++ b/tests/e2e/evidence/e2e-results.json @@ -0,0 +1,669 @@ +{ + "numTotalTestSuites": 10, + "numPassedTestSuites": 2, + "numFailedTestSuites": 8, + "numPendingTestSuites": 0, + "numTotalTests": 47, + "numPassedTests": 9, + "numFailedTests": 38, + "numPendingTests": 0, + "numTodoTests": 0, + "snapshot": { + "added": 0, + "failure": false, + "filesAdded": 0, + "filesRemoved": 0, + "filesRemovedList": [], + "filesUnmatched": 0, + "filesUpdated": 0, + "matched": 0, + "total": 0, + "unchecked": 0, + "uncheckedKeysByFile": [], + "unmatched": 0, + "updated": 0, + "didUpdate": false + }, + "startTime": 1790408012144, + "success": false, + "testResults": [ + { + "assertionResults": [ + { + "ancestorTitles": ["HARNESS: реальный сервер + PostgreSQL 17"], + "fullName": "HARNESS: реальный сервер + PostgreSQL 17 [HARNESS] сервер отвечает live/ready (ready проверяет БД)", + "status": "passed", + "title": "[HARNESS] сервер отвечает live/ready (ready проверяет БД)", + "duration": 32.192098, + "failureMessages": [], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["HARNESS: реальный сервер + PostgreSQL 17"], + "fullName": "HARNESS: реальный сервер + PostgreSQL 17 [HARNESS] БД: PostgreSQL 17, приложение под ролью без SUPERUSER/BYPASSRLS, мигратор без SUPERUSER", + "status": "passed", + "title": "[HARNESS] БД: PostgreSQL 17, приложение под ролью без SUPERUSER/BYPASSRLS, мигратор без SUPERUSER", + "duration": 14.342552000000012, + "failureMessages": [], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["HARNESS: реальный сервер + PostgreSQL 17"], + "fullName": "HARNESS: реальный сервер + PostgreSQL 17 [HARNESS] миграции применены мигратором, app-роль не видит schema_migrations", + "status": "passed", + "title": "[HARNESS] миграции применены мигратором, app-роль не видит schema_migrations", + "duration": 14.26604900000001, + "failureMessages": [], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["HARNESS: реальный сервер + PostgreSQL 17"], + "fullName": "HARNESS: реальный сервер + PostgreSQL 17 [HARNESS] токены: без токена 401, случайный токен 401, manager-токен 200", + "status": "passed", + "title": "[HARNESS] токены: без токена 401, случайный токен 401, manager-токен 200", + "duration": 13.863121000000007, + "failureMessages": [], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["HARNESS: реальный сервер + PostgreSQL 17"], + "fullName": "HARNESS: реальный сервер + PostgreSQL 17 [HARNESS] терминал: отметка сотрудника из импорта принимается (201)", + "status": "passed", + "title": "[HARNESS] терминал: отметка сотрудника из импорта принимается (201)", + "duration": 24.62379200000001, + "failureMessages": [], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["HARNESS: реальный сервер + PostgreSQL 17"], + "fullName": "HARNESS: реальный сервер + PostgreSQL 17 [CTRL] RBAC: терминал не видит портал и не создаёт сотрудников; сотрудник видит только себя", + "status": "passed", + "title": "[CTRL] RBAC: терминал не видит портал и не создаёт сотрудников; сотрудник видит только себя", + "duration": 23.691180000000003, + "failureMessages": [], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["HARNESS: реальный сервер + PostgreSQL 17"], + "fullName": "HARNESS: реальный сервер + PostgreSQL 17 [CTRL] уволенный сотрудник теряет доступ (401)", + "status": "passed", + "title": "[CTRL] уволенный сотрудник теряет доступ (401)", + "duration": 23.254977999999994, + "failureMessages": [], + "meta": {}, + "tags": [], + "benchmarks": [] + } + ], + "startTime": 1790408019083, + "endTime": 1790408019229.255, + "status": "passed", + "message": "", + "name": "/workspace/krona-staff/tests/e2e/00-harness.e2e.ts" + }, + { + "assertionResults": [ + { + "ancestorTitles": ["Основной API на реальной PostgreSQL"], + "fullName": "Основной API на реальной PostgreSQL [N1] менеджер создаёт сотрудника через POST /employees → 201", + "status": "failed", + "title": "[N1] менеджер создаёт сотрудника через POST /employees → 201", + "duration": 38.316193, + "failureMessages": [ + "AssertionError: HTTP 500 {\"statusCode\":500,\"code\":\"42P08\",\"error\":\"Internal Server Error\",\"message\":\"inconsistent types deduced for parameter $2\"}: expected 500 to be 201 // Object.is equality\n at /workspace/krona-staff/tests/e2e/10-core-defects.e2e.ts:55:57\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Основной API на реальной PostgreSQL"], + "fullName": "Основной API на реальной PostgreSQL [N2] подтверждение смены, расчёт и утверждение зарплаты проходят (200) и начисляют 8 ч × ставка", + "status": "failed", + "title": "[N2] подтверждение смены, расчёт и утверждение зарплаты проходят (200) и начисляют 8 ч × ставка", + "duration": 110.697531, + "failureMessages": [ + "AssertionError: подтверждение смены: HTTP 500 {\"statusCode\":500,\"code\":\"23502\",\"error\":\"Internal Server Error\",\"message\":\"null value in column \\\"occurred_at\\\" of relation \\\"staff_outbox\\\" violates not-null constraint\"}: expected 500 to be 200 // Object.is equality\n at /workspace/krona-staff/tests/e2e/10-core-defects.e2e.ts:73:81\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Основной API на реальной PostgreSQL"], + "fullName": "Основной API на реальной PostgreSQL [N4] пересекающиеся расчёты не начисляют одну смену дважды", + "status": "failed", + "title": "[N4] пересекающиеся расчёты не начисляют одну смену дважды", + "duration": 66.33918700000004, + "failureMessages": [ + "AssertionError: подтверждение смены (предусловие, см. N2): HTTP 500 {\"statusCode\":500,\"code\":\"23502\",\"error\":\"Internal Server Error\",\"message\":\"null value in column \\\"occurred_at\\\" of relation \\\"staff_outbox\\\" violates not-null constraint\"}: expected 500 to be 200 // Object.is equality\n at /workspace/krona-staff/tests/e2e/10-core-defects.e2e.ts:104:7\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Основной API на реальной PostgreSQL"], + "fullName": "Основной API на реальной PostgreSQL [N3] push-подписка на внутренний адрес отклоняется, сервер не подключается к 127.0.0.1", + "status": "failed", + "title": "[N3] push-подписка на внутренний адрес отклоняется, сервер не подключается к 127.0.0.1", + "duration": 2544.330582, + "failureMessages": [ + "AssertionError: подписка: HTTP 201 {\"id\":\"01M3EA4FH3FG4Q3YEKXYQ8Y4Q5\",\"endpoint\":\"https://127.0.0.1:36027/e2e-internal-admin\"}: expected { status: 201, connections: 1 } to deeply equal { status: toSatisfy{…}, …(1) }\n at /workspace/krona-staff/tests/e2e/10-core-defects.e2e.ts:161:9\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Основной API на реальной PostgreSQL"], + "fullName": "Основной API на реальной PostgreSQL [N9] чужой push-endpoint нельзя перепривязать к другому сотруднику", + "status": "failed", + "title": "[N9] чужой push-endpoint нельзя перепривязать к другому сотруднику", + "duration": 44.48753099999976, + "failureMessages": [ + "AssertionError: HTTP 201 {\"id\":\"01M3EA4J0JSPFRDF22J6E2CEY1\",\"endpoint\":\"https://fcm.googleapis.com/fcm/send/e2e-d464594734e6ddf8569ec571f5832dbf\"}: expected { status: 201, …(1) } to deeply equal { status: toSatisfy{…}, …(1) }\n at /workspace/krona-staff/tests/e2e/10-core-defects.e2e.ts:191:7\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Основной API на реальной PostgreSQL"], + "fullName": "Основной API на реальной PostgreSQL [N12] PUT pay-assignment отвергает лишние поля и нереальные суммы (400)", + "status": "failed", + "title": "[N12] PUT pay-assignment отвергает лишние поля и нереальные суммы (400)", + "duration": 31.35817700000007, + "failureMessages": [ + "AssertionError: HTTP 200 {\"id\":\"01M3EA4J1PHXWHFMAMYYVRMK3E\",\"employee_id\":\"01M3EA4J151B1H9D5AKAR29AN9\",\"org_unit_id\":null,\"pay_rule_id\":\"01M3EA4FCDRQSS6V8H5Q6XS615\",\"pay_rule_code\":\"hourly\",\"pay_rule_name\":\"Почасовая (стажёр, дополнительный сотрудник)\",\"rate_minor\":12345,\"percent_bp\":0,\"guarantee_minor\":0,\"pool_weight_bp\":0… | HTTP 200 {\"id\":\"01M3EA4J1PHXWHFMAMYYVRMK3E\",\"employee_id\":\"01M3EA4J151B1H9D5AKAR29AN9\",\"org_unit_id\":null,\"pay_rule_id\":\"01M3EA4FCDRQSS6V8H5Q6XS615\",\"pay_rule_code\":\"hourly\",\"pay_rule_name\":\"Почасовая (стажёр, дополнительный сотрудник)\",\"rate_minor\":9007199254740991,\"percent_bp\":0,\"guarantee_minor\":900719925…: expected { extra: 200, huge: 200 } to deeply equal { extra: 400, huge: 400 }\n at /workspace/krona-staff/tests/e2e/10-core-defects.e2e.ts:215:7\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Основной API на реальной PostgreSQL"], + "fullName": "Основной API на реальной PostgreSQL [N10] терминальный токен не читает справочники профессий и точек (403)", + "status": "failed", + "title": "[N10] терминальный токен не читает справочники профессий и точек (403)", + "duration": 4.364047000000028, + "failureMessages": [ + "AssertionError: expected { professions: 200, units: 200 } to deeply equal { professions: 403, units: 403 }\n at /workspace/krona-staff/tests/e2e/10-core-defects.e2e.ts:224:70\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Основной API на реальной PostgreSQL"], + "fullName": "Основной API на реальной PostgreSQL [F2] standalone без токенов не выдаёт права менеджера анонимному запросу (401)", + "status": "failed", + "title": "[F2] standalone без токенов не выдаёт права менеджера анонимному запросу (401)", + "duration": 19.630533999999898, + "failureMessages": [ + "AssertionError: expected { portal: 200, payroll: 200, …(1) } to deeply equal { portal: 401, payroll: 401, …(1) }\n at /workspace/krona-staff/tests/e2e/10-core-defects.e2e.ts:237:85\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Основной API на реальной PostgreSQL"], + "fullName": "Основной API на реальной PostgreSQL [F3] cookie сессии не содержит сырой токен и отзывается при выходе", + "status": "failed", + "title": "[F3] cookie сессии не содержит сырой токен и отзывается при выходе", + "duration": 8.088321000000178, + "failureMessages": [ + "AssertionError: expected { rawTokenInCookie: true, …(1) } to deeply equal { rawTokenInCookie: false, …(1) }\n at /workspace/krona-staff/tests/e2e/10-core-defects.e2e.ts:255:91\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Основной API на реальной PostgreSQL"], + "fullName": "Основной API на реальной PostgreSQL [F10] мутация по cookie без Origin отклоняется (CSRF, 403)", + "status": "failed", + "title": "[F10] мутация по cookie без Origin отклоняется (CSRF, 403)", + "duration": 5.457843000000139, + "failureMessages": [ + "AssertionError: HTTP 201 {\"id\":\"01M3EA4J31CEM99Y9708PNVE90\",\"code\":\"profession-01m3ea4j31cem99y9708pnve90\",\"name\":\"E2E-CSRF-профессия-c30803\",\"status\":\"active\"}: expected 201 to be 403 // Object.is equality\n at /workspace/krona-staff/tests/e2e/10-core-defects.e2e.ts:269:57\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Основной API на реальной PostgreSQL"], + "fullName": "Основной API на реальной PostgreSQL [F7] повтор Idempotency-Key с другим телом не создаёт второе событие", + "status": "failed", + "title": "[F7] повтор Idempotency-Key с другим телом не создаёт второе событие", + "duration": 31.478251999999884, + "failureMessages": [ + "AssertionError: expected { first: 201, secondCreated: true } to deeply equal { first: 201, secondCreated: false }\n at /workspace/krona-staff/tests/e2e/10-core-defects.e2e.ts:288:75\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Основной API на реальной PostgreSQL"], + "fullName": "Основной API на реальной PostgreSQL [N11] импорт с неверным kind начисления → 400, а не 500", + "status": "failed", + "title": "[N11] импорт с неверным kind начисления → 400, а не 500", + "duration": 24.907294000000093, + "failureMessages": [ + "AssertionError: HTTP 500 {\"statusCode\":500,\"code\":\"23514\",\"error\":\"Internal Server Error\",\"message\":\"new row for relation \\\"staff_payroll_ledger\\\" violates check constraint \\\"staff_payroll_ledger_kind_check\\\"\"}: expected 500 to be 400 // Object.is equality\n at /workspace/krona-staff/tests/e2e/10-core-defects.e2e.ts:311:57\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Основной API на реальной PostgreSQL"], + "fullName": "Основной API на реальной PostgreSQL [F4] перебор ключей входа ограничивается (429 не позже 30 неверных попыток)", + "status": "failed", + "title": "[F4] перебор ключей входа ограничивается (429 не позже 30 неверных попыток)", + "duration": 75.38818200000014, + "failureMessages": [ + "AssertionError: статусы: 401: expected false to be true // Object.is equality\n at /workspace/krona-staff/tests/e2e/10-core-defects.e2e.ts:324:84\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + } + ], + "startTime": 1790408015147, + "endTime": 1790408018151.3882, + "status": "failed", + "message": "", + "name": "/workspace/krona-staff/tests/e2e/10-core-defects.e2e.ts" + }, + { + "assertionResults": [ + { + "ancestorTitles": ["Офлайн-синхронизация на реальной PostgreSQL"], + "fullName": "Офлайн-синхронизация на реальной PostgreSQL [SYNC-A] устройство не может само подтвердить смену (status=confirmed отклоняется)", + "status": "failed", + "title": "[SYNC-A] устройство не может само подтвердить смену (status=confirmed отклоняется)", + "duration": 86.95440500000001, + "failureMessages": [ + "AssertionError: HTTP 200 {\"results\":[{\"idempotency_key\":\"e2e-01M3EA4JPXC3E39GZMHFH33H92\",\"command_type\":\"upsert_work_session\",\"status\":\"applied\",\"result\":{\"id\":\"01M3EA4JPXQPVQDPGEA3YVFPXV\",\"revision\":1,\"status\":\"applied\"}}]}: expected { http: 200, result: 'applied', …(1) } to deeply equal { http: 200, result: 'rejected', …(1) }\n at /workspace/krona-staff/tests/e2e/20-sync-defects.e2e.ts:86:7\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Офлайн-синхронизация на реальной PostgreSQL"], + "fullName": "Офлайн-синхронизация на реальной PostgreSQL [SYNC-B] устройство не может утвердить табель (status=approved отклоняется)", + "status": "failed", + "title": "[SYNC-B] устройство не может утвердить табель (status=approved отклоняется)", + "duration": 32.361658000000006, + "failureMessages": [ + "AssertionError: HTTP 200 {\"results\":[{\"idempotency_key\":\"e2e-01M3EA4JR4CST4PE643FC043K9\",\"command_type\":\"upsert_timesheet_entry\",\"status\":\"applied\",\"result\":{\"id\":\"01M3EA4JR43V65BMVJVX5DHSV0\",\"revision\":1,\"status\":\"applied\"}}]}: expected { result: 'applied', …(1) } to deeply equal { result: 'rejected', stored: null }\n at /workspace/krona-staff/tests/e2e/20-sync-defects.e2e.ts:109:7\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Офлайн-синхронизация на реальной PostgreSQL"], + "fullName": "Офлайн-синхронизация на реальной PostgreSQL [SYNC-C0] начальная загрузка (pull без курсора) работает на реальной БД (200)", + "status": "failed", + "title": "[SYNC-C0] начальная загрузка (pull без курсора) работает на реальной БД (200)", + "duration": 39.13565999999997, + "failureMessages": [ + "AssertionError: HTTP 500 {\"statusCode\":500,\"code\":\"42703\",\"error\":\"Internal Server Error\",\"message\":\"column \\\"status\\\" does not exist\"}: expected 500 to be 200 // Object.is equality\n at /workspace/krona-staff/tests/e2e/20-sync-defects.e2e.ts:120:57\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Офлайн-синхронизация на реальной PostgreSQL"], + "fullName": "Офлайн-синхронизация на реальной PostgreSQL [SYNC-C] начальная загрузка >100 сущностей отдаёт все сущности постранично", + "status": "failed", + "title": "[SYNC-C] начальная загрузка >100 сущностей отдаёт все сущности постранично", + "duration": 54.852048000000025, + "failureMessages": [ + "AssertionError: HTTP 500 {\"statusCode\":500,\"code\":\"42703\",\"error\":\"Internal Server Error\",\"message\":\"column \\\"status\\\" does not exist\"}: expected 500 to be 200 // Object.is equality\n at pullAll (/workspace/krona-staff/tests/e2e/20-sync-defects.e2e.ts:51:57)\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at /workspace/krona-staff/tests/e2e/20-sync-defects.e2e.ts:130:25\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Офлайн-синхронизация на реальной PostgreSQL"], + "fullName": "Офлайн-синхронизация на реальной PostgreSQL [SYNC-D] изменения, сделанные через портал, попадают в инкрементальный pull", + "status": "failed", + "title": "[SYNC-D] изменения, сделанные через портал, попадают в инкрементальный pull", + "duration": 40.97763200000003, + "failureMessages": [ + "AssertionError: expected false to be true // Object.is equality\n at /workspace/krona-staff/tests/e2e/20-sync-defects.e2e.ts:151:95\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Офлайн-синхронизация на реальной PostgreSQL"], + "fullName": "Офлайн-синхронизация на реальной PostgreSQL [SYNC-E] отметка уволенного сотрудника через sync отклоняется", + "status": "failed", + "title": "[SYNC-E] отметка уволенного сотрудника через sync отклоняется", + "duration": 23.937388999999996, + "failureMessages": [ + "AssertionError: HTTP 200 {\"results\":[{\"idempotency_key\":\"e2e-01M3EA4JXB10Y1W7WAT3QXPJXR\",\"command_type\":\"attendance_event\",\"status\":\"applied\",\"result\":{\"event_id\":\"01M3EA4JXD7TMSBAMMAK6HMXK2\",\"status\":\"accepted\"}}]}: expected 'applied' to be 'rejected' // Object.is equality\n at /workspace/krona-staff/tests/e2e/20-sync-defects.e2e.ts:171:77\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Офлайн-синхронизация на реальной PostgreSQL"], + "fullName": "Офлайн-синхронизация на реальной PostgreSQL [SYNC-F] отметка через sync сохраняет точку устройства; чужая точка в payload отклоняется", + "status": "failed", + "title": "[SYNC-F] отметка через sync сохраняет точку устройства; чужая точка в payload отклоняется", + "duration": 42.41749800000002, + "failureMessages": [ + "AssertionError: HTTP 200 {\"results\":[{\"idempotency_key\":\"e2e-01M3EA4JYFDZ0AAZYVEF6G72T2\",\"command_type\":\"attendance_event\",\"status\":\"applied\",\"result\":{\"event_id\":\"01M3EA4JYH12S10KQ4NWN232FM\",\"status\":\"accepted\"}},{\"idempotency_key\":\"e2e-01M3EA4JYFDXJXPH923SG1E832\",\"command_type\":\"attendance_event\",\"status\":\"applied\",\"resul…: expected { Object (ownOrgUnit, foreign) } to deeply equal { …(2) }\n at /workspace/krona-staff/tests/e2e/20-sync-defects.e2e.ts:202:7\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Офлайн-синхронизация на реальной PostgreSQL"], + "fullName": "Офлайн-синхронизация на реальной PostgreSQL [SYNC-G] битая команда в пакете отклоняется по отдельности, остальные применяются (не 500)", + "status": "failed", + "title": "[SYNC-G] битая команда в пакете отклоняется по отдельности, остальные применяются (не 500)", + "duration": 20.59652299999999, + "failureMessages": [ + "AssertionError: HTTP 500 {\"statusCode\":500,\"code\":\"22007\",\"error\":\"Internal Server Error\",\"message\":\"invalid input syntax for type timestamp with time zone: \\\"e2e-not-a-timestamp\\\"\"}: expected { http: 500, statuses: [] } to deeply equal { http: 200, statuses: [ …(2) ] }\n at /workspace/krona-staff/tests/e2e/20-sync-defects.e2e.ts:225:7\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Офлайн-синхронизация на реальной PostgreSQL"], + "fullName": "Офлайн-синхронизация на реальной PostgreSQL [SYNC-H] регистрация устройства по cookie с чужим Origin отклоняется (CSRF, 403)", + "status": "failed", + "title": "[SYNC-H] регистрация устройства по cookie с чужим Origin отклоняется (CSRF, 403)", + "duration": 9.081312000000025, + "failureMessages": [ + "AssertionError: HTTP 201 {\"device\":{\"id\":\"01M3EA4JZKVD04KCMNCGGW1EAH\",\"tenant_id\":\"01M3EA4DJNEY3HRCYSBSX43XW0\",\"device_code\":\"E2E-5J7EDPFQV6\",\"name\":\"E2E-CSRF-терминал-34e01a\",\"token_hint\":\"kstaff_dev_01M3E\",\"status\":\"active\",\"allowed_scopes\":[\"attendance:sync\"],\"registered_at\":\"2026-09-26T07:33:38.935Z\",\"created_by\":\"01M3E…: expected 201 to be 403 // Object.is equality\n at /workspace/krona-staff/tests/e2e/20-sync-defects.e2e.ts:236:57\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Офлайн-синхронизация на реальной PostgreSQL"], + "fullName": "Офлайн-синхронизация на реальной PostgreSQL [SYNC-I] без настроенных токенов анонимный запрос не регистрирует устройство (401)", + "status": "failed", + "title": "[SYNC-I] без настроенных токенов анонимный запрос не регистрирует устройство (401)", + "duration": 6.548922000000005, + "failureMessages": [ + "AssertionError: HTTP 201 {\"device\":{\"id\":\"01M3EA4JZWQF4S3SXWCX77J9ST\",\"tenant_id\":\"01M3EA4DJNEY3HRCYSBSX43XW0\",\"device_code\":\"E2E-KS5GF18F83\",\"name\":\"E2E-Анонимный терминал-75d36d\",\"token_hint\":\"kstaff_dev_01M3E\",\"status\":\"active\",\"allowed_scopes\":[\"attendance:sync\"],\"registered_at\":\"2026-09-26T07:33:38.940Z\",\"created_by\":\"…: expected 201 to be 401 // Object.is equality\n at /workspace/krona-staff/tests/e2e/20-sync-defects.e2e.ts:247:57\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Офлайн-синхронизация на реальной PostgreSQL"], + "fullName": "Офлайн-синхронизация на реальной PostgreSQL [SYNC-J] отметка через sync вне окна времени (2001 год) отклоняется, как в POST /attendance/events", + "status": "failed", + "title": "[SYNC-J] отметка через sync вне окна времени (2001 год) отклоняется, как в POST /attendance/events", + "duration": 23.565251999999987, + "failureMessages": [ + "AssertionError: HTTP 200 {\"results\":[{\"idempotency_key\":\"e2e-01M3EA4K0JQNMDJTDAM1PZ1J8K\",\"command_type\":\"attendance_event\",\"status\":\"applied\",\"result\":{\"event_id\":\"01M3EA4K0NB5RS8GACHWC7N2C2\",\"status\":\"accepted\"}}]}: expected 'applied' to be 'rejected' // Object.is equality\n at /workspace/krona-staff/tests/e2e/20-sync-defects.e2e.ts:260:77\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Офлайн-синхронизация на реальной PostgreSQL"], + "fullName": "Офлайн-синхронизация на реальной PostgreSQL [SYNC-K] ack курсора из будущего (больше выданного сервером) отклоняется (400)", + "status": "failed", + "title": "[SYNC-K] ack курсора из будущего (больше выданного сервером) отклоняется (400)", + "duration": 6.953785000000039, + "failureMessages": [ + "AssertionError: HTTP 200 {\"acknowledged\":true,\"cursor\":\"cur_999999999_fd163ccb01a6\",\"acknowledged_at\":\"2026-09-26T07:33:38.972Z\"}: expected 200 to be 400 // Object.is equality\n at /workspace/krona-staff/tests/e2e/20-sync-defects.e2e.ts:275:57\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Офлайн-синхронизация на реальной PostgreSQL"], + "fullName": "Офлайн-синхронизация на реальной PostgreSQL [SYNC-L] отозванное устройство не может синхронизироваться (403) — позитивный контроль", + "status": "passed", + "title": "[SYNC-L] отозванное устройство не может синхронизироваться (403) — позитивный контроль", + "duration": 8.451247999999964, + "failureMessages": [], + "meta": {}, + "tags": [], + "benchmarks": [] + } + ], + "startTime": 1790408018587, + "endTime": 1790408018982.4512, + "status": "failed", + "message": "", + "name": "/workspace/krona-staff/tests/e2e/20-sync-defects.e2e.ts" + }, + { + "assertionResults": [ + { + "ancestorTitles": ["Решения владельца: роли, пакеты зарплаты, согласие на биометрию"], + "fullName": "Решения владельца: роли, пакеты зарплаты, согласие на биометрию [OWN-01] менеджер точки A запускает расчёт для точки B → 403", + "status": "failed", + "title": "[OWN-01] менеджер точки A запускает расчёт для точки B → 403", + "duration": 109.84663699999999, + "failureMessages": [ + "AssertionError: C1 POST /access-grants (point_manager): HTTP 404 {\"message\":\"Route POST:/api/v1/staff/access-grants not found\",\"error\":\"Not Found\",\"statusCode\":404}: expected 404 to be 201 // Object.is equality\n at grant (/workspace/krona-staff/tests/e2e/30-owner-decisions.e2e.ts:28:94)\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at /workspace/krona-staff/tests/e2e/30-owner-decisions.e2e.ts:94:22\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Решения владельца: роли, пакеты зарплаты, согласие на биометрию"], + "fullName": "Решения владельца: роли, пакеты зарплаты, согласие на биометрию [OWN-02] менеджер точки отправляет пакет на согласование → 403", + "status": "failed", + "title": "[OWN-02] менеджер точки отправляет пакет на согласование → 403", + "duration": 64.021771, + "failureMessages": [ + "AssertionError: C1 POST /access-grants (point_manager): HTTP 404 {\"message\":\"Route POST:/api/v1/staff/access-grants not found\",\"error\":\"Not Found\",\"statusCode\":404}: expected 404 to be 201 // Object.is equality\n at grant (/workspace/krona-staff/tests/e2e/30-owner-decisions.e2e.ts:28:94)\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at /workspace/krona-staff/tests/e2e/30-owner-decisions.e2e.ts:105:22\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Решения владельца: роли, пакеты зарплаты, согласие на биометрию"], + "fullName": "Решения владельца: роли, пакеты зарплаты, согласие на биометрию [OWN-03] бухгалтер отправляет пакет → успех, каждый директор получает ровно одно уведомление", + "status": "failed", + "title": "[OWN-03] бухгалтер отправляет пакет → успех, каждый директор получает ровно одно уведомление", + "duration": 1.5183850000000234, + "failureMessages": [ + "AssertionError: C1 POST /access-grants (accountant): HTTP 404 {\"message\":\"Route POST:/api/v1/staff/access-grants not found\",\"error\":\"Not Found\",\"statusCode\":404}: expected 404 to be 201 // Object.is equality\n at grant (/workspace/krona-staff/tests/e2e/30-owner-decisions.e2e.ts:28:94)\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at /workspace/krona-staff/tests/e2e/30-owner-decisions.e2e.ts:118:24\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Решения владельца: роли, пакеты зарплаты, согласие на биометрию"], + "fullName": "Решения владельца: роли, пакеты зарплаты, согласие на биометрию [OWN-04] бухгалтер пытается подписать пакет → 403", + "status": "failed", + "title": "[OWN-04] бухгалтер пытается подписать пакет → 403", + "duration": 1.8508840000000077, + "failureMessages": [ + "AssertionError: C1 POST /access-grants (accountant): HTTP 404 {\"message\":\"Route POST:/api/v1/staff/access-grants not found\",\"error\":\"Not Found\",\"statusCode\":404}: expected 404 to be 201 // Object.is equality\n at grant (/workspace/krona-staff/tests/e2e/30-owner-decisions.e2e.ts:28:94)\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at /workspace/krona-staff/tests/e2e/30-owner-decisions.e2e.ts:133:24\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Решения владельца: роли, пакеты зарплаты, согласие на биометрию"], + "fullName": "Решения владельца: роли, пакеты зарплаты, согласие на биометрию [OWN-05] до подписи директора в ledger нет начислений и выплат", + "status": "failed", + "title": "[OWN-05] до подписи директора в ledger нет начислений и выплат", + "duration": 1.9114280000000008, + "failureMessages": [ + "AssertionError: C1 POST /access-grants (accountant): HTTP 404 {\"message\":\"Route POST:/api/v1/staff/access-grants not found\",\"error\":\"Not Found\",\"statusCode\":404}: expected 404 to be 201 // Object.is equality\n at grant (/workspace/krona-staff/tests/e2e/30-owner-decisions.e2e.ts:28:94)\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at /workspace/krona-staff/tests/e2e/30-owner-decisions.e2e.ts:141:24\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Решения владельца: роли, пакеты зарплаты, согласие на биометрию"], + "fullName": "Решения владельца: роли, пакеты зарплаты, согласие на биометрию [OWN-06] подпись директора → начисления и выплаты в ledger, пакет и смены неизменяемы", + "status": "failed", + "title": "[OWN-06] подпись директора → начисления и выплаты в ledger, пакет и смены неизменяемы", + "duration": 1.5373430000000212, + "failureMessages": [ + "AssertionError: C1 POST /access-grants (accountant): HTTP 404 {\"message\":\"Route POST:/api/v1/staff/access-grants not found\",\"error\":\"Not Found\",\"statusCode\":404}: expected 404 to be 201 // Object.is equality\n at grant (/workspace/krona-staff/tests/e2e/30-owner-decisions.e2e.ts:28:94)\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at /workspace/krona-staff/tests/e2e/30-owner-decisions.e2e.ts:148:24\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Решения владельца: роли, пакеты зарплаты, согласие на биометрию"], + "fullName": "Решения владельца: роли, пакеты зарплаты, согласие на биометрию [OWN-07] смена изменена после отправки → подписать нельзя (409), пакет возвращён бухгалтеру", + "status": "failed", + "title": "[OWN-07] смена изменена после отправки → подписать нельзя (409), пакет возвращён бухгалтеру", + "duration": 1.4993349999999737, + "failureMessages": [ + "AssertionError: C1 POST /access-grants (accountant): HTTP 404 {\"message\":\"Route POST:/api/v1/staff/access-grants not found\",\"error\":\"Not Found\",\"statusCode\":404}: expected 404 to be 201 // Object.is equality\n at grant (/workspace/krona-staff/tests/e2e/30-owner-decisions.e2e.ts:28:94)\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at /workspace/krona-staff/tests/e2e/30-owner-decisions.e2e.ts:173:24\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Решения владельца: роли, пакеты зарплаты, согласие на биометрию"], + "fullName": "Решения владельца: роли, пакеты зарплаты, согласие на биометрию [OWN-08] возврат с комментарием → пакет у бухгалтера, комментарий сохранён", + "status": "failed", + "title": "[OWN-08] возврат с комментарием → пакет у бухгалтера, комментарий сохранён", + "duration": 2.188139000000035, + "failureMessages": [ + "AssertionError: C1 POST /access-grants (accountant): HTTP 404 {\"message\":\"Route POST:/api/v1/staff/access-grants not found\",\"error\":\"Not Found\",\"statusCode\":404}: expected 404 to be 201 // Object.is equality\n at grant (/workspace/krona-staff/tests/e2e/30-owner-decisions.e2e.ts:28:94)\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at /workspace/krona-staff/tests/e2e/30-owner-decisions.e2e.ts:195:24\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Решения владельца: роли, пакеты зарплаты, согласие на биометрию"], + "fullName": "Решения владельца: роли, пакеты зарплаты, согласие на биометрию [OWN-09] сотрудник точки A отработал смену в точке B → смена попадает в зарплату точки B", + "status": "failed", + "title": "[OWN-09] сотрудник точки A отработал смену в точке B → смена попадает в зарплату точки B", + "duration": 2.2691649999999868, + "failureMessages": [ + "AssertionError: C1 POST /access-grants (accountant): HTTP 404 {\"message\":\"Route POST:/api/v1/staff/access-grants not found\",\"error\":\"Not Found\",\"statusCode\":404}: expected 404 to be 201 // Object.is equality\n at grant (/workspace/krona-staff/tests/e2e/30-owner-decisions.e2e.ts:28:94)\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at /workspace/krona-staff/tests/e2e/30-owner-decisions.e2e.ts:213:24\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Решения владельца: роли, пакеты зарплаты, согласие на биометрию"], + "fullName": "Решения владельца: роли, пакеты зарплаты, согласие на биометрию [OWN-10] сотрудник без согласия на биометрию → сервер сообщает терминалу «регистрация запрещена»", + "status": "failed", + "title": "[OWN-10] сотрудник без согласия на биометрию → сервер сообщает терминалу «регистрация запрещена»", + "duration": 15.068132999999989, + "failureMessages": [ + "AssertionError: C3: HTTP 404 {\"message\":\"Route GET:/api/v1/staff/terminal/employees/01M3EA4JGPPB7M0G78QQBQBJ1M/enrollment not found\",\"error\":\"Not Found\",\"statusCode\":404}: expected 404 to be 200 // Object.is equality\n at /workspace/krona-staff/tests/e2e/30-owner-decisions.e2e.ts:241:66\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["Решения владельца: роли, пакеты зарплаты, согласие на биометрию"], + "fullName": "Решения владельца: роли, пакеты зарплаты, согласие на биометрию [OWN-11] согласие отозвано → статус для терминала меняется", + "status": "failed", + "title": "[OWN-11] согласие отозвано → статус для терминала меняется", + "duration": 14.774637000000041, + "failureMessages": [ + "AssertionError: C3 PUT biometric-consent: HTTP 404 {\"message\":\"Route PUT:/api/v1/staff/employees/01M3EA4JH57XZ361XBC2Z7SA6J/biometric-consent not found\",\"error\":\"Not Found\",\"statusCode\":404}: expected 404 to be 200 // Object.is equality\n at /workspace/krona-staff/tests/e2e/30-owner-decisions.e2e.ts:255:86\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:20" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + } + ], + "startTime": 1790408018262, + "endTime": 1790408018478.7747, + "status": "failed", + "message": "", + "name": "/workspace/krona-staff/tests/e2e/30-owner-decisions.e2e.ts" + }, + { + "assertionResults": [ + { + "ancestorTitles": ["deploy/pilot/compose.yaml"], + "fullName": "deploy/pilot/compose.yaml [PILOT-1] все подставляемые переменные обязательны: ${VAR:?сообщение}", + "status": "failed", + "title": "[PILOT-1] все подставляемые переменные обязательны: ${VAR:?сообщение}", + "duration": 5.8893739999999895, + "failureMessages": [ + "AssertionError: переменные без :? — пустое значение молча попадёт в контейнер: expected [ 'STANDALONE_MANAGER_TOKEN', …(13) ] to deeply equal []\n at /workspace/krona-staff/tests/e2e/40-compose-pilot.e2e.ts:34:87\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:1628:35\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:26\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:3319:20\n at new Promise ()\n at runWithCancel (file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:3314:10)\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:3299:20\n at new Promise ()\n at runWithTimeout (file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:3257:10)\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:3876:64" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["deploy/pilot/compose.yaml"], + "fullName": "deploy/pilot/compose.yaml [PILOT-2] ни один сервис не запускается с NODE_ENV=development", + "status": "failed", + "title": "[PILOT-2] ни один сервис не запускается с NODE_ENV=development", + "duration": 1.0336859999999888, + "failureMessages": [ + "AssertionError: expected [ 'app' ] to deeply equal []\n at /workspace/krona-staff/tests/e2e/40-compose-pilot.e2e.ts:41:23\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:1628:35\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:2783:26\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:3319:20\n at new Promise ()\n at runWithCancel (file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:3314:10)\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:3299:20\n at new Promise ()\n at runWithTimeout (file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:3257:10)\n at file:///workspace/krona-staff/node_modules/vitest/dist/chunks/run.C5UmxDPh.js:3876:64" + ], + "meta": {}, + "tags": [], + "benchmarks": [] + }, + { + "ancestorTitles": ["deploy/pilot/compose.yaml"], + "fullName": "deploy/pilot/compose.yaml [PILOT-3] у сервиса app нет учётных данных мигратора", + "status": "passed", + "title": "[PILOT-3] у сервиса app нет учётных данных мигратора", + "duration": 0.5442440000000062, + "failureMessages": [], + "meta": {}, + "tags": [], + "benchmarks": [] + } + ], + "startTime": 1790408019346, + "endTime": 1790408019353.5442, + "status": "failed", + "message": "", + "name": "/workspace/krona-staff/tests/e2e/40-compose-pilot.e2e.ts" + } + ] +} diff --git a/tests/e2e/evidence/e2e-run.txt b/tests/e2e/evidence/e2e-run.txt new file mode 100644 index 0000000..8742401 --- /dev/null +++ b/tests/e2e/evidence/e2e-run.txt @@ -0,0 +1,941 @@ +$ npx vitest run --config tests/e2e/vitest.e2e.config.ts --reporter=verbose --reporter=json --outputFile.json=/workspace/krona-staff/tests/e2e/evidence/e2e-results.json + + RUN v5.0.1 /workspace/krona-staff + +[e2e] provision: +provisioned database=krona_staff_e2e server_version=17.11 +role=krona_migrator super=false createrole=false createdb=false bypassrls=false +role=krona_staff_app super=false createrole=false createdb=false bypassrls=false +[e2e] migrations (roundtrip) as krona_migrator: +== migrate up (1) +applied 0001_infrastructure.up.sql +applied 0002_security_hardening.up.sql +applied 0003_app_role_privileges.up.sql +applied 0004_revoke_broad_default_privileges.up.sql +applied 0005_attendance_portal.up.sql +applied 0006_payroll_foundation.up.sql +applied 0007_work_session_trace.up.sql +applied 0008_employee_access.up.sql +applied 0009_professions.up.sql +applied 0010_employee_push_notifications.up.sql +applied 0011_offline_sync_backend.up.sql +== rollback all (applied now: 11) +rolled back 0011_offline_sync_backend.down.sql +rolled back 0010_employee_push_notifications.down.sql +rolled back 0009_professions.down.sql +rolled back 0008_employee_access.down.sql +rolled back 0007_work_session_trace.down.sql +rolled back 0006_payroll_foundation.down.sql +rolled back 0005_attendance_portal.down.sql +rolled back 0004_revoke_broad_default_privileges.down.sql +rolled back 0003_app_role_privileges.down.sql +rolled back 0002_security_hardening.down.sql +rolled back 0001_infrastructure.down.sql +no migration to roll back +== rolled back 11 migrations +== migrate up (2) +applied 0001_infrastructure.up.sql +applied 0002_security_hardening.up.sql +applied 0003_app_role_privileges.up.sql +applied 0004_revoke_broad_default_privileges.up.sql +applied 0005_attendance_portal.up.sql +applied 0006_payroll_foundation.up.sql +applied 0007_work_session_trace.up.sql +applied 0008_employee_access.up.sql +applied 0009_professions.up.sql +applied 0010_employee_push_notifications.up.sql +applied 0011_offline_sync_backend.up.sql +== migrate up (3, must be no-op) +== roundtrip OK: rolledBack=11 reapplied=11 +[e2e] server secured ready at http://127.0.0.1:35389 (log: tests/e2e/evidence/server-secured.txt) +[e2e] server no-tokens ready at http://127.0.0.1:33821 (log: tests/e2e/evidence/server-no-tokens.txt) +[e2e] server rate-limit ready at http://127.0.0.1:36299 (log: tests/e2e/evidence/server-rate-limit.txt) + × tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [N1] менеджер создаёт сотрудника через POST /employees → 201 38ms + → HTTP 500 {"statusCode":500,"code":"42P08","error":"Internal Server Error","message":"inconsistent types deduced for parameter $2"}: expected 500 to be 201 // Object.is equality + × tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [N2] подтверждение смены, расчёт и утверждение зарплаты проходят (200) и начисляют 8 ч × ставка 111ms + → подтверждение смены: HTTP 500 {"statusCode":500,"code":"23502","error":"Internal Server Error","message":"null value in column \"occurred_at\" of relation \"staff_outbox\" violates not-null constraint"}: expected 500 to be 200 // Object.is equality + × tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [N4] пересекающиеся расчёты не начисляют одну смену дважды 66ms + → подтверждение смены (предусловие, см. N2): HTTP 500 {"statusCode":500,"code":"23502","error":"Internal Server Error","message":"null value in column \"occurred_at\" of relation \"staff_outbox\" violates not-null constraint"}: expected 500 to be 200 // Object.is equality + × tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [N3] push-подписка на внутренний адрес отклоняется, сервер не подключается к 127.0.0.1 2544ms + → подписка: HTTP 201 {"id":"01M3EA4FH3FG4Q3YEKXYQ8Y4Q5","endpoint":"https://127.0.0.1:36027/e2e-internal-admin"}: expected { status: 201, connections: 1 } to deeply equal { status: toSatisfy{…}, …(1) } + × tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [N9] чужой push-endpoint нельзя перепривязать к другому сотруднику 44ms + → HTTP 201 {"id":"01M3EA4J0JSPFRDF22J6E2CEY1","endpoint":"https://fcm.googleapis.com/fcm/send/e2e-d464594734e6ddf8569ec571f5832dbf"}: expected { status: 201, …(1) } to deeply equal { status: toSatisfy{…}, …(1) } + × tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [N12] PUT pay-assignment отвергает лишние поля и нереальные суммы (400) 31ms + → HTTP 200 {"id":"01M3EA4J1PHXWHFMAMYYVRMK3E","employee_id":"01M3EA4J151B1H9D5AKAR29AN9","org_unit_id":null,"pay_rule_id":"01M3EA4FCDRQSS6V8H5Q6XS615","pay_rule_code":"hourly","pay_rule_name":"Почасовая (стажёр, дополнительный сотрудник)","rate_minor":12345,"percent_bp":0,"guarantee_minor":0,"pool_weight_bp":0… | HTTP 200 {"id":"01M3EA4J1PHXWHFMAMYYVRMK3E","employee_id":"01M3EA4J151B1H9D5AKAR29AN9","org_unit_id":null,"pay_rule_id":"01M3EA4FCDRQSS6V8H5Q6XS615","pay_rule_code":"hourly","pay_rule_name":"Почасовая (стажёр, дополнительный сотрудник)","rate_minor":9007199254740991,"percent_bp":0,"guarantee_minor":900719925…: expected { extra: 200, huge: 200 } to deeply equal { extra: 400, huge: 400 } + × tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [N10] терминальный токен не читает справочники профессий и точек (403) 4ms + → expected { professions: 200, units: 200 } to deeply equal { professions: 403, units: 403 } + × tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [F2] standalone без токенов не выдаёт права менеджера анонимному запросу (401) 20ms + → expected { portal: 200, payroll: 200, …(1) } to deeply equal { portal: 401, payroll: 401, …(1) } + × tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [F3] cookie сессии не содержит сырой токен и отзывается при выходе 8ms + → expected { rawTokenInCookie: true, …(1) } to deeply equal { rawTokenInCookie: false, …(1) } + × tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [F10] мутация по cookie без Origin отклоняется (CSRF, 403) 5ms + → HTTP 201 {"id":"01M3EA4J31CEM99Y9708PNVE90","code":"profession-01m3ea4j31cem99y9708pnve90","name":"E2E-CSRF-профессия-c30803","status":"active"}: expected 201 to be 403 // Object.is equality + × tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [F7] повтор Idempotency-Key с другим телом не создаёт второе событие 31ms + → expected { first: 201, secondCreated: true } to deeply equal { first: 201, secondCreated: false } + × tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [N11] импорт с неверным kind начисления → 400, а не 500 25ms + → HTTP 500 {"statusCode":500,"code":"23514","error":"Internal Server Error","message":"new row for relation \"staff_payroll_ledger\" violates check constraint \"staff_payroll_ledger_kind_check\""}: expected 500 to be 400 // Object.is equality + × tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [F4] перебор ключей входа ограничивается (429 не позже 30 неверных попыток) 75ms + → статусы: 401: expected false to be true // Object.is equality + × tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-01] менеджер точки A запускает расчёт для точки B → 403 110ms + → C1 POST /access-grants (point_manager): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + × tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-02] менеджер точки отправляет пакет на согласование → 403 64ms + → C1 POST /access-grants (point_manager): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + × tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-03] бухгалтер отправляет пакет → успех, каждый директор получает ровно одно уведомление 2ms + → C1 POST /access-grants (accountant): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + × tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-04] бухгалтер пытается подписать пакет → 403 2ms + → C1 POST /access-grants (accountant): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + × tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-05] до подписи директора в ledger нет начислений и выплат 2ms + → C1 POST /access-grants (accountant): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + × tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-06] подпись директора → начисления и выплаты в ledger, пакет и смены неизменяемы 2ms + → C1 POST /access-grants (accountant): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + × tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-07] смена изменена после отправки → подписать нельзя (409), пакет возвращён бухгалтеру 1ms + → C1 POST /access-grants (accountant): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + × tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-08] возврат с комментарием → пакет у бухгалтера, комментарий сохранён 2ms + → C1 POST /access-grants (accountant): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + × tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-09] сотрудник точки A отработал смену в точке B → смена попадает в зарплату точки B 2ms + → C1 POST /access-grants (accountant): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + × tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-10] сотрудник без согласия на биометрию → сервер сообщает терминалу «регистрация запрещена» 15ms + → C3: HTTP 404 {"message":"Route GET:/api/v1/staff/terminal/employees/01M3EA4JGPPB7M0G78QQBQBJ1M/enrollment not found","error":"Not Found","statusCode":404}: expected 404 to be 200 // Object.is equality + × tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-11] согласие отозвано → статус для терминала меняется 15ms + → C3 PUT biometric-consent: HTTP 404 {"message":"Route PUT:/api/v1/staff/employees/01M3EA4JH57XZ361XBC2Z7SA6J/biometric-consent not found","error":"Not Found","statusCode":404}: expected 404 to be 200 // Object.is equality + × tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-A] устройство не может само подтвердить смену (status=confirmed отклоняется) 87ms + → HTTP 200 {"results":[{"idempotency_key":"e2e-01M3EA4JPXC3E39GZMHFH33H92","command_type":"upsert_work_session","status":"applied","result":{"id":"01M3EA4JPXQPVQDPGEA3YVFPXV","revision":1,"status":"applied"}}]}: expected { http: 200, result: 'applied', …(1) } to deeply equal { http: 200, result: 'rejected', …(1) } + × tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-B] устройство не может утвердить табель (status=approved отклоняется) 32ms + → HTTP 200 {"results":[{"idempotency_key":"e2e-01M3EA4JR4CST4PE643FC043K9","command_type":"upsert_timesheet_entry","status":"applied","result":{"id":"01M3EA4JR43V65BMVJVX5DHSV0","revision":1,"status":"applied"}}]}: expected { result: 'applied', …(1) } to deeply equal { result: 'rejected', stored: null } + × tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-C0] начальная загрузка (pull без курсора) работает на реальной БД (200) 39ms + → HTTP 500 {"statusCode":500,"code":"42703","error":"Internal Server Error","message":"column \"status\" does not exist"}: expected 500 to be 200 // Object.is equality + × tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-C] начальная загрузка >100 сущностей отдаёт все сущности постранично 55ms + → HTTP 500 {"statusCode":500,"code":"42703","error":"Internal Server Error","message":"column \"status\" does not exist"}: expected 500 to be 200 // Object.is equality + × tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-D] изменения, сделанные через портал, попадают в инкрементальный pull 41ms + → expected false to be true // Object.is equality + × tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-E] отметка уволенного сотрудника через sync отклоняется 24ms + → HTTP 200 {"results":[{"idempotency_key":"e2e-01M3EA4JXB10Y1W7WAT3QXPJXR","command_type":"attendance_event","status":"applied","result":{"event_id":"01M3EA4JXD7TMSBAMMAK6HMXK2","status":"accepted"}}]}: expected 'applied' to be 'rejected' // Object.is equality + × tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-F] отметка через sync сохраняет точку устройства; чужая точка в payload отклоняется 42ms + → HTTP 200 {"results":[{"idempotency_key":"e2e-01M3EA4JYFDZ0AAZYVEF6G72T2","command_type":"attendance_event","status":"applied","result":{"event_id":"01M3EA4JYH12S10KQ4NWN232FM","status":"accepted"}},{"idempotency_key":"e2e-01M3EA4JYFDXJXPH923SG1E832","command_type":"attendance_event","status":"applied","resul…: expected { Object (ownOrgUnit, foreign) } to deeply equal { …(2) } + × tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-G] битая команда в пакете отклоняется по отдельности, остальные применяются (не 500) 21ms + → HTTP 500 {"statusCode":500,"code":"22007","error":"Internal Server Error","message":"invalid input syntax for type timestamp with time zone: \"e2e-not-a-timestamp\""}: expected { http: 500, statuses: [] } to deeply equal { http: 200, statuses: [ …(2) ] } + × tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-H] регистрация устройства по cookie с чужим Origin отклоняется (CSRF, 403) 9ms + → HTTP 201 {"device":{"id":"01M3EA4JZKVD04KCMNCGGW1EAH","tenant_id":"01M3EA4DJNEY3HRCYSBSX43XW0","device_code":"E2E-5J7EDPFQV6","name":"E2E-CSRF-терминал-34e01a","token_hint":"kstaff_dev_01M3E","status":"active","allowed_scopes":["attendance:sync"],"registered_at":"2026-09-26T07:33:38.935Z","created_by":"01M3E…: expected 201 to be 403 // Object.is equality + × tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-I] без настроенных токенов анонимный запрос не регистрирует устройство (401) 7ms + → HTTP 201 {"device":{"id":"01M3EA4JZWQF4S3SXWCX77J9ST","tenant_id":"01M3EA4DJNEY3HRCYSBSX43XW0","device_code":"E2E-KS5GF18F83","name":"E2E-Анонимный терминал-75d36d","token_hint":"kstaff_dev_01M3E","status":"active","allowed_scopes":["attendance:sync"],"registered_at":"2026-09-26T07:33:38.940Z","created_by":"…: expected 201 to be 401 // Object.is equality + × tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-J] отметка через sync вне окна времени (2001 год) отклоняется, как в POST /attendance/events 24ms + → HTTP 200 {"results":[{"idempotency_key":"e2e-01M3EA4K0JQNMDJTDAM1PZ1J8K","command_type":"attendance_event","status":"applied","result":{"event_id":"01M3EA4K0NB5RS8GACHWC7N2C2","status":"accepted"}}]}: expected 'applied' to be 'rejected' // Object.is equality + × tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-K] ack курсора из будущего (больше выданного сервером) отклоняется (400) 7ms + → HTTP 200 {"acknowledged":true,"cursor":"cur_999999999_fd163ccb01a6","acknowledged_at":"2026-09-26T07:33:38.972Z"}: expected 200 to be 400 // Object.is equality + ✓ tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-L] отозванное устройство не может синхронизироваться (403) — позитивный контроль 8ms + ✓ tests/e2e/00-harness.e2e.ts > HARNESS: реальный сервер + PostgreSQL 17 > [HARNESS] сервер отвечает live/ready (ready проверяет БД) 32ms + ✓ tests/e2e/00-harness.e2e.ts > HARNESS: реальный сервер + PostgreSQL 17 > [HARNESS] БД: PostgreSQL 17, приложение под ролью без SUPERUSER/BYPASSRLS, мигратор без SUPERUSER 14ms + ✓ tests/e2e/00-harness.e2e.ts > HARNESS: реальный сервер + PostgreSQL 17 > [HARNESS] миграции применены мигратором, app-роль не видит schema_migrations 14ms + ✓ tests/e2e/00-harness.e2e.ts > HARNESS: реальный сервер + PostgreSQL 17 > [HARNESS] токены: без токена 401, случайный токен 401, manager-токен 200 14ms + ✓ tests/e2e/00-harness.e2e.ts > HARNESS: реальный сервер + PostgreSQL 17 > [HARNESS] терминал: отметка сотрудника из импорта принимается (201) 25ms + ✓ tests/e2e/00-harness.e2e.ts > HARNESS: реальный сервер + PostgreSQL 17 > [CTRL] RBAC: терминал не видит портал и не создаёт сотрудников; сотрудник видит только себя 24ms + ✓ tests/e2e/00-harness.e2e.ts > HARNESS: реальный сервер + PostgreSQL 17 > [CTRL] уволенный сотрудник теряет доступ (401) 23ms + × tests/e2e/40-compose-pilot.e2e.ts > deploy/pilot/compose.yaml > [PILOT-1] все подставляемые переменные обязательны: ${VAR:?сообщение} 6ms + → переменные без :? — пустое значение молча попадёт в контейнер: expected [ 'STANDALONE_MANAGER_TOKEN', …(13) ] to deeply equal [] + × tests/e2e/40-compose-pilot.e2e.ts > deploy/pilot/compose.yaml > [PILOT-2] ни один сервис не запускается с NODE_ENV=development 1ms + → expected [ 'app' ] to deeply equal [] + ✓ tests/e2e/40-compose-pilot.e2e.ts > deploy/pilot/compose.yaml > [PILOT-3] у сервиса app нет учётных данных мигратора 1ms + +⎯⎯⎯⎯⎯⎯ Failed Tests 38 ⎯⎯⎯⎯⎯⎯⎯ + + FAIL tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [N1] менеджер создаёт сотрудника через POST /employees → 201 +AssertionError: HTTP 500 {"statusCode":500,"code":"42P08","error":"Internal Server Error","message":"inconsistent types deduced for parameter $2"}: expected 500 to be 201 // Object.is equality + +- Expected ++ Received + +- 201 ++ 500 + + ❯ tests/e2e/10-core-defects.e2e.ts:55:57 + 53| }, + 54| }); + 55| expect(response.status, describeResponse(response)).toBe(201); + | ^ + 56| const rows = await dbQuery('SELECT id FROM staff_employees WHERE p… + 57| number, + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/38]⎯ + + FAIL tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [N2] подтверждение смены, расчёт и утверждение зарплаты проходят (200) и начисляют 8 ч × ставка +AssertionError: подтверждение смены: HTTP 500 {"statusCode":500,"code":"23502","error":"Internal Server Error","message":"null value in column \"occurred_at\" of relation \"staff_outbox\" violates not-null constraint"}: expected 500 to be 200 // Object.is equality + +- Expected ++ Received + +- 200 ++ 500 + + ❯ tests/e2e/10-core-defects.e2e.ts:73:81 + 71| body: { status: 'confirmed' }, + 72| }); + 73| expect(confirm.status, `подтверждение смены: ${describeResponse(co… + | ^ + 74| + 75| const calculate = await api('POST', '/payroll/calculate', { + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/38]⎯ + + FAIL tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [N4] пересекающиеся расчёты не начисляют одну смену дважды +AssertionError: подтверждение смены (предусловие, см. N2): HTTP 500 {"statusCode":500,"code":"23502","error":"Internal Server Error","message":"null value in column \"occurred_at\" of relation \"staff_outbox\" violates not-null constraint"}: expected 500 to be 200 // Object.is equality + +- Expected ++ Received + +- 200 ++ 500 + + ❯ tests/e2e/10-core-defects.e2e.ts:104:7 + 102| confirm.status, + 103| `подтверждение смены (предусловие, см. N2): ${describeResponse(c… + 104| ).toBe(200); + | ^ + 105| + 106| const month = monthOf(day); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[3/38]⎯ + + FAIL tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [N3] push-подписка на внутренний адрес отклоняется, сервер не подключается к 127.0.0.1 +AssertionError: подписка: HTTP 201 {"id":"01M3EA4FH3FG4Q3YEKXYQ8Y4Q5","endpoint":"https://127.0.0.1:36027/e2e-internal-admin"}: expected { status: 201, connections: 1 } to deeply equal { status: toSatisfy{…}, …(1) } + +- Expected ++ Received + + { +- "connections": 0, +- "status": toSatisfy<[Function anonymous]>, ++ "connections": 1, ++ "status": 201, + } + + ❯ tests/e2e/10-core-defects.e2e.ts:161:9 + 159| { status: subscribe.status, connections }, + 160| `подписка: ${describeResponse(subscribe)}`, + 161| ).toEqual({ + | ^ + 162| status: expect.toSatisfy((s: number) => s === 400 || s === 422… + 163| connections: 0, + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[4/38]⎯ + + FAIL tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [N9] чужой push-endpoint нельзя перепривязать к другому сотруднику +AssertionError: HTTP 201 {"id":"01M3EA4J0JSPFRDF22J6E2CEY1","endpoint":"https://fcm.googleapis.com/fcm/send/e2e-d464594734e6ddf8569ec571f5832dbf"}: expected { status: 201, …(1) } to deeply equal { status: toSatisfy{…}, …(1) } + +- Expected ++ Received + + { + "owner": [ +- "01M3EA4HZSY982GYTPDAVP0Z0Q", ++ "01M3EA4HZTSZ12MKP3SV134FKS", + ], +- "status": toSatisfy<[Function anonymous]>, ++ "status": 201, + } + + ❯ tests/e2e/10-core-defects.e2e.ts:191:7 + 189| { status: second.status, owner: owner.map((row) => row.employee_… + 190| describeResponse(second), + 191| ).toEqual({ + | ^ + 192| status: expect.toSatisfy((s: number) => s === 409 || s === 403), + 193| owner: [employeeA!.id], + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[5/38]⎯ + + FAIL tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [N12] PUT pay-assignment отвергает лишние поля и нереальные суммы (400) +AssertionError: HTTP 200 {"id":"01M3EA4J1PHXWHFMAMYYVRMK3E","employee_id":"01M3EA4J151B1H9D5AKAR29AN9","org_unit_id":null,"pay_rule_id":"01M3EA4FCDRQSS6V8H5Q6XS615","pay_rule_code":"hourly","pay_rule_name":"Почасовая (стажёр, дополнительный сотрудник)","rate_minor":12345,"percent_bp":0,"guarantee_minor":0,"pool_weight_bp":0… | HTTP 200 {"id":"01M3EA4J1PHXWHFMAMYYVRMK3E","employee_id":"01M3EA4J151B1H9D5AKAR29AN9","org_unit_id":null,"pay_rule_id":"01M3EA4FCDRQSS6V8H5Q6XS615","pay_rule_code":"hourly","pay_rule_name":"Почасовая (стажёр, дополнительный сотрудник)","rate_minor":9007199254740991,"percent_bp":0,"guarantee_minor":900719925…: expected { extra: 200, huge: 200 } to deeply equal { extra: 400, huge: 400 } + +- Expected ++ Received + + { +- "extra": 400, +- "huge": 400, ++ "extra": 200, ++ "huge": 200, + } + + ❯ tests/e2e/10-core-defects.e2e.ts:215:7 + 213| { extra: extra.status, huge: huge.status }, + 214| `${describeResponse(extra)} | ${describeResponse(huge)}`, + 215| ).toEqual({ + | ^ + 216| extra: 400, + 217| huge: 400, + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[6/38]⎯ + + FAIL tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [N10] терминальный токен не читает справочники профессий и точек (403) +AssertionError: expected { professions: 200, units: 200 } to deeply equal { professions: 403, units: 403 } + +- Expected ++ Received + + { +- "professions": 403, +- "units": 403, ++ "professions": 200, ++ "units": 200, + } + + ❯ tests/e2e/10-core-defects.e2e.ts:224:70 + 222| const professions = await api('GET', '/professions', { token: ctx(… + 223| const units = await api('GET', '/org-units', { token: ctx().termin… + 224| expect({ professions: professions.status, units: units.status }).t… + | ^ + 225| professions: 403, + 226| units: 403, + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[7/38]⎯ + + FAIL tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [F2] standalone без токенов не выдаёт права менеджера анонимному запросу (401) +AssertionError: expected { portal: 200, payroll: 200, …(1) } to deeply equal { portal: 401, payroll: 401, …(1) } + +- Expected ++ Received + + { +- "payroll": 401, +- "portal": 401, +- "write": 401, ++ "payroll": 200, ++ "portal": 200, ++ "write": 201, + } + + ❯ tests/e2e/10-core-defects.e2e.ts:237:85 + 235| body: { name: synthetic('Профессия') }, + 236| }); + 237| expect({ portal: portal.status, payroll: payroll.status, write: wr… + | ^ + 238| portal: 401, + 239| payroll: 401, + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[8/38]⎯ + + FAIL tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [F3] cookie сессии не содержит сырой токен и отзывается при выходе +AssertionError: expected { rawTokenInCookie: true, …(1) } to deeply equal { rawTokenInCookie: false, …(1) } + +- Expected ++ Received + + { +- "afterLogout": 401, +- "rawTokenInCookie": false, ++ "afterLogout": 200, ++ "rawTokenInCookie": true, + } + + ❯ tests/e2e/10-core-defects.e2e.ts:255:91 + 253| expect(logout.status).toBe(204); + 254| const reuse = await api('GET', '/portal', { headers: { cookie } }); + 255| expect({ rawTokenInCookie: value === ctx().managerToken, afterLogo… + | ^ + 256| rawTokenInCookie: false, + 257| afterLogout: 401, + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[9/38]⎯ + + FAIL tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [F10] мутация по cookie без Origin отклоняется (CSRF, 403) +AssertionError: HTTP 201 {"id":"01M3EA4J31CEM99Y9708PNVE90","code":"profession-01m3ea4j31cem99y9708pnve90","name":"E2E-CSRF-профессия-c30803","status":"active"}: expected 201 to be 403 // Object.is equality + +- Expected ++ Received + +- 403 ++ 201 + + ❯ tests/e2e/10-core-defects.e2e.ts:269:57 + 267| body: { name: synthetic('CSRF-профессия') }, + 268| }); + 269| expect(response.status, describeResponse(response)).toBe(403); + | ^ + 270| }); + 271| + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[10/38]⎯ + + FAIL tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [F7] повтор Idempotency-Key с другим телом не создаёт второе событие +AssertionError: expected { first: 201, secondCreated: true } to deeply equal { first: 201, secondCreated: false } + +- Expected ++ Received + + { + "first": 201, +- "secondCreated": false, ++ "secondCreated": true, + } + + ❯ tests/e2e/10-core-defects.e2e.ts:288:75 + 286| const first = await send(`e2e-${randomUlid()}`); + 287| const second = await send(`e2e-${randomUlid()}`); + 288| expect({ first: first.status, secondCreated: second.status === 201… + | ^ + 289| first: 201, + 290| secondCreated: false, + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[11/38]⎯ + + FAIL tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [N11] импорт с неверным kind начисления → 400, а не 500 +AssertionError: HTTP 500 {"statusCode":500,"code":"23514","error":"Internal Server Error","message":"new row for relation \"staff_payroll_ledger\" violates check constraint \"staff_payroll_ledger_kind_check\""}: expected 500 to be 400 // Object.is equality + +- Expected ++ Received + +- 400 ++ 500 + + ❯ tests/e2e/10-core-defects.e2e.ts:311:57 + 309| }, + 310| }); + 311| expect(response.status, describeResponse(response)).toBe(400); + | ^ + 312| }); + 313| + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[12/38]⎯ + + FAIL tests/e2e/10-core-defects.e2e.ts > Основной API на реальной PostgreSQL > [F4] перебор ключей входа ограничивается (429 не позже 30 неверных попыток) +AssertionError: статусы: 401: expected false to be true // Object.is equality + +- Expected ++ Received + +- true ++ false + + ❯ tests/e2e/10-core-defects.e2e.ts:324:84 + 322| if (response.status === 429) break; + 323| } + 324| expect(statuses.includes(429), `статусы: ${[...new Set(statuses)].… + | ^ + 325| }); + 326| }); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[13/38]⎯ + + FAIL tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-A] устройство не может само подтвердить смену (status=confirmed отклоняется) +AssertionError: HTTP 200 {"results":[{"idempotency_key":"e2e-01M3EA4JPXC3E39GZMHFH33H92","command_type":"upsert_work_session","status":"applied","result":{"id":"01M3EA4JPXQPVQDPGEA3YVFPXV","revision":1,"status":"applied"}}]}: expected { http: 200, result: 'applied', …(1) } to deeply equal { http: 200, result: 'rejected', …(1) } + +- Expected ++ Received + + { + "http": 200, +- "result": "rejected", +- "stored": null, ++ "result": "applied", ++ "stored": "confirmed", + } + + ❯ tests/e2e/20-sync-defects.e2e.ts:86:7 + 84| }, + 85| describeResponse(response), + 86| ).toEqual({ http: 200, result: 'rejected', stored: null }); + | ^ + 87| }); + 88| + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[14/38]⎯ + + FAIL tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-B] устройство не может утвердить табель (status=approved отклоняется) +AssertionError: HTTP 200 {"results":[{"idempotency_key":"e2e-01M3EA4JR4CST4PE643FC043K9","command_type":"upsert_timesheet_entry","status":"applied","result":{"id":"01M3EA4JR43V65BMVJVX5DHSV0","revision":1,"status":"applied"}}]}: expected { result: 'applied', …(1) } to deeply equal { result: 'rejected', stored: null } + +- Expected ++ Received + + { +- "result": "rejected", +- "stored": null, ++ "result": "applied", ++ "stored": "approved", + } + + ❯ tests/e2e/20-sync-defects.e2e.ts:109:7 + 107| { result: response.body?.results?.[0]?.status, stored: stored[0]… + 108| describeResponse(response), + 109| ).toEqual({ result: 'rejected', stored: null }); + | ^ + 110| }); + 111| + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[15/38]⎯ + + FAIL tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-C0] начальная загрузка (pull без курсора) работает на реальной БД (200) +AssertionError: HTTP 500 {"statusCode":500,"code":"42703","error":"Internal Server Error","message":"column \"status\" does not exist"}: expected 500 to be 200 // Object.is equality + +- Expected ++ Received + +- 200 ++ 500 + + ❯ tests/e2e/20-sync-defects.e2e.ts:120:57 + 118| body: { cursor: null }, + 119| }); + 120| expect(response.status, describeResponse(response)).toBe(200); + | ^ + 121| const types = new Set( + 122| (response.body.changes as Array<{ entity_type: string }>).map((c… + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[16/38]⎯ + + FAIL tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-C] начальная загрузка >100 сущностей отдаёт все сущности постранично +AssertionError: HTTP 500 {"statusCode":500,"code":"42703","error":"Internal Server Error","message":"column \"status\" does not exist"}: expected 500 to be 200 // Object.is equality + +- Expected ++ Received + +- 200 ++ 500 + + ❯ pullAll tests/e2e/20-sync-defects.e2e.ts:51:57 + 49| body: { cursor: next, limit: 100 }, + 50| }); + 51| expect(response.status, describeResponse(response)).toBe(200); + | ^ + 52| changes.push(...(response.body.changes as Array<{ entity_type: str… + 53| next = response.body.next_cursor as string; + ❯ tests/e2e/20-sync-defects.e2e.ts:130:25 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[17/38]⎯ + + FAIL tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-D] изменения, сделанные через портал, попадают в инкрементальный pull +AssertionError: expected false to be true // Object.is equality + +- Expected ++ Received + +- true ++ false + + ❯ tests/e2e/20-sync-defects.e2e.ts:151:95 + 149| expect(patch.status, describeResponse(patch)).toBe(200); + 150| const { changes } = await pullAll(device, cursor); + 151| expect(changes.some((c) => c.entity_type === 'employee' && c.entit… + | ^ + 152| true, + 153| ); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[18/38]⎯ + + FAIL tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-E] отметка уволенного сотрудника через sync отклоняется +AssertionError: HTTP 200 {"results":[{"idempotency_key":"e2e-01M3EA4JXB10Y1W7WAT3QXPJXR","command_type":"attendance_event","status":"applied","result":{"event_id":"01M3EA4JXD7TMSBAMMAK6HMXK2","status":"accepted"}}]}: expected 'applied' to be 'rejected' // Object.is equality + +Expected: "rejected" +Received: "applied" + + ❯ tests/e2e/20-sync-defects.e2e.ts:171:77 + 169| }), + 170| ]); + 171| expect(response.body?.results?.[0]?.status, describeResponse(respo… + | ^ + 172| }); + 173| + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[19/38]⎯ + + FAIL tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-F] отметка через sync сохраняет точку устройства; чужая точка в payload отклоняется +AssertionError: HTTP 200 {"results":[{"idempotency_key":"e2e-01M3EA4JYFDZ0AAZYVEF6G72T2","command_type":"attendance_event","status":"applied","result":{"event_id":"01M3EA4JYH12S10KQ4NWN232FM","status":"accepted"}},{"idempotency_key":"e2e-01M3EA4JYFDXJXPH923SG1E832","command_type":"attendance_event","status":"applied","resul…: expected { Object (ownOrgUnit, foreign) } to deeply equal { …(2) } + +- Expected ++ Received + + { +- "foreign": "rejected", +- "ownOrgUnit": "01M3EA4JXPPT6RXP11RKV1VY20", ++ "foreign": "applied", ++ "ownOrgUnit": null, + } + + ❯ tests/e2e/20-sync-defects.e2e.ts:202:7 + 200| }, + 201| describeResponse(response), + 202| ).toEqual({ ownOrgUnit: unitA!.id, foreign: 'rejected' }); + | ^ + 203| }); + 204| + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[20/38]⎯ + + FAIL tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-G] битая команда в пакете отклоняется по отдельности, остальные применяются (не 500) +AssertionError: HTTP 500 {"statusCode":500,"code":"22007","error":"Internal Server Error","message":"invalid input syntax for type timestamp with time zone: \"e2e-not-a-timestamp\""}: expected { http: 500, statuses: [] } to deeply equal { http: 200, statuses: [ …(2) ] } + +- Expected ++ Received + + { +- "http": 200, +- "statuses": [ +- "applied", +- "rejected", +- ], ++ "http": 500, ++ "statuses": [], + } + + ❯ tests/e2e/20-sync-defects.e2e.ts:225:7 + 223| }, + 224| describeResponse(response), + 225| ).toEqual({ http: 200, statuses: ['applied', 'rejected'] }); + | ^ + 226| }); + 227| + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[21/38]⎯ + + FAIL tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-H] регистрация устройства по cookie с чужим Origin отклоняется (CSRF, 403) +AssertionError: HTTP 201 {"device":{"id":"01M3EA4JZKVD04KCMNCGGW1EAH","tenant_id":"01M3EA4DJNEY3HRCYSBSX43XW0","device_code":"E2E-5J7EDPFQV6","name":"E2E-CSRF-терминал-34e01a","token_hint":"kstaff_dev_01M3E","status":"active","allowed_scopes":["attendance:sync"],"registered_at":"2026-09-26T07:33:38.935Z","created_by":"01M3E…: expected 201 to be 403 // Object.is equality + +- Expected ++ Received + +- 403 ++ 201 + + ❯ tests/e2e/20-sync-defects.e2e.ts:236:57 + 234| body: { device_code: `E2E-${randomUlid().slice(-10)}`, name: syn… + 235| }); + 236| expect(response.status, describeResponse(response)).toBe(403); + | ^ + 237| }); + 238| + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[22/38]⎯ + + FAIL tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-I] без настроенных токенов анонимный запрос не регистрирует устройство (401) +AssertionError: HTTP 201 {"device":{"id":"01M3EA4JZWQF4S3SXWCX77J9ST","tenant_id":"01M3EA4DJNEY3HRCYSBSX43XW0","device_code":"E2E-KS5GF18F83","name":"E2E-Анонимный терминал-75d36d","token_hint":"kstaff_dev_01M3E","status":"active","allowed_scopes":["attendance:sync"],"registered_at":"2026-09-26T07:33:38.940Z","created_by":"…: expected 201 to be 401 // Object.is equality + +- Expected ++ Received + +- 401 ++ 201 + + ❯ tests/e2e/20-sync-defects.e2e.ts:247:57 + 245| }, + 246| }); + 247| expect(response.status, describeResponse(response)).toBe(401); + | ^ + 248| }); + 249| + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[23/38]⎯ + + FAIL tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-J] отметка через sync вне окна времени (2001 год) отклоняется, как в POST /attendance/events +AssertionError: HTTP 200 {"results":[{"idempotency_key":"e2e-01M3EA4K0JQNMDJTDAM1PZ1J8K","command_type":"attendance_event","status":"applied","result":{"event_id":"01M3EA4K0NB5RS8GACHWC7N2C2","status":"accepted"}}]}: expected 'applied' to be 'rejected' // Object.is equality + +Expected: "rejected" +Received: "applied" + + ❯ tests/e2e/20-sync-defects.e2e.ts:260:77 + 258| }), + 259| ]); + 260| expect(response.body?.results?.[0]?.status, describeResponse(respo… + | ^ + 261| }); + 262| + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[24/38]⎯ + + FAIL tests/e2e/20-sync-defects.e2e.ts > Офлайн-синхронизация на реальной PostgreSQL > [SYNC-K] ack курсора из будущего (больше выданного сервером) отклоняется (400) +AssertionError: HTTP 200 {"acknowledged":true,"cursor":"cur_999999999_fd163ccb01a6","acknowledged_at":"2026-09-26T07:33:38.972Z"}: expected 200 to be 400 // Object.is equality + +- Expected ++ Received + +- 400 ++ 200 + + ❯ tests/e2e/20-sync-defects.e2e.ts:275:57 + 273| body: { cursor: `cur_${seq}_${hash}` }, + 274| }); + 275| expect(response.status, describeResponse(response)).toBe(400); + | ^ + 276| }); + 277| + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[25/38]⎯ + + FAIL tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-01] менеджер точки A запускает расчёт для точки B → 403 +AssertionError: C1 POST /access-grants (point_manager): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + +- Expected ++ Received + +- 201 ++ 404 + + ❯ grant tests/e2e/30-owner-decisions.e2e.ts:28:94 + 26| body: { role, org_unit_ids: orgUnitIds, display_name: synthetic(ro… + 27| }); + 28| expect(response.status, `C1 POST /access-grants (${role}): ${describ… + | ^ + 29| 201, + 30| ); + ❯ tests/e2e/30-owner-decisions.e2e.ts:94:22 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[26/38]⎯ + + FAIL tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-02] менеджер точки отправляет пакет на согласование → 403 +AssertionError: C1 POST /access-grants (point_manager): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + +- Expected ++ Received + +- 201 ++ 404 + + ❯ grant tests/e2e/30-owner-decisions.e2e.ts:28:94 + 26| body: { role, org_unit_ids: orgUnitIds, display_name: synthetic(ro… + 27| }); + 28| expect(response.status, `C1 POST /access-grants (${role}): ${describ… + | ^ + 29| 201, + 30| ); + ❯ tests/e2e/30-owner-decisions.e2e.ts:105:22 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[27/38]⎯ + + FAIL tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-03] бухгалтер отправляет пакет → успех, каждый директор получает ровно одно уведомление +AssertionError: C1 POST /access-grants (accountant): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + +- Expected ++ Received + +- 201 ++ 404 + + ❯ grant tests/e2e/30-owner-decisions.e2e.ts:28:94 + 26| body: { role, org_unit_ids: orgUnitIds, display_name: synthetic(ro… + 27| }); + 28| expect(response.status, `C1 POST /access-grants (${role}): ${describ… + | ^ + 29| 201, + 30| ); + ❯ tests/e2e/30-owner-decisions.e2e.ts:118:24 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[28/38]⎯ + + FAIL tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-04] бухгалтер пытается подписать пакет → 403 +AssertionError: C1 POST /access-grants (accountant): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + +- Expected ++ Received + +- 201 ++ 404 + + ❯ grant tests/e2e/30-owner-decisions.e2e.ts:28:94 + 26| body: { role, org_unit_ids: orgUnitIds, display_name: synthetic(ro… + 27| }); + 28| expect(response.status, `C1 POST /access-grants (${role}): ${describ… + | ^ + 29| 201, + 30| ); + ❯ tests/e2e/30-owner-decisions.e2e.ts:133:24 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[29/38]⎯ + + FAIL tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-05] до подписи директора в ledger нет начислений и выплат +AssertionError: C1 POST /access-grants (accountant): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + +- Expected ++ Received + +- 201 ++ 404 + + ❯ grant tests/e2e/30-owner-decisions.e2e.ts:28:94 + 26| body: { role, org_unit_ids: orgUnitIds, display_name: synthetic(ro… + 27| }); + 28| expect(response.status, `C1 POST /access-grants (${role}): ${describ… + | ^ + 29| 201, + 30| ); + ❯ tests/e2e/30-owner-decisions.e2e.ts:141:24 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[30/38]⎯ + + FAIL tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-06] подпись директора → начисления и выплаты в ledger, пакет и смены неизменяемы +AssertionError: C1 POST /access-grants (accountant): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + +- Expected ++ Received + +- 201 ++ 404 + + ❯ grant tests/e2e/30-owner-decisions.e2e.ts:28:94 + 26| body: { role, org_unit_ids: orgUnitIds, display_name: synthetic(ro… + 27| }); + 28| expect(response.status, `C1 POST /access-grants (${role}): ${describ… + | ^ + 29| 201, + 30| ); + ❯ tests/e2e/30-owner-decisions.e2e.ts:148:24 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[31/38]⎯ + + FAIL tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-07] смена изменена после отправки → подписать нельзя (409), пакет возвращён бухгалтеру +AssertionError: C1 POST /access-grants (accountant): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + +- Expected ++ Received + +- 201 ++ 404 + + ❯ grant tests/e2e/30-owner-decisions.e2e.ts:28:94 + 26| body: { role, org_unit_ids: orgUnitIds, display_name: synthetic(ro… + 27| }); + 28| expect(response.status, `C1 POST /access-grants (${role}): ${describ… + | ^ + 29| 201, + 30| ); + ❯ tests/e2e/30-owner-decisions.e2e.ts:173:24 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[32/38]⎯ + + FAIL tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-08] возврат с комментарием → пакет у бухгалтера, комментарий сохранён +AssertionError: C1 POST /access-grants (accountant): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + +- Expected ++ Received + +- 201 ++ 404 + + ❯ grant tests/e2e/30-owner-decisions.e2e.ts:28:94 + 26| body: { role, org_unit_ids: orgUnitIds, display_name: synthetic(ro… + 27| }); + 28| expect(response.status, `C1 POST /access-grants (${role}): ${describ… + | ^ + 29| 201, + 30| ); + ❯ tests/e2e/30-owner-decisions.e2e.ts:195:24 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[33/38]⎯ + + FAIL tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-09] сотрудник точки A отработал смену в точке B → смена попадает в зарплату точки B +AssertionError: C1 POST /access-grants (accountant): HTTP 404 {"message":"Route POST:/api/v1/staff/access-grants not found","error":"Not Found","statusCode":404}: expected 404 to be 201 // Object.is equality + +- Expected ++ Received + +- 201 ++ 404 + + ❯ grant tests/e2e/30-owner-decisions.e2e.ts:28:94 + 26| body: { role, org_unit_ids: orgUnitIds, display_name: synthetic(ro… + 27| }); + 28| expect(response.status, `C1 POST /access-grants (${role}): ${describ… + | ^ + 29| 201, + 30| ); + ❯ tests/e2e/30-owner-decisions.e2e.ts:213:24 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[34/38]⎯ + + FAIL tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-10] сотрудник без согласия на биометрию → сервер сообщает терминалу «регистрация запрещена» +AssertionError: C3: HTTP 404 {"message":"Route GET:/api/v1/staff/terminal/employees/01M3EA4JGPPB7M0G78QQBQBJ1M/enrollment not found","error":"Not Found","statusCode":404}: expected 404 to be 200 // Object.is equality + +- Expected ++ Received + +- 200 ++ 404 + + ❯ tests/e2e/30-owner-decisions.e2e.ts:241:66 + 239| token: ctx().terminalToken, + 240| }); + 241| expect(response.status, `C3: ${describeResponse(response)}`).toBe(… + | ^ + 242| expect(response.body).toMatchObject({ registration_allowed: false,… + 243| }); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[35/38]⎯ + + FAIL tests/e2e/30-owner-decisions.e2e.ts > Решения владельца: роли, пакеты зарплаты, согласие на биометрию > [OWN-11] согласие отозвано → статус для терминала меняется +AssertionError: C3 PUT biometric-consent: HTTP 404 {"message":"Route PUT:/api/v1/staff/employees/01M3EA4JH57XZ361XBC2Z7SA6J/biometric-consent not found","error":"Not Found","statusCode":404}: expected 404 to be 200 // Object.is equality + +- Expected ++ Received + +- 200 ++ 404 + + ❯ tests/e2e/30-owner-decisions.e2e.ts:255:86 + 253| api('GET', `/terminal/employees/${employee!.id}/enrollment`, { t… + 254| const granted = await setConsent('granted'); + 255| expect(granted.status, `C3 PUT biometric-consent: ${describeRespon… + | ^ + 256| const before = await enrollment(); + 257| const revoked = await setConsent('revoked'); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[36/38]⎯ + + FAIL tests/e2e/40-compose-pilot.e2e.ts > deploy/pilot/compose.yaml > [PILOT-1] все подставляемые переменные обязательны: ${VAR:?сообщение} +AssertionError: переменные без :? — пустое значение молча попадёт в контейнер: expected [ 'STANDALONE_MANAGER_TOKEN', …(13) ] to deeply equal [] + +- Expected ++ Received + +- [] ++ [ ++ "STANDALONE_MANAGER_TOKEN", ++ "STANDALONE_TERMINAL_TOKEN", ++ "STANDALONE_TENANT_ID", ++ "STANDALONE_ACTOR_ID", ++ "STANDALONE_TERMINAL_ACTOR_ID", ++ "VAPID_PUBLIC_KEY", ++ "VAPID_PRIVATE_KEY", ++ "VAPID_SUBJECT", ++ "POSTGRES_APP_PASSWORD", ++ "HTTPS_PFX_PASSPHRASE", ++ "POSTGRES_MIGRATION_PASSWORD", ++ "POSTGRES_APP_PASSWORD", ++ "POSTGRES_MIGRATION_PASSWORD", ++ "POSTGRES_MIGRATION_PASSWORD", ++ ] + + ❯ tests/e2e/40-compose-pilot.e2e.ts:34:87 + 32| expect(interpolations.length).toBeGreaterThan(0); + 33| const optional = interpolations.filter((inner) => !/^[A-Z0-9_]+:\?… + 34| expect(optional, 'переменные без :? — пустое значение молча попадё… + | ^ + 35| }); + 36| + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[37/38]⎯ + + FAIL tests/e2e/40-compose-pilot.e2e.ts > deploy/pilot/compose.yaml > [PILOT-2] ни один сервис не запускается с NODE_ENV=development +AssertionError: expected [ 'app' ] to deeply equal [] + +- Expected ++ Received + +- [] ++ [ ++ "app", ++ ] + + ❯ tests/e2e/40-compose-pilot.e2e.ts:41:23 + 39| (service) => environmentOf(service).NODE_ENV === 'development', + 40| ); + 41| expect(offenders).toEqual([]); + | ^ + 42| }); + 43| + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[38/38]⎯ + + + Test Files 4 failed | 1 passed (5) + Tests 38 failed | 9 passed (47) + Start at 14:33:32 + Duration 7.22s (tests 95%, import 3%, transform 2%) + +JSON report written to /workspace/krona-staff/tests/e2e/evidence/e2e-results.json diff --git a/tests/e2e/evidence/e2e-table.md b/tests/e2e/evidence/e2e-table.md new file mode 100644 index 0000000..bbfceb0 --- /dev/null +++ b/tests/e2e/evidence/e2e-table.md @@ -0,0 +1,44 @@ +| ID | Цвет | Зелёных/всего | Вердикт | +| ------- | ----- | ------------- | ----------------------------- | +| CTRL | GREEN | 2/2 | зелёный | +| F10 | RED | 0/1 | красный (известный дефект) | +| F2 | RED | 0/1 | красный (известный дефект) | +| F3 | RED | 0/1 | красный (известный дефект) | +| F4 | RED | 0/1 | красный (известный дефект) | +| F7 | RED | 0/1 | красный (известный дефект) | +| HARNESS | GREEN | 5/5 | зелёный (позитивный контроль) | +| N1 | RED | 0/1 | красный (известный дефект) | +| N10 | RED | 0/1 | красный (известный дефект) | +| N11 | RED | 0/1 | красный (известный дефект) | +| N12 | RED | 0/1 | красный (известный дефект) | +| N2 | RED | 0/1 | красный (известный дефект) | +| N3 | RED | 0/1 | красный (известный дефект) | +| N4 | RED | 0/1 | красный (известный дефект) | +| N9 | RED | 0/1 | красный (известный дефект) | +| OWN-01 | RED | 0/1 | красный (известный дефект) | +| OWN-02 | RED | 0/1 | красный (известный дефект) | +| OWN-03 | RED | 0/1 | красный (известный дефект) | +| OWN-04 | RED | 0/1 | красный (известный дефект) | +| OWN-05 | RED | 0/1 | красный (известный дефект) | +| OWN-06 | RED | 0/1 | красный (известный дефект) | +| OWN-07 | RED | 0/1 | красный (известный дефект) | +| OWN-08 | RED | 0/1 | красный (известный дефект) | +| OWN-09 | RED | 0/1 | красный (известный дефект) | +| OWN-10 | RED | 0/1 | красный (известный дефект) | +| OWN-11 | RED | 0/1 | красный (известный дефект) | +| PILOT-1 | RED | 0/1 | красный (известный дефект) | +| PILOT-2 | RED | 0/1 | красный (известный дефект) | +| PILOT-3 | GREEN | 1/1 | зелёный | +| SYNC-A | RED | 0/1 | красный (известный дефект) | +| SYNC-B | RED | 0/1 | красный (известный дефект) | +| SYNC-C | RED | 0/1 | красный (известный дефект) | +| SYNC-C0 | RED | 0/1 | красный (известный дефект) | +| SYNC-D | RED | 0/1 | красный (известный дефект) | +| SYNC-E | RED | 0/1 | красный (известный дефект) | +| SYNC-F | RED | 0/1 | красный (известный дефект) | +| SYNC-G | RED | 0/1 | красный (известный дефект) | +| SYNC-H | RED | 0/1 | красный (известный дефект) | +| SYNC-I | RED | 0/1 | красный (известный дефект) | +| SYNC-J | RED | 0/1 | красный (известный дефект) | +| SYNC-K | RED | 0/1 | красный (известный дефект) | +| SYNC-L | GREEN | 1/1 | зелёный | diff --git a/tests/e2e/evidence/server-no-tokens.txt b/tests/e2e/evidence/server-no-tokens.txt new file mode 100644 index 0000000..a0429e7 --- /dev/null +++ b/tests/e2e/evidence/server-no-tokens.txt @@ -0,0 +1,11 @@ +{"level":30,"time":1790408014423,"pid":1688835,"hostname":"grok-bot-vm-420973429","msg":"Server listening at http://127.0.0.1:33821"} +{"level":30,"time":1790408014470,"pid":1688835,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4EM59MB3QYQ7QG56R4Q6","req":{"method":"GET","url":"/api/v1/staff/ready","host":"127.0.0.1:33821","remoteAddress":"127.0.0.1","remotePort":43800},"msg":"incoming request"} +{"level":30,"time":1790408014485,"pid":1688835,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4EM59MB3QYQ7QG56R4Q6","res":{"statusCode":200},"responseTime":15.399766999999997,"msg":"request completed"} +{"level":30,"time":1790408017988,"pid":1688835,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J24H0CNE1DPZ87J7PY6","req":{"method":"GET","url":"/api/v1/staff/portal","host":"127.0.0.1:33821","remoteAddress":"127.0.0.1","remotePort":41914},"msg":"incoming request"} +{"level":30,"time":1790408017995,"pid":1688835,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J24H0CNE1DPZ87J7PY6","res":{"statusCode":200},"responseTime":7.126036999999997,"msg":"request completed"} +{"level":30,"time":1790408017997,"pid":1688835,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J2CSDE96DCZ4X0TSJ1E","req":{"method":"GET","url":"/api/v1/staff/payroll","host":"127.0.0.1:33821","remoteAddress":"127.0.0.1","remotePort":41916},"msg":"incoming request"} +{"level":30,"time":1790408018000,"pid":1688835,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J2CSDE96DCZ4X0TSJ1E","res":{"statusCode":200},"responseTime":3.394659000000047,"msg":"request completed"} +{"level":30,"time":1790408018001,"pid":1688835,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J2HH1VC67KYM9CGFM3R","req":{"method":"POST","url":"/api/v1/staff/professions","host":"127.0.0.1:33821","remoteAddress":"127.0.0.1","remotePort":41914},"msg":"incoming request"} +{"level":30,"time":1790408018006,"pid":1688835,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J2HH1VC67KYM9CGFM3R","res":{"statusCode":201},"responseTime":4.0853070000002845,"msg":"request completed"} +{"level":30,"time":1790408018939,"pid":1688835,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JZTH0S49N5WD7NP5DXV","req":{"method":"POST","url":"/api/v1/staff/sync/devices","host":"127.0.0.1:33821","remoteAddress":"127.0.0.1","remotePort":41926},"msg":"incoming request"} +{"level":30,"time":1790408018943,"pid":1688835,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JZTH0S49N5WD7NP5DXV","res":{"statusCode":201},"responseTime":4.126679999999396,"msg":"request completed"} diff --git a/tests/e2e/evidence/server-rate-limit.txt b/tests/e2e/evidence/server-rate-limit.txt new file mode 100644 index 0000000..4bdfa60 --- /dev/null +++ b/tests/e2e/evidence/server-rate-limit.txt @@ -0,0 +1,93 @@ +{"level":30,"time":1790408014985,"pid":1688859,"hostname":"grok-bot-vm-420973429","msg":"Server listening at http://127.0.0.1:36299"} +{"level":30,"time":1790408014994,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4F4HH3VG14PERD1YSY9Y","req":{"method":"GET","url":"/api/v1/staff/ready","host":"127.0.0.1:36299","remoteAddress":"127.0.0.1","remotePort":38380},"msg":"incoming request"} +{"level":30,"time":1790408015008,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4F4HH3VG14PERD1YSY9Y","res":{"statusCode":200},"responseTime":13.205045999999982,"msg":"request completed"} +{"level":30,"time":1790408018078,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J4YV0JF6R2376AEHJPT","req":{"method":"POST","url":"/api/v1/staff/session","host":"127.0.0.1:36299","remoteAddress":"127.0.0.1","remotePort":34810},"msg":"incoming request"} +{"level":30,"time":1790408018085,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J4YV0JF6R2376AEHJPT","res":{"statusCode":401},"err":{"type":"UnauthorizedError","message":"Требуется действующий ключ доступа.","stack":"UnauthorizedError: Требуется действующий ключ доступа.\n at Object.unauthorized (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:25:12)\n at resolveToken (/workspace/krona-staff/src/portal.ts:1337:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:253:23)","status":401,"statusCode":401,"expose":true},"msg":"Требуется действующий ключ доступа."} +{"level":30,"time":1790408018088,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J4YV0JF6R2376AEHJPT","res":{"statusCode":401},"responseTime":10.026388999999654,"msg":"request completed"} +{"level":30,"time":1790408018090,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J5AY86FT8CXCVMZBCVE","req":{"method":"POST","url":"/api/v1/staff/session","host":"127.0.0.1:36299","remoteAddress":"127.0.0.1","remotePort":34822},"msg":"incoming request"} +{"level":30,"time":1790408018092,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J5AY86FT8CXCVMZBCVE","res":{"statusCode":401},"err":{"type":"UnauthorizedError","message":"Требуется действующий ключ доступа.","stack":"UnauthorizedError: Требуется действующий ключ доступа.\n at Object.unauthorized (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:25:12)\n at resolveToken (/workspace/krona-staff/src/portal.ts:1337:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:253:23)","status":401,"statusCode":401,"expose":true},"msg":"Требуется действующий ключ доступа."} +{"level":30,"time":1790408018093,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J5AY86FT8CXCVMZBCVE","res":{"statusCode":401},"responseTime":3.1223180000001776,"msg":"request completed"} +{"level":30,"time":1790408018094,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J5EVV7MG8NSJEN3BEHE","req":{"method":"POST","url":"/api/v1/staff/session","host":"127.0.0.1:36299","remoteAddress":"127.0.0.1","remotePort":34810},"msg":"incoming request"} +{"level":30,"time":1790408018095,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J5EVV7MG8NSJEN3BEHE","res":{"statusCode":401},"err":{"type":"UnauthorizedError","message":"Требуется действующий ключ доступа.","stack":"UnauthorizedError: Требуется действующий ключ доступа.\n at Object.unauthorized (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:25:12)\n at resolveToken (/workspace/krona-staff/src/portal.ts:1337:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:253:23)","status":401,"statusCode":401,"expose":true},"msg":"Требуется действующий ключ доступа."} +{"level":30,"time":1790408018095,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J5EVV7MG8NSJEN3BEHE","res":{"statusCode":401},"responseTime":1.5804190000003473,"msg":"request completed"} +{"level":30,"time":1790408018096,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J5GS3DNBZVF696K10GB","req":{"method":"POST","url":"/api/v1/staff/session","host":"127.0.0.1:36299","remoteAddress":"127.0.0.1","remotePort":34822},"msg":"incoming request"} +{"level":30,"time":1790408018097,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J5GS3DNBZVF696K10GB","res":{"statusCode":401},"err":{"type":"UnauthorizedError","message":"Требуется действующий ключ доступа.","stack":"UnauthorizedError: Требуется действующий ключ доступа.\n at Object.unauthorized (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:25:12)\n at resolveToken (/workspace/krona-staff/src/portal.ts:1337:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:253:23)","status":401,"statusCode":401,"expose":true},"msg":"Требуется действующий ключ доступа."} +{"level":30,"time":1790408018098,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J5GS3DNBZVF696K10GB","res":{"statusCode":401},"responseTime":1.4676269999999931,"msg":"request completed"} +{"level":30,"time":1790408018099,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J5J8T6KXH5TFHHSCHVF","req":{"method":"POST","url":"/api/v1/staff/session","host":"127.0.0.1:36299","remoteAddress":"127.0.0.1","remotePort":34810},"msg":"incoming request"} +{"level":30,"time":1790408018100,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J5J8T6KXH5TFHHSCHVF","res":{"statusCode":401},"err":{"type":"UnauthorizedError","message":"Требуется действующий ключ доступа.","stack":"UnauthorizedError: Требуется действующий ключ доступа.\n at Object.unauthorized (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:25:12)\n at resolveToken (/workspace/krona-staff/src/portal.ts:1337:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:253:23)","status":401,"statusCode":401,"expose":true},"msg":"Требуется действующий ключ доступа."} +{"level":30,"time":1790408018100,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J5J8T6KXH5TFHHSCHVF","res":{"statusCode":401},"responseTime":1.386855000000196,"msg":"request completed"} +{"level":30,"time":1790408018101,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J5NP6FY0C583X92CP43","req":{"method":"POST","url":"/api/v1/staff/session","host":"127.0.0.1:36299","remoteAddress":"127.0.0.1","remotePort":34822},"msg":"incoming request"} +{"level":30,"time":1790408018102,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J5NP6FY0C583X92CP43","res":{"statusCode":401},"err":{"type":"UnauthorizedError","message":"Требуется действующий ключ доступа.","stack":"UnauthorizedError: Требуется действующий ключ доступа.\n at Object.unauthorized (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:25:12)\n at resolveToken (/workspace/krona-staff/src/portal.ts:1337:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:253:23)","status":401,"statusCode":401,"expose":true},"msg":"Требуется действующий ключ доступа."} +{"level":30,"time":1790408018102,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J5NP6FY0C583X92CP43","res":{"statusCode":401},"responseTime":1.2076160000001437,"msg":"request completed"} +{"level":30,"time":1790408018103,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J5Q5TRCA85QYA3H0VYQ","req":{"method":"POST","url":"/api/v1/staff/session","host":"127.0.0.1:36299","remoteAddress":"127.0.0.1","remotePort":34810},"msg":"incoming request"} +{"level":30,"time":1790408018104,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J5Q5TRCA85QYA3H0VYQ","res":{"statusCode":401},"err":{"type":"UnauthorizedError","message":"Требуется действующий ключ доступа.","stack":"UnauthorizedError: Требуется действующий ключ доступа.\n at Object.unauthorized (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:25:12)\n at resolveToken (/workspace/krona-staff/src/portal.ts:1337:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:253:23)","status":401,"statusCode":401,"expose":true},"msg":"Требуется действующий ключ доступа."} +{"level":30,"time":1790408018104,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J5Q5TRCA85QYA3H0VYQ","res":{"statusCode":401},"responseTime":1.1122859999995853,"msg":"request completed"} +{"level":30,"time":1790408018105,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J5SA4BPNWS2DED9PXYB","req":{"method":"POST","url":"/api/v1/staff/session","host":"127.0.0.1:36299","remoteAddress":"127.0.0.1","remotePort":34822},"msg":"incoming request"} +{"level":30,"time":1790408018107,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J5SA4BPNWS2DED9PXYB","res":{"statusCode":401},"err":{"type":"UnauthorizedError","message":"Требуется действующий ключ доступа.","stack":"UnauthorizedError: Требуется действующий ключ доступа.\n at Object.unauthorized (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:25:12)\n at resolveToken (/workspace/krona-staff/src/portal.ts:1337:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:253:23)","status":401,"statusCode":401,"expose":true},"msg":"Требуется действующий ключ доступа."} +{"level":30,"time":1790408018107,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J5SA4BPNWS2DED9PXYB","res":{"statusCode":401},"responseTime":1.8221369999996568,"msg":"request completed"} +{"level":30,"time":1790408018108,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J5WVAX2TGTKMNXF5TMG","req":{"method":"POST","url":"/api/v1/staff/session","host":"127.0.0.1:36299","remoteAddress":"127.0.0.1","remotePort":34810},"msg":"incoming request"} +{"level":30,"time":1790408018110,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J5WVAX2TGTKMNXF5TMG","res":{"statusCode":401},"err":{"type":"UnauthorizedError","message":"Требуется действующий ключ доступа.","stack":"UnauthorizedError: Требуется действующий ключ доступа.\n at Object.unauthorized (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:25:12)\n at resolveToken (/workspace/krona-staff/src/portal.ts:1337:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:253:23)","status":401,"statusCode":401,"expose":true},"msg":"Требуется действующий ключ доступа."} +{"level":30,"time":1790408018110,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J5WVAX2TGTKMNXF5TMG","res":{"statusCode":401},"responseTime":1.6929129999998622,"msg":"request completed"} +{"level":30,"time":1790408018111,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J5ZJ0TBAM6HCKDG31ST","req":{"method":"POST","url":"/api/v1/staff/session","host":"127.0.0.1:36299","remoteAddress":"127.0.0.1","remotePort":34822},"msg":"incoming request"} +{"level":30,"time":1790408018112,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J5ZJ0TBAM6HCKDG31ST","res":{"statusCode":401},"err":{"type":"UnauthorizedError","message":"Требуется действующий ключ доступа.","stack":"UnauthorizedError: Требуется действующий ключ доступа.\n at Object.unauthorized (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:25:12)\n at resolveToken (/workspace/krona-staff/src/portal.ts:1337:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:253:23)","status":401,"statusCode":401,"expose":true},"msg":"Требуется действующий ключ доступа."} +{"level":30,"time":1790408018112,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J5ZJ0TBAM6HCKDG31ST","res":{"statusCode":401},"responseTime":1.3584950000004028,"msg":"request completed"} +{"level":30,"time":1790408018113,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J61SAXX1SBMMF6K7MW7","req":{"method":"POST","url":"/api/v1/staff/session","host":"127.0.0.1:36299","remoteAddress":"127.0.0.1","remotePort":34810},"msg":"incoming request"} +{"level":30,"time":1790408018114,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J61SAXX1SBMMF6K7MW7","res":{"statusCode":401},"err":{"type":"UnauthorizedError","message":"Требуется действующий ключ доступа.","stack":"UnauthorizedError: Требуется действующий ключ доступа.\n at Object.unauthorized (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:25:12)\n at resolveToken (/workspace/krona-staff/src/portal.ts:1337:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:253:23)","status":401,"statusCode":401,"expose":true},"msg":"Требуется действующий ключ доступа."} +{"level":30,"time":1790408018115,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J61SAXX1SBMMF6K7MW7","res":{"statusCode":401},"responseTime":1.17779500000006,"msg":"request completed"} +{"level":30,"time":1790408018116,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J64PXWG5P4DSGFA9VDQ","req":{"method":"POST","url":"/api/v1/staff/session","host":"127.0.0.1:36299","remoteAddress":"127.0.0.1","remotePort":34822},"msg":"incoming request"} +{"level":30,"time":1790408018117,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J64PXWG5P4DSGFA9VDQ","res":{"statusCode":401},"err":{"type":"UnauthorizedError","message":"Требуется действующий ключ доступа.","stack":"UnauthorizedError: Требуется действующий ключ доступа.\n at Object.unauthorized (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:25:12)\n at resolveToken (/workspace/krona-staff/src/portal.ts:1337:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:253:23)","status":401,"statusCode":401,"expose":true},"msg":"Требуется действующий ключ доступа."} +{"level":30,"time":1790408018117,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J64PXWG5P4DSGFA9VDQ","res":{"statusCode":401},"responseTime":1.2440259999998489,"msg":"request completed"} +{"level":30,"time":1790408018118,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J665CYSPZZM1V2R18JN","req":{"method":"POST","url":"/api/v1/staff/session","host":"127.0.0.1:36299","remoteAddress":"127.0.0.1","remotePort":34810},"msg":"incoming request"} +{"level":30,"time":1790408018119,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J665CYSPZZM1V2R18JN","res":{"statusCode":401},"err":{"type":"UnauthorizedError","message":"Требуется действующий ключ доступа.","stack":"UnauthorizedError: Требуется действующий ключ доступа.\n at Object.unauthorized (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:25:12)\n at resolveToken (/workspace/krona-staff/src/portal.ts:1337:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:253:23)","status":401,"statusCode":401,"expose":true},"msg":"Требуется действующий ключ доступа."} +{"level":30,"time":1790408018120,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J665CYSPZZM1V2R18JN","res":{"statusCode":401},"responseTime":1.6543000000001484,"msg":"request completed"} +{"level":30,"time":1790408018120,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J681X6JYH17BSE6KS7T","req":{"method":"POST","url":"/api/v1/staff/session","host":"127.0.0.1:36299","remoteAddress":"127.0.0.1","remotePort":34822},"msg":"incoming request"} +{"level":30,"time":1790408018121,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J681X6JYH17BSE6KS7T","res":{"statusCode":401},"err":{"type":"UnauthorizedError","message":"Требуется действующий ключ доступа.","stack":"UnauthorizedError: Требуется действующий ключ доступа.\n at Object.unauthorized (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:25:12)\n at resolveToken (/workspace/krona-staff/src/portal.ts:1337:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:253:23)","status":401,"statusCode":401,"expose":true},"msg":"Требуется действующий ключ доступа."} +{"level":30,"time":1790408018121,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J681X6JYH17BSE6KS7T","res":{"statusCode":401},"responseTime":0.9558520000000499,"msg":"request completed"} +{"level":30,"time":1790408018122,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6AZB9EF2ZWRM58K33X","req":{"method":"POST","url":"/api/v1/staff/session","host":"127.0.0.1:36299","remoteAddress":"127.0.0.1","remotePort":34810},"msg":"incoming request"} +{"level":30,"time":1790408018124,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6AZB9EF2ZWRM58K33X","res":{"statusCode":401},"err":{"type":"UnauthorizedError","message":"Требуется действующий ключ доступа.","stack":"UnauthorizedError: Требуется действующий ключ доступа.\n at Object.unauthorized (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:25:12)\n at resolveToken (/workspace/krona-staff/src/portal.ts:1337:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:253:23)","status":401,"statusCode":401,"expose":true},"msg":"Требуется действующий ключ доступа."} +{"level":30,"time":1790408018124,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6AZB9EF2ZWRM58K33X","res":{"statusCode":401},"responseTime":1.3041690000000017,"msg":"request completed"} +{"level":30,"time":1790408018125,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6DANVFJ43ANCSWN2AD","req":{"method":"POST","url":"/api/v1/staff/session","host":"127.0.0.1:36299","remoteAddress":"127.0.0.1","remotePort":34822},"msg":"incoming request"} +{"level":30,"time":1790408018126,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6DANVFJ43ANCSWN2AD","res":{"statusCode":401},"err":{"type":"UnauthorizedError","message":"Требуется действующий ключ доступа.","stack":"UnauthorizedError: Требуется действующий ключ доступа.\n at Object.unauthorized (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:25:12)\n at resolveToken (/workspace/krona-staff/src/portal.ts:1337:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:253:23)","status":401,"statusCode":401,"expose":true},"msg":"Требуется действующий ключ доступа."} +{"level":30,"time":1790408018126,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6DANVFJ43ANCSWN2AD","res":{"statusCode":401},"responseTime":1.0975260000000162,"msg":"request completed"} +{"level":30,"time":1790408018127,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6FB5G9XGHEX6J2DQD9","req":{"method":"POST","url":"/api/v1/staff/session","host":"127.0.0.1:36299","remoteAddress":"127.0.0.1","remotePort":34810},"msg":"incoming request"} +{"level":30,"time":1790408018128,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6FB5G9XGHEX6J2DQD9","res":{"statusCode":401},"err":{"type":"UnauthorizedError","message":"Требуется действующий ключ доступа.","stack":"UnauthorizedError: Требуется действующий ключ доступа.\n at Object.unauthorized (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:25:12)\n at resolveToken (/workspace/krona-staff/src/portal.ts:1337:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:253:23)","status":401,"statusCode":401,"expose":true},"msg":"Требуется действующий ключ доступа."} +{"level":30,"time":1790408018128,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6FB5G9XGHEX6J2DQD9","res":{"statusCode":401},"responseTime":0.9584480000003168,"msg":"request completed"} +{"level":30,"time":1790408018129,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6HN1B0FT6JSM29WA43","req":{"method":"POST","url":"/api/v1/staff/session","host":"127.0.0.1:36299","remoteAddress":"127.0.0.1","remotePort":34822},"msg":"incoming request"} +{"level":30,"time":1790408018129,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6HN1B0FT6JSM29WA43","res":{"statusCode":401},"err":{"type":"UnauthorizedError","message":"Требуется действующий ключ доступа.","stack":"UnauthorizedError: Требуется действующий ключ доступа.\n at Object.unauthorized (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:25:12)\n at resolveToken (/workspace/krona-staff/src/portal.ts:1337:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:253:23)","status":401,"statusCode":401,"expose":true},"msg":"Требуется действующий ключ доступа."} +{"level":30,"time":1790408018130,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6HN1B0FT6JSM29WA43","res":{"statusCode":401},"responseTime":0.8860890000000836,"msg":"request completed"} +{"level":30,"time":1790408018130,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6JYZVQY0HTDDS7J417","req":{"method":"POST","url":"/api/v1/staff/session","host":"127.0.0.1:36299","remoteAddress":"127.0.0.1","remotePort":34810},"msg":"incoming request"} +{"level":30,"time":1790408018131,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6JYZVQY0HTDDS7J417","res":{"statusCode":401},"err":{"type":"UnauthorizedError","message":"Требуется действующий ключ доступа.","stack":"UnauthorizedError: Требуется действующий ключ доступа.\n at Object.unauthorized (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:25:12)\n at resolveToken (/workspace/krona-staff/src/portal.ts:1337:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:253:23)","status":401,"statusCode":401,"expose":true},"msg":"Требуется действующий ключ доступа."} +{"level":30,"time":1790408018131,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6JYZVQY0HTDDS7J417","res":{"statusCode":401},"responseTime":1.0295750000000226,"msg":"request completed"} +{"level":30,"time":1790408018132,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6MATZ7QY0BR7V8AW72","req":{"method":"POST","url":"/api/v1/staff/session","host":"127.0.0.1:36299","remoteAddress":"127.0.0.1","remotePort":34822},"msg":"incoming request"} +{"level":30,"time":1790408018133,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6MATZ7QY0BR7V8AW72","res":{"statusCode":401},"err":{"type":"UnauthorizedError","message":"Требуется действующий ключ доступа.","stack":"UnauthorizedError: Требуется действующий ключ доступа.\n at Object.unauthorized (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:25:12)\n at resolveToken (/workspace/krona-staff/src/portal.ts:1337:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:253:23)","status":401,"statusCode":401,"expose":true},"msg":"Требуется действующий ключ доступа."} +{"level":30,"time":1790408018133,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6MATZ7QY0BR7V8AW72","res":{"statusCode":401},"responseTime":0.9096939999999449,"msg":"request completed"} +{"level":30,"time":1790408018134,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6PDK66S783WHQ51ASV","req":{"method":"POST","url":"/api/v1/staff/session","host":"127.0.0.1:36299","remoteAddress":"127.0.0.1","remotePort":34810},"msg":"incoming request"} +{"level":30,"time":1790408018135,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6PDK66S783WHQ51ASV","res":{"statusCode":401},"err":{"type":"UnauthorizedError","message":"Требуется действующий ключ доступа.","stack":"UnauthorizedError: Требуется действующий ключ доступа.\n at Object.unauthorized (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:25:12)\n at resolveToken (/workspace/krona-staff/src/portal.ts:1337:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:253:23)","status":401,"statusCode":401,"expose":true},"msg":"Требуется действующий ключ доступа."} +{"level":30,"time":1790408018135,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6PDK66S783WHQ51ASV","res":{"statusCode":401},"responseTime":0.9012949999996636,"msg":"request completed"} +{"level":30,"time":1790408018136,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6R8EVAMEACB5RG5PMT","req":{"method":"POST","url":"/api/v1/staff/session","host":"127.0.0.1:36299","remoteAddress":"127.0.0.1","remotePort":34822},"msg":"incoming request"} +{"level":30,"time":1790408018137,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6R8EVAMEACB5RG5PMT","res":{"statusCode":401},"err":{"type":"UnauthorizedError","message":"Требуется действующий ключ доступа.","stack":"UnauthorizedError: Требуется действующий ключ доступа.\n at Object.unauthorized (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:25:12)\n at resolveToken (/workspace/krona-staff/src/portal.ts:1337:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:253:23)","status":401,"statusCode":401,"expose":true},"msg":"Требуется действующий ключ доступа."} +{"level":30,"time":1790408018137,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6R8EVAMEACB5RG5PMT","res":{"statusCode":401},"responseTime":0.97691500000019,"msg":"request completed"} +{"level":30,"time":1790408018137,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6S4NWEJWJSHW2QW0H1","req":{"method":"POST","url":"/api/v1/staff/session","host":"127.0.0.1:36299","remoteAddress":"127.0.0.1","remotePort":34810},"msg":"incoming request"} +{"level":30,"time":1790408018138,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6S4NWEJWJSHW2QW0H1","res":{"statusCode":401},"err":{"type":"UnauthorizedError","message":"Требуется действующий ключ доступа.","stack":"UnauthorizedError: Требуется действующий ключ доступа.\n at Object.unauthorized (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:25:12)\n at resolveToken (/workspace/krona-staff/src/portal.ts:1337:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:253:23)","status":401,"statusCode":401,"expose":true},"msg":"Требуется действующий ключ доступа."} +{"level":30,"time":1790408018139,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6S4NWEJWJSHW2QW0H1","res":{"statusCode":401},"responseTime":1.0356249999999818,"msg":"request completed"} +{"level":30,"time":1790408018139,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6V5MVSWERJFSE4H8S1","req":{"method":"POST","url":"/api/v1/staff/session","host":"127.0.0.1:36299","remoteAddress":"127.0.0.1","remotePort":34822},"msg":"incoming request"} +{"level":30,"time":1790408018140,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6V5MVSWERJFSE4H8S1","res":{"statusCode":401},"err":{"type":"UnauthorizedError","message":"Требуется действующий ключ доступа.","stack":"UnauthorizedError: Требуется действующий ключ доступа.\n at Object.unauthorized (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:25:12)\n at resolveToken (/workspace/krona-staff/src/portal.ts:1337:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:253:23)","status":401,"statusCode":401,"expose":true},"msg":"Требуется действующий ключ доступа."} +{"level":30,"time":1790408018140,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6V5MVSWERJFSE4H8S1","res":{"statusCode":401},"responseTime":0.9596630000000914,"msg":"request completed"} +{"level":30,"time":1790408018141,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6X3SS6P42S0J20JY43","req":{"method":"POST","url":"/api/v1/staff/session","host":"127.0.0.1:36299","remoteAddress":"127.0.0.1","remotePort":34810},"msg":"incoming request"} +{"level":30,"time":1790408018142,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6X3SS6P42S0J20JY43","res":{"statusCode":401},"err":{"type":"UnauthorizedError","message":"Требуется действующий ключ доступа.","stack":"UnauthorizedError: Требуется действующий ключ доступа.\n at Object.unauthorized (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:25:12)\n at resolveToken (/workspace/krona-staff/src/portal.ts:1337:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:253:23)","status":401,"statusCode":401,"expose":true},"msg":"Требуется действующий ключ доступа."} +{"level":30,"time":1790408018142,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6X3SS6P42S0J20JY43","res":{"statusCode":401},"responseTime":0.8438820000001215,"msg":"request completed"} +{"level":30,"time":1790408018143,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6ZGJ3J8AZ6CADNGANJ","req":{"method":"POST","url":"/api/v1/staff/session","host":"127.0.0.1:36299","remoteAddress":"127.0.0.1","remotePort":34822},"msg":"incoming request"} +{"level":30,"time":1790408018144,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6ZGJ3J8AZ6CADNGANJ","res":{"statusCode":401},"err":{"type":"UnauthorizedError","message":"Требуется действующий ключ доступа.","stack":"UnauthorizedError: Требуется действующий ключ доступа.\n at Object.unauthorized (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:25:12)\n at resolveToken (/workspace/krona-staff/src/portal.ts:1337:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:253:23)","status":401,"statusCode":401,"expose":true},"msg":"Требуется действующий ключ доступа."} +{"level":30,"time":1790408018144,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J6ZGJ3J8AZ6CADNGANJ","res":{"statusCode":401},"responseTime":1.0216669999999795,"msg":"request completed"} +{"level":30,"time":1790408018145,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J70HW4EQGVGGWZBSN09","req":{"method":"POST","url":"/api/v1/staff/session","host":"127.0.0.1:36299","remoteAddress":"127.0.0.1","remotePort":34810},"msg":"incoming request"} +{"level":30,"time":1790408018146,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J70HW4EQGVGGWZBSN09","res":{"statusCode":401},"err":{"type":"UnauthorizedError","message":"Требуется действующий ключ доступа.","stack":"UnauthorizedError: Требуется действующий ключ доступа.\n at Object.unauthorized (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:25:12)\n at resolveToken (/workspace/krona-staff/src/portal.ts:1337:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:253:23)","status":401,"statusCode":401,"expose":true},"msg":"Требуется действующий ключ доступа."} +{"level":30,"time":1790408018146,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J70HW4EQGVGGWZBSN09","res":{"statusCode":401},"responseTime":1.648689000000104,"msg":"request completed"} +{"level":30,"time":1790408018147,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J73XM8Q0YNRJ914G8W1","req":{"method":"POST","url":"/api/v1/staff/session","host":"127.0.0.1:36299","remoteAddress":"127.0.0.1","remotePort":34822},"msg":"incoming request"} +{"level":30,"time":1790408018148,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J73XM8Q0YNRJ914G8W1","res":{"statusCode":401},"err":{"type":"UnauthorizedError","message":"Требуется действующий ключ доступа.","stack":"UnauthorizedError: Требуется действующий ключ доступа.\n at Object.unauthorized (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:25:12)\n at resolveToken (/workspace/krona-staff/src/portal.ts:1337:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:253:23)","status":401,"statusCode":401,"expose":true},"msg":"Требуется действующий ключ доступа."} +{"level":30,"time":1790408018148,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J73XM8Q0YNRJ914G8W1","res":{"statusCode":401},"responseTime":0.967511000000286,"msg":"request completed"} +{"level":30,"time":1790408018149,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J74SQB99XZJCVDXJNMT","req":{"method":"POST","url":"/api/v1/staff/session","host":"127.0.0.1:36299","remoteAddress":"127.0.0.1","remotePort":34810},"msg":"incoming request"} +{"level":30,"time":1790408018149,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J74SQB99XZJCVDXJNMT","res":{"statusCode":401},"err":{"type":"UnauthorizedError","message":"Требуется действующий ключ доступа.","stack":"UnauthorizedError: Требуется действующий ключ доступа.\n at Object.unauthorized (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:25:12)\n at resolveToken (/workspace/krona-staff/src/portal.ts:1337:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:253:23)","status":401,"statusCode":401,"expose":true},"msg":"Требуется действующий ключ доступа."} +{"level":30,"time":1790408018149,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J74SQB99XZJCVDXJNMT","res":{"statusCode":401},"responseTime":0.8698090000002594,"msg":"request completed"} +{"level":30,"time":1790408018150,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J76XMMPD5PD7AKCYR2N","req":{"method":"POST","url":"/api/v1/staff/session","host":"127.0.0.1:36299","remoteAddress":"127.0.0.1","remotePort":34822},"msg":"incoming request"} +{"level":30,"time":1790408018151,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J76XMMPD5PD7AKCYR2N","res":{"statusCode":401},"err":{"type":"UnauthorizedError","message":"Требуется действующий ключ доступа.","stack":"UnauthorizedError: Требуется действующий ключ доступа.\n at Object.unauthorized (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:25:12)\n at resolveToken (/workspace/krona-staff/src/portal.ts:1337:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:253:23)","status":401,"statusCode":401,"expose":true},"msg":"Требуется действующий ключ доступа."} +{"level":30,"time":1790408018151,"pid":1688859,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J76XMMPD5PD7AKCYR2N","res":{"statusCode":401},"responseTime":1.0111910000000535,"msg":"request completed"} diff --git a/tests/e2e/evidence/server-secured.txt b/tests/e2e/evidence/server-secured.txt new file mode 100644 index 0000000..88cfa2e --- /dev/null +++ b/tests/e2e/evidence/server-secured.txt @@ -0,0 +1,279 @@ +{"level":30,"time":1790408013912,"pid":1688811,"hostname":"grok-bot-vm-420973429","msg":"Server listening at http://127.0.0.1:35389"} +{"level":30,"time":1790408013941,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4E3M5MJKAGV50FFXN9SZ","req":{"method":"GET","url":"/api/v1/staff/ready","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41352},"msg":"incoming request"} +{"level":30,"time":1790408013957,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4E3M5MJKAGV50FFXN9SZ","res":{"statusCode":200},"responseTime":16.484744000000035,"msg":"request completed"} +{"level":30,"time":1790408015166,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4F9X4201XC0AAD6DNBP5","req":{"method":"POST","url":"/api/v1/staff/employees","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41366},"msg":"incoming request"} +{"level":50,"time":1790408015172,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4F9X4201XC0AAD6DNBP5","req":{"method":"POST","url":"/api/v1/staff/employees","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41366},"res":{"statusCode":500},"err":{"type":"DatabaseError","message":"inconsistent types deduced for parameter $2","stack":"error: inconsistent types deduced for parameter $2\n at /workspace/krona-staff/node_modules/pg/lib/client.js:694:17\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async (/workspace/krona-staff/src/portal.ts:465:25)\n at async Database.tenantTransaction (/workspace/krona-staff/src/infrastructure/database.ts:30:22)\n at async Object. (/workspace/krona-staff/src/portal.ts:461:24)","length":155,"name":"error","severity":"ERROR","code":"42P08","detail":"text versus character varying","position":"150","file":"parse_param.c","line":"219","routine":"variable_coerce_param_hook"},"msg":"inconsistent types deduced for parameter $2"} +{"level":30,"time":1790408015177,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4F9X4201XC0AAD6DNBP5","res":{"statusCode":500},"responseTime":11.21852100000001,"msg":"request completed"} +{"level":30,"time":1790408015188,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FAMNJX2833KF1T4TTXN","req":{"method":"POST","url":"/api/v1/staff/imports/owner-workbook","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41370},"msg":"incoming request"} +{"level":30,"time":1790408015205,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FAMNJX2833KF1T4TTXN","res":{"statusCode":202},"responseTime":17.02252499999986,"msg":"request completed"} +{"level":30,"time":1790408015223,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FBQJSK6DGCRM59J8R5P","req":{"method":"POST","url":"/api/v1/staff/imports/owner-workbook","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41366},"msg":"incoming request"} +{"level":30,"time":1790408015232,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FBQJSK6DGCRM59J8R5P","res":{"statusCode":202},"responseTime":9.666789000000108,"msg":"request completed"} +{"level":30,"time":1790408015242,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FCAV488NV3PYX6F3FJA","req":{"method":"GET","url":"/api/v1/staff/pay-rules","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41366},"msg":"incoming request"} +{"level":30,"time":1790408015247,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FCAV488NV3PYX6F3FJA","res":{"statusCode":200},"responseTime":4.858270000000175,"msg":"request completed"} +{"level":30,"time":1790408015249,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FCGJF6Z76CTR188VGCN","req":{"method":"PUT","url":"/api/v1/staff/employees/01M3EA4FBZ4PJA3W2WDRQSRQSA/pay-assignment","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41370},"msg":"incoming request"} +{"level":30,"time":1790408015257,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FCGJF6Z76CTR188VGCN","res":{"statusCode":200},"responseTime":8.3228059999999,"msg":"request completed"} +{"level":30,"time":1790408015259,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FCVQ0FHFZTP5RX5VGFS","req":{"method":"POST","url":"/api/v1/staff/attendance/events","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41366},"msg":"incoming request"} +{"level":30,"time":1790408015262,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FCVQ0FHFZTP5RX5VGFS","res":{"statusCode":201},"responseTime":3.2303699999999935,"msg":"request completed"} +{"level":30,"time":1790408015264,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FCZJ2ZQZ454GQVQ000V","req":{"method":"POST","url":"/api/v1/staff/attendance/events","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41370},"msg":"incoming request"} +{"level":30,"time":1790408015272,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FCZJ2ZQZ454GQVQ000V","res":{"statusCode":201},"responseTime":8.185108000000128,"msg":"request completed"} +{"level":30,"time":1790408015273,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FD9GB296ZS3YK71ZE6D","req":{"method":"POST","url":"/api/v1/staff/work-sessions/reconcile","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41366},"msg":"incoming request"} +{"level":30,"time":1790408015279,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FD9GB296ZS3YK71ZE6D","res":{"statusCode":200},"responseTime":6.122667999999976,"msg":"request completed"} +{"level":30,"time":1790408015289,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FDSCE1FXX9KMABVM5TM","req":{"method":"PATCH","url":"/api/v1/staff/work-sessions/01M3EA4FDDGG7NT2PNT26E1QKB","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41366},"msg":"incoming request"} +{"level":50,"time":1790408015293,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FDSCE1FXX9KMABVM5TM","req":{"method":"PATCH","url":"/api/v1/staff/work-sessions/01M3EA4FDDGG7NT2PNT26E1QKB","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41366},"res":{"statusCode":500},"err":{"type":"DatabaseError","message":"null value in column \"occurred_at\" of relation \"staff_outbox\" violates not-null constraint","stack":"error: null value in column \"occurred_at\" of relation \"staff_outbox\" violates not-null constraint\n at /workspace/krona-staff/node_modules/pg/lib/client.js:694:17\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async (/workspace/krona-staff/src/portal.ts:1145:13)\n at async Database.tenantTransaction (/workspace/krona-staff/src/infrastructure/database.ts:30:22)\n at async Object. (/workspace/krona-staff/src/portal.ts:1053:23)","length":188,"name":"error","severity":"ERROR","code":"23502","schema":"public","table":"staff_outbox","column":"occurred_at","file":"execMain.c","line":"2022","routine":"ExecConstraints"},"msg":"null value in column \"occurred_at\" of relation \"staff_outbox\" violates not-null constraint"} +{"level":30,"time":1790408015294,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FDSCE1FXX9KMABVM5TM","res":{"statusCode":500},"responseTime":4.745336999999836,"msg":"request completed"} +{"level":30,"time":1790408015297,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FE18FJJN9394Y3N6BJ5","req":{"method":"POST","url":"/api/v1/staff/imports/owner-workbook","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41370},"msg":"incoming request"} +{"level":30,"time":1790408015304,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FE18FJJN9394Y3N6BJ5","res":{"statusCode":202},"responseTime":6.942637999999988,"msg":"request completed"} +{"level":30,"time":1790408015313,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FEH4RF0G7FDCFWZYRG2","req":{"method":"POST","url":"/api/v1/staff/imports/owner-workbook","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41366},"msg":"incoming request"} +{"level":30,"time":1790408015320,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FEH4RF0G7FDCFWZYRG2","res":{"statusCode":202},"responseTime":6.775562000000036,"msg":"request completed"} +{"level":30,"time":1790408015329,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FF1VZ350VV5QWXTG0CR","req":{"method":"GET","url":"/api/v1/staff/pay-rules","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41366},"msg":"incoming request"} +{"level":30,"time":1790408015333,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FF1VZ350VV5QWXTG0CR","res":{"statusCode":200},"responseTime":3.717247000000043,"msg":"request completed"} +{"level":30,"time":1790408015334,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FF6VREYSW25ACQZKRG3","req":{"method":"PUT","url":"/api/v1/staff/employees/01M3EA4FEQWG7KW934X22C56ZR/pay-assignment","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41370},"msg":"incoming request"} +{"level":30,"time":1790408015340,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FF6VREYSW25ACQZKRG3","res":{"statusCode":200},"responseTime":6.012408999999934,"msg":"request completed"} +{"level":30,"time":1790408015341,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FFDF0DKJ2W7ZPPDR4DV","req":{"method":"POST","url":"/api/v1/staff/attendance/events","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41366},"msg":"incoming request"} +{"level":30,"time":1790408015344,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FFDF0DKJ2W7ZPPDR4DV","res":{"statusCode":201},"responseTime":2.4532470000001467,"msg":"request completed"} +{"level":30,"time":1790408015345,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FFHKWR6VMNF2WQKGBWZ","req":{"method":"POST","url":"/api/v1/staff/attendance/events","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41370},"msg":"incoming request"} +{"level":30,"time":1790408015346,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FFHKWR6VMNF2WQKGBWZ","res":{"statusCode":201},"responseTime":1.5671030000000883,"msg":"request completed"} +{"level":30,"time":1790408015347,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FFKMGVXC8YMD6PFV6W2","req":{"method":"POST","url":"/api/v1/staff/work-sessions/reconcile","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41366},"msg":"incoming request"} +{"level":30,"time":1790408015350,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FFKMGVXC8YMD6PFV6W2","res":{"statusCode":200},"responseTime":3.180074999999988,"msg":"request completed"} +{"level":30,"time":1790408015358,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FFYESE8NJFN70MAFRPV","req":{"method":"PATCH","url":"/api/v1/staff/work-sessions/01M3EA4FFN6TXZWFAV7AD8W931","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41366},"msg":"incoming request"} +{"level":50,"time":1790408015361,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FFYESE8NJFN70MAFRPV","req":{"method":"PATCH","url":"/api/v1/staff/work-sessions/01M3EA4FFN6TXZWFAV7AD8W931","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41366},"res":{"statusCode":500},"err":{"type":"DatabaseError","message":"null value in column \"occurred_at\" of relation \"staff_outbox\" violates not-null constraint","stack":"error: null value in column \"occurred_at\" of relation \"staff_outbox\" violates not-null constraint\n at /workspace/krona-staff/node_modules/pg/lib/client.js:694:17\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async (/workspace/krona-staff/src/portal.ts:1145:13)\n at async Database.tenantTransaction (/workspace/krona-staff/src/infrastructure/database.ts:30:22)\n at async Object. (/workspace/krona-staff/src/portal.ts:1053:23)","length":188,"name":"error","severity":"ERROR","code":"23502","schema":"public","table":"staff_outbox","column":"occurred_at","file":"execMain.c","line":"2022","routine":"ExecConstraints"},"msg":"null value in column \"occurred_at\" of relation \"staff_outbox\" violates not-null constraint"} +{"level":30,"time":1790408015361,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FFYESE8NJFN70MAFRPV","res":{"statusCode":500},"responseTime":2.768146999999999,"msg":"request completed"} +{"level":30,"time":1790408015363,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FG37GZKF5QXE421K1NS","req":{"method":"POST","url":"/api/v1/staff/imports/owner-workbook","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41370},"msg":"incoming request"} +{"level":30,"time":1790408015374,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FG37GZKF5QXE421K1NS","res":{"statusCode":202},"responseTime":10.611540999999988,"msg":"request completed"} +{"level":30,"time":1790408015383,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FGQ28S5QBWAQDRD3ENC","req":{"method":"POST","url":"/api/v1/staff/employees/01M3EA4FGC5Y20677SW81GPFB2/access-token","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41366},"msg":"incoming request"} +{"level":30,"time":1790408015387,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FGQ28S5QBWAQDRD3ENC","res":{"statusCode":200},"responseTime":4.416566000000103,"msg":"request completed"} +{"level":30,"time":1790408015392,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FH06VNHJY4EBW5EE2XX","req":{"method":"POST","url":"/api/v1/staff/push/subscriptions","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41370},"msg":"incoming request"} +{"level":30,"time":1790408015397,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FH06VNHJY4EBW5EE2XX","res":{"statusCode":201},"responseTime":4.635773999999856,"msg":"request completed"} +{"level":30,"time":1790408015398,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FH57Y74WHQVGP02939Q","req":{"method":"POST","url":"/api/v1/staff/attendance/events","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41366},"msg":"incoming request"} +{"level":30,"time":1790408015401,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4FH57Y74WHQVGP02939Q","res":{"statusCode":201},"responseTime":2.8056480000000192,"msg":"request completed"} +{"level":30,"time":1790408017908,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4HZMM5H00GW47QM8H57P","req":{"method":"POST","url":"/api/v1/staff/imports/owner-workbook","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41366},"msg":"incoming request"} +{"level":30,"time":1790408017915,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4HZMM5H00GW47QM8H57P","res":{"statusCode":202},"responseTime":6.821124000000054,"msg":"request completed"} +{"level":30,"time":1790408017927,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J070MWKRVC3R9SEXHZZ","req":{"method":"POST","url":"/api/v1/staff/employees/01M3EA4HZSY982GYTPDAVP0Z0Q/access-token","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41366},"msg":"incoming request"} +{"level":30,"time":1790408017932,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J070MWKRVC3R9SEXHZZ","res":{"statusCode":200},"responseTime":4.815638999999464,"msg":"request completed"} +{"level":30,"time":1790408017933,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J0D6X5ZRVMAHE2KHFP0","req":{"method":"POST","url":"/api/v1/staff/employees/01M3EA4HZTSZ12MKP3SV134FKS/access-token","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41370},"msg":"incoming request"} +{"level":30,"time":1790408017935,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J0D6X5ZRVMAHE2KHFP0","res":{"statusCode":200},"responseTime":2.3987600000000384,"msg":"request completed"} +{"level":30,"time":1790408017936,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J0GAPK6MYZKS6CEP69P","req":{"method":"POST","url":"/api/v1/staff/push/subscriptions","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41366},"msg":"incoming request"} +{"level":30,"time":1790408017938,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J0GAPK6MYZKS6CEP69P","res":{"statusCode":201},"responseTime":1.9624579999999696,"msg":"request completed"} +{"level":30,"time":1790408017939,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J0K1RMKPTCT5QNAGV7A","req":{"method":"POST","url":"/api/v1/staff/push/subscriptions","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41370},"msg":"incoming request"} +{"level":30,"time":1790408017941,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J0K1RMKPTCT5QNAGV7A","res":{"statusCode":201},"responseTime":2.340323000000353,"msg":"request completed"} +{"level":30,"time":1790408017952,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J10VK1XV0ZMVF812CYW","req":{"method":"POST","url":"/api/v1/staff/imports/owner-workbook","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41366},"msg":"incoming request"} +{"level":30,"time":1790408017958,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J10VK1XV0ZMVF812CYW","res":{"statusCode":202},"responseTime":5.686529999999948,"msg":"request completed"} +{"level":30,"time":1790408017965,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J1DG7KEQN92H5D256PE","req":{"method":"GET","url":"/api/v1/staff/pay-rules","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41366},"msg":"incoming request"} +{"level":30,"time":1790408017970,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J1DG7KEQN92H5D256PE","res":{"statusCode":200},"responseTime":4.494719000000259,"msg":"request completed"} +{"level":30,"time":1790408017971,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J1KMHYPJ01JH6Z2WEQK","req":{"method":"PUT","url":"/api/v1/staff/employees/01M3EA4J151B1H9D5AKAR29AN9/pay-assignment","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41370},"msg":"incoming request"} +{"level":30,"time":1790408017976,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J1KMHYPJ01JH6Z2WEQK","res":{"statusCode":200},"responseTime":5.194629999999961,"msg":"request completed"} +{"level":30,"time":1790408017977,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J1S0SNJZ8H7X0K9F7T1","req":{"method":"PUT","url":"/api/v1/staff/employees/01M3EA4J151B1H9D5AKAR29AN9/pay-assignment","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41366},"msg":"incoming request"} +{"level":30,"time":1790408017981,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J1S0SNJZ8H7X0K9F7T1","res":{"statusCode":200},"responseTime":4.459873999999218,"msg":"request completed"} +{"level":30,"time":1790408017983,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J1ZDTDW66WF28KDYB4W","req":{"method":"GET","url":"/api/v1/staff/professions","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41370},"msg":"incoming request"} +{"level":30,"time":1790408017984,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J1ZDTDW66WF28KDYB4W","res":{"statusCode":200},"responseTime":1.0135330000002796,"msg":"request completed"} +{"level":30,"time":1790408017985,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J208WKMDXHJERS4H6MT","req":{"method":"GET","url":"/api/v1/staff/org-units","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41366},"msg":"incoming request"} +{"level":30,"time":1790408017986,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J208WKMDXHJERS4H6MT","res":{"statusCode":200},"responseTime":1.3112160000000586,"msg":"request completed"} +{"level":30,"time":1790408018007,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J2Q3T2JSPF95TG96N6P","req":{"method":"POST","url":"/api/v1/staff/session","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41366},"msg":"incoming request"} +{"level":30,"time":1790408018008,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J2Q3T2JSPF95TG96N6P","res":{"statusCode":200},"responseTime":0.6348109999998996,"msg":"request completed"} +{"level":30,"time":1790408018009,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J2SK303DG80T5VC5DDC","req":{"method":"DELETE","url":"/api/v1/staff/session","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41370},"msg":"incoming request"} +{"level":30,"time":1790408018009,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J2SK303DG80T5VC5DDC","res":{"statusCode":204},"responseTime":0.33697699999993347,"msg":"request completed"} +{"level":30,"time":1790408018010,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J2S1XNED469T2N44WFY","req":{"method":"GET","url":"/api/v1/staff/portal","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41366},"msg":"incoming request"} +{"level":30,"time":1790408018013,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J2S1XNED469T2N44WFY","res":{"statusCode":200},"responseTime":3.6036009999997987,"msg":"request completed"} +{"level":30,"time":1790408018015,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J2Z7TW54HTHRM9B7PFS","req":{"method":"POST","url":"/api/v1/staff/session","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41370},"msg":"incoming request"} +{"level":30,"time":1790408018016,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J2Z7TW54HTHRM9B7PFS","res":{"statusCode":200},"responseTime":0.40848600000026636,"msg":"request completed"} +{"level":30,"time":1790408018017,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J31AWQFE866QK3R19T8","req":{"method":"POST","url":"/api/v1/staff/professions","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41366},"msg":"incoming request"} +{"level":30,"time":1790408018019,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J31AWQFE866QK3R19T8","res":{"statusCode":201},"responseTime":2.3794800000005125,"msg":"request completed"} +{"level":30,"time":1790408018021,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J35B5NNN9AVW7EH7XVR","req":{"method":"POST","url":"/api/v1/staff/imports/owner-workbook","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41370},"msg":"incoming request"} +{"level":30,"time":1790408018027,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J35B5NNN9AVW7EH7XVR","res":{"statusCode":202},"responseTime":6.364180999999917,"msg":"request completed"} +{"level":30,"time":1790408018037,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J3NFJ32S6B487DGQF3F","req":{"method":"POST","url":"/api/v1/staff/attendance/events","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41366},"msg":"incoming request"} +{"level":30,"time":1790408018040,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J3NFJ32S6B487DGQF3F","res":{"statusCode":201},"responseTime":3.285291999999572,"msg":"request completed"} +{"level":30,"time":1790408018041,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J3S918GM99F9BXZKYHD","req":{"method":"POST","url":"/api/v1/staff/attendance/events","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41370},"msg":"incoming request"} +{"level":30,"time":1790408018051,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J3S918GM99F9BXZKYHD","res":{"statusCode":201},"responseTime":9.325840999999855,"msg":"request completed"} +{"level":30,"time":1790408018052,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J44HBZG5R6A7238SHNC","req":{"method":"POST","url":"/api/v1/staff/imports/owner-workbook","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41366},"msg":"incoming request"} +{"level":30,"time":1790408018059,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J44HBZG5R6A7238SHNC","res":{"statusCode":202},"responseTime":6.6378679999997985,"msg":"request completed"} +{"level":30,"time":1790408018068,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J4MJ6D7YHY7NJP8XW6B","req":{"method":"POST","url":"/api/v1/staff/imports/owner-workbook","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41366},"msg":"incoming request"} +{"level":50,"time":1790408018073,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J4MJ6D7YHY7NJP8XW6B","req":{"method":"POST","url":"/api/v1/staff/imports/owner-workbook","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":41366},"res":{"statusCode":500},"err":{"type":"DatabaseError","message":"new row for relation \"staff_payroll_ledger\" violates check constraint \"staff_payroll_ledger_kind_check\"","stack":"error: new row for relation \"staff_payroll_ledger\" violates check constraint \"staff_payroll_ledger_kind_check\"\n at /workspace/krona-staff/node_modules/pg/lib/client.js:694:17\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async (/workspace/krona-staff/src/operations.ts:1033:13)\n at async Database.tenantTransaction (/workspace/krona-staff/src/infrastructure/database.ts:30:22)\n at async Object. (/workspace/krona-staff/src/operations.ts:813:22)","length":229,"name":"error","severity":"ERROR","code":"23514","schema":"public","table":"staff_payroll_ledger","constraint":"staff_payroll_ledger_kind_check","file":"execMain.c","line":"2074","routine":"ExecConstraints"},"msg":"new row for relation \"staff_payroll_ledger\" violates check constraint \"staff_payroll_ledger_kind_check\""} +{"level":30,"time":1790408018076,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4J4MJ6D7YHY7NJP8XW6B","res":{"statusCode":500},"responseTime":7.259319999999207,"msg":"request completed"} +{"level":30,"time":1790408018281,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JB912NAAC419Y02QPGD","req":{"method":"POST","url":"/api/v1/staff/imports/owner-workbook","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35778},"msg":"incoming request"} +{"level":30,"time":1790408018289,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JB912NAAC419Y02QPGD","res":{"statusCode":202},"responseTime":7.542034999999487,"msg":"request completed"} +{"level":30,"time":1790408018310,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JC6JJ5PE5S4M8MJAPYQ","req":{"method":"POST","url":"/api/v1/staff/imports/owner-workbook","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35778},"msg":"incoming request"} +{"level":30,"time":1790408018323,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JC6JJ5PE5S4M8MJAPYQ","res":{"statusCode":202},"responseTime":12.457030999999915,"msg":"request completed"} +{"level":30,"time":1790408018333,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JCXCHJFD211C4GCEFKB","req":{"method":"GET","url":"/api/v1/staff/pay-rules","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35778},"msg":"incoming request"} +{"level":30,"time":1790408018338,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JCXCHJFD211C4GCEFKB","res":{"statusCode":200},"responseTime":4.526701000000685,"msg":"request completed"} +{"level":30,"time":1790408018340,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JD4NWCFKZRS9ENNQ1RR","req":{"method":"PUT","url":"/api/v1/staff/employees/01M3EA4JCJZDWYMA296ZFPY4DF/pay-assignment","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35782},"msg":"incoming request"} +{"level":30,"time":1790408018346,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JD4NWCFKZRS9ENNQ1RR","res":{"statusCode":200},"responseTime":5.515754999999444,"msg":"request completed"} +{"level":30,"time":1790408018348,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JDC28B95P2KDW019QM5","req":{"method":"POST","url":"/api/v1/staff/attendance/events","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35778},"msg":"incoming request"} +{"level":30,"time":1790408018350,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JDC28B95P2KDW019QM5","res":{"statusCode":201},"responseTime":1.652274000000034,"msg":"request completed"} +{"level":30,"time":1790408018351,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JDFHP41V6MX75HC8BA2","req":{"method":"POST","url":"/api/v1/staff/attendance/events","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35782},"msg":"incoming request"} +{"level":30,"time":1790408018353,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JDFHP41V6MX75HC8BA2","res":{"statusCode":201},"responseTime":1.7120279999999184,"msg":"request completed"} +{"level":30,"time":1790408018354,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JDJP8QC0RWYNJG3BAWE","req":{"method":"POST","url":"/api/v1/staff/work-sessions/reconcile","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35778},"msg":"incoming request"} +{"level":30,"time":1790408018357,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JDJP8QC0RWYNJG3BAWE","res":{"statusCode":200},"responseTime":3.009777999999642,"msg":"request completed"} +{"level":30,"time":1790408018366,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JDY7YVS8NFMK6B159M9","req":{"method":"POST","url":"/api/v1/staff/access-grants","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35778},"msg":"incoming request"} +{"level":30,"time":1790408018367,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JDY7YVS8NFMK6B159M9","msg":"Route POST:/api/v1/staff/access-grants not found"} +{"level":30,"time":1790408018367,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JDY7YVS8NFMK6B159M9","res":{"statusCode":404},"responseTime":0.45273399999950925,"msg":"request completed"} +{"level":30,"time":1790408018373,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JE5C72SJMQT011VRYK0","req":{"method":"POST","url":"/api/v1/staff/imports/owner-workbook","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35782},"msg":"incoming request"} +{"level":30,"time":1790408018380,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JE5C72SJMQT011VRYK0","res":{"statusCode":202},"responseTime":6.309143000000404,"msg":"request completed"} +{"level":30,"time":1790408018391,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JEQ53Q7Q75D8JNWM330","req":{"method":"POST","url":"/api/v1/staff/imports/owner-workbook","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35778},"msg":"incoming request"} +{"level":30,"time":1790408018395,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JEQ53Q7Q75D8JNWM330","res":{"statusCode":202},"responseTime":4.627241999999569,"msg":"request completed"} +{"level":30,"time":1790408018403,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JF35G4F1KTESX0J64QY","req":{"method":"GET","url":"/api/v1/staff/pay-rules","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35778},"msg":"incoming request"} +{"level":30,"time":1790408018406,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JF35G4F1KTESX0J64QY","res":{"statusCode":200},"responseTime":2.5201289999995424,"msg":"request completed"} +{"level":30,"time":1790408018407,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JF75GCM7BPRQ93RQXGY","req":{"method":"PUT","url":"/api/v1/staff/employees/01M3EA4JETWGVJMHFN7Q38N6ZH/pay-assignment","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35782},"msg":"incoming request"} +{"level":30,"time":1790408018410,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JF75GCM7BPRQ93RQXGY","res":{"statusCode":200},"responseTime":3.6298900000001595,"msg":"request completed"} +{"level":30,"time":1790408018412,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JFB7RG1HJWMFPP628P1","req":{"method":"POST","url":"/api/v1/staff/attendance/events","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35778},"msg":"incoming request"} +{"level":30,"time":1790408018413,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JFB7RG1HJWMFPP628P1","res":{"statusCode":201},"responseTime":1.662560000000667,"msg":"request completed"} +{"level":30,"time":1790408018414,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JFEEZ33FSBQR5V8S3XG","req":{"method":"POST","url":"/api/v1/staff/attendance/events","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35782},"msg":"incoming request"} +{"level":30,"time":1790408018422,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JFEEZ33FSBQR5V8S3XG","res":{"statusCode":201},"responseTime":7.868167999999969,"msg":"request completed"} +{"level":30,"time":1790408018423,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JFQ185WPASH3T84B2KY","req":{"method":"POST","url":"/api/v1/staff/work-sessions/reconcile","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35778},"msg":"incoming request"} +{"level":30,"time":1790408018427,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JFQ185WPASH3T84B2KY","res":{"statusCode":200},"responseTime":3.232307000000219,"msg":"request completed"} +{"level":30,"time":1790408018435,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JG3C73K6MDYG5QKZBX4","req":{"method":"POST","url":"/api/v1/staff/access-grants","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35778},"msg":"incoming request"} +{"level":30,"time":1790408018435,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JG3C73K6MDYG5QKZBX4","msg":"Route POST:/api/v1/staff/access-grants not found"} +{"level":30,"time":1790408018435,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JG3C73K6MDYG5QKZBX4","res":{"statusCode":404},"responseTime":0.33230400000047666,"msg":"request completed"} +{"level":30,"time":1790408018437,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JG57J9AN9YWDETCP3FJ","req":{"method":"POST","url":"/api/v1/staff/access-grants","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35782},"msg":"incoming request"} +{"level":30,"time":1790408018437,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JG57J9AN9YWDETCP3FJ","msg":"Route POST:/api/v1/staff/access-grants not found"} +{"level":30,"time":1790408018437,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JG57J9AN9YWDETCP3FJ","res":{"statusCode":404},"responseTime":0.2454699999998411,"msg":"request completed"} +{"level":30,"time":1790408018438,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JG6X163QEGB6N85AM9P","req":{"method":"POST","url":"/api/v1/staff/access-grants","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35778},"msg":"incoming request"} +{"level":30,"time":1790408018439,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JG6X163QEGB6N85AM9P","msg":"Route POST:/api/v1/staff/access-grants not found"} +{"level":30,"time":1790408018439,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JG6X163QEGB6N85AM9P","res":{"statusCode":404},"responseTime":0.2565549999999348,"msg":"request completed"} +{"level":30,"time":1790408018440,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JG8B5RZ5V4K0GB12G8X","req":{"method":"POST","url":"/api/v1/staff/access-grants","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35782},"msg":"incoming request"} +{"level":30,"time":1790408018441,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JG8B5RZ5V4K0GB12G8X","msg":"Route POST:/api/v1/staff/access-grants not found"} +{"level":30,"time":1790408018441,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JG8B5RZ5V4K0GB12G8X","res":{"statusCode":404},"responseTime":0.28928499999983615,"msg":"request completed"} +{"level":30,"time":1790408018442,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JGAE9ZP2T630SJGVMDD","req":{"method":"POST","url":"/api/v1/staff/access-grants","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35778},"msg":"incoming request"} +{"level":30,"time":1790408018442,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JGAE9ZP2T630SJGVMDD","msg":"Route POST:/api/v1/staff/access-grants not found"} +{"level":30,"time":1790408018443,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JGAE9ZP2T630SJGVMDD","res":{"statusCode":404},"responseTime":0.2572410000002492,"msg":"request completed"} +{"level":30,"time":1790408018444,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JGCQ53FE88AQGRDBRZG","req":{"method":"POST","url":"/api/v1/staff/access-grants","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35782},"msg":"incoming request"} +{"level":30,"time":1790408018444,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JGCQ53FE88AQGRDBRZG","msg":"Route POST:/api/v1/staff/access-grants not found"} +{"level":30,"time":1790408018444,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JGCQ53FE88AQGRDBRZG","res":{"statusCode":404},"responseTime":0.2509200000004057,"msg":"request completed"} +{"level":30,"time":1790408018445,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JGDK389KPYPC2PXWXYA","req":{"method":"POST","url":"/api/v1/staff/access-grants","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35778},"msg":"incoming request"} +{"level":30,"time":1790408018446,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JGDK389KPYPC2PXWXYA","msg":"Route POST:/api/v1/staff/access-grants not found"} +{"level":30,"time":1790408018446,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JGDK389KPYPC2PXWXYA","res":{"statusCode":404},"responseTime":0.2959399999999732,"msg":"request completed"} +{"level":30,"time":1790408018448,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JGGYYTDWN5DQXM5JY5P","req":{"method":"POST","url":"/api/v1/staff/access-grants","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35782},"msg":"incoming request"} +{"level":30,"time":1790408018448,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JGGYYTDWN5DQXM5JY5P","msg":"Route POST:/api/v1/staff/access-grants not found"} +{"level":30,"time":1790408018448,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JGGYYTDWN5DQXM5JY5P","res":{"statusCode":404},"responseTime":0.39974900000015623,"msg":"request completed"} +{"level":30,"time":1790408018450,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JGJS6D7CH512HB9HZTM","req":{"method":"POST","url":"/api/v1/staff/imports/owner-workbook","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35778},"msg":"incoming request"} +{"level":30,"time":1790408018455,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JGJS6D7CH512HB9HZTM","res":{"statusCode":202},"responseTime":4.826310999999805,"msg":"request completed"} +{"level":30,"time":1790408018463,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JGZ01CBTK1YMAHJRB18","req":{"method":"GET","url":"/api/v1/staff/terminal/employees/01M3EA4JGPPB7M0G78QQBQBJ1M/enrollment","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35778},"msg":"incoming request"} +{"level":30,"time":1790408018463,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JGZ01CBTK1YMAHJRB18","msg":"Route GET:/api/v1/staff/terminal/employees/01M3EA4JGPPB7M0G78QQBQBJ1M/enrollment not found"} +{"level":30,"time":1790408018463,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JGZ01CBTK1YMAHJRB18","res":{"statusCode":404},"responseTime":0.3378870000005918,"msg":"request completed"} +{"level":30,"time":1790408018465,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JH1A0MMMC9Y5FHG5JR3","req":{"method":"POST","url":"/api/v1/staff/imports/owner-workbook","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35782},"msg":"incoming request"} +{"level":30,"time":1790408018470,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JH1A0MMMC9Y5FHG5JR3","res":{"statusCode":202},"responseTime":5.273951000000125,"msg":"request completed"} +{"level":30,"time":1790408018478,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JHE1Z7JVRT7FTV70AXY","req":{"method":"PUT","url":"/api/v1/staff/employees/01M3EA4JH57XZ361XBC2Z7SA6J/biometric-consent","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35778},"msg":"incoming request"} +{"level":30,"time":1790408018478,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JHE1Z7JVRT7FTV70AXY","msg":"Route PUT:/api/v1/staff/employees/01M3EA4JH57XZ361XBC2Z7SA6J/biometric-consent not found"} +{"level":30,"time":1790408018478,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JHE1Z7JVRT7FTV70AXY","res":{"statusCode":404},"responseTime":0.304058000000623,"msg":"request completed"} +{"level":30,"time":1790408018606,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JNE3G43KVT3QY8K1AEW","req":{"method":"POST","url":"/api/v1/staff/imports/owner-workbook","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35792},"msg":"incoming request"} +{"level":30,"time":1790408018612,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JNE3G43KVT3QY8K1AEW","res":{"statusCode":202},"responseTime":6.345726999999897,"msg":"request completed"} +{"level":30,"time":1790408018632,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JP8Q2M2Y2BDPFWA68K7","req":{"method":"POST","url":"/api/v1/staff/imports/owner-workbook","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35792},"msg":"incoming request"} +{"level":30,"time":1790408018637,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JP8Q2M2Y2BDPFWA68K7","res":{"statusCode":202},"responseTime":4.942963999999847,"msg":"request completed"} +{"level":30,"time":1790408018647,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JPQHAWFX6VEZQRJADJ4","req":{"method":"POST","url":"/api/v1/staff/sync/devices","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35792},"msg":"incoming request"} +{"level":30,"time":1790408018650,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JPQHAWFX6VEZQRJADJ4","res":{"statusCode":201},"responseTime":2.9649260000005597,"msg":"request completed"} +{"level":30,"time":1790408018654,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JPYKMHN8AV2XRK1ZT9C","req":{"method":"POST","url":"/api/v1/staff/sync/push","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35806},"msg":"incoming request"} +{"level":30,"time":1790408018660,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JPYKMHN8AV2XRK1ZT9C","res":{"statusCode":200},"responseTime":5.449781000000257,"msg":"request completed"} +{"level":30,"time":1790408018675,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JQKCR13BT1AW47A8GYY","req":{"method":"POST","url":"/api/v1/staff/imports/owner-workbook","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35792},"msg":"incoming request"} +{"level":30,"time":1790408018681,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JQKCR13BT1AW47A8GYY","res":{"statusCode":202},"responseTime":5.823410999999396,"msg":"request completed"} +{"level":30,"time":1790408018690,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JR2M60V60HT7JY4DVYZ","req":{"method":"POST","url":"/api/v1/staff/sync/devices","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35792},"msg":"incoming request"} +{"level":30,"time":1790408018691,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JR2M60V60HT7JY4DVYZ","res":{"statusCode":201},"responseTime":1.3205479999996896,"msg":"request completed"} +{"level":30,"time":1790408018693,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JR5F9GRXENA9023DH3Q","req":{"method":"POST","url":"/api/v1/staff/sync/push","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35806},"msg":"incoming request"} +{"level":30,"time":1790408018697,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JR5F9GRXENA9023DH3Q","res":{"statusCode":200},"responseTime":3.8750069999996413,"msg":"request completed"} +{"level":30,"time":1790408018707,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JRKGVB9KFM4GW8JCCRS","req":{"method":"POST","url":"/api/v1/staff/imports/owner-workbook","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35792},"msg":"incoming request"} +{"level":30,"time":1790408018712,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JRKGVB9KFM4GW8JCCRS","res":{"statusCode":202},"responseTime":4.9716669999997976,"msg":"request completed"} +{"level":30,"time":1790408018722,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JS290GZAPS7A6Z5YFZZ","req":{"method":"POST","url":"/api/v1/staff/imports/owner-workbook","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35792},"msg":"incoming request"} +{"level":30,"time":1790408018727,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JS290GZAPS7A6Z5YFZZ","res":{"statusCode":202},"responseTime":5.085656000000199,"msg":"request completed"} +{"level":30,"time":1790408018736,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JSG89R09EJQ2CDW87CW","req":{"method":"POST","url":"/api/v1/staff/sync/devices","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35792},"msg":"incoming request"} +{"level":30,"time":1790408018738,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JSG89R09EJQ2CDW87CW","res":{"statusCode":201},"responseTime":1.3734510000003866,"msg":"request completed"} +{"level":30,"time":1790408018739,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JSKMK02GDMP23FZ2DZR","req":{"method":"POST","url":"/api/v1/staff/sync/pull","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35806},"msg":"incoming request"} +{"level":50,"time":1790408018743,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JSKMK02GDMP23FZ2DZR","req":{"method":"POST","url":"/api/v1/staff/sync/pull","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35806},"res":{"statusCode":500},"err":{"type":"DatabaseError","message":"column \"status\" does not exist","stack":"error: column \"status\" does not exist\n at /workspace/krona-staff/node_modules/pg/lib/client.js:694:17\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async (/workspace/krona-staff/src/domain/sync/service.ts:389:24)\n at async Database.tenantTransaction (/workspace/krona-staff/src/infrastructure/database.ts:30:22)\n at async Object. (/workspace/krona-staff/src/sync.ts:306:28)","length":106,"name":"error","severity":"ERROR","code":"42703","position":"24","file":"parse_relation.c","line":"3716","routine":"errorMissingColumn"},"msg":"column \"status\" does not exist"} +{"level":30,"time":1790408018744,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JSKMK02GDMP23FZ2DZR","res":{"statusCode":500},"responseTime":4.648181000000477,"msg":"request completed"} +{"level":30,"time":1790408018747,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JSVD8C9S834XPRJQTD2","req":{"method":"POST","url":"/api/v1/staff/imports/owner-workbook","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35792},"msg":"incoming request"} +{"level":30,"time":1790408018785,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JSVD8C9S834XPRJQTD2","res":{"statusCode":202},"responseTime":37.420500999999604,"msg":"request completed"} +{"level":30,"time":1790408018793,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JV9WNV36C6MKDW979R6","req":{"method":"POST","url":"/api/v1/staff/sync/devices","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35792},"msg":"incoming request"} +{"level":30,"time":1790408018796,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JV9WNV36C6MKDW979R6","res":{"statusCode":201},"responseTime":2.075665000000299,"msg":"request completed"} +{"level":30,"time":1790408018797,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JVDPWZPXAZ8HFFNX7AB","req":{"method":"POST","url":"/api/v1/staff/sync/pull","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35806},"msg":"incoming request"} +{"level":50,"time":1790408018799,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JVDPWZPXAZ8HFFNX7AB","req":{"method":"POST","url":"/api/v1/staff/sync/pull","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35806},"res":{"statusCode":500},"err":{"type":"DatabaseError","message":"column \"status\" does not exist","stack":"error: column \"status\" does not exist\n at /workspace/krona-staff/node_modules/pg/lib/client.js:694:17\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async (/workspace/krona-staff/src/domain/sync/service.ts:389:24)\n at async Database.tenantTransaction (/workspace/krona-staff/src/infrastructure/database.ts:30:22)\n at async Object. (/workspace/krona-staff/src/sync.ts:306:28)","length":106,"name":"error","severity":"ERROR","code":"42703","position":"24","file":"parse_relation.c","line":"3716","routine":"errorMissingColumn"},"msg":"column \"status\" does not exist"} +{"level":30,"time":1790408018799,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JVDPWZPXAZ8HFFNX7AB","res":{"statusCode":500},"responseTime":2.661884999999529,"msg":"request completed"} +{"level":30,"time":1790408018801,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JVHZF6TQCPQ6PWDKPCP","req":{"method":"POST","url":"/api/v1/staff/sync/devices","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35792},"msg":"incoming request"} +{"level":30,"time":1790408018813,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JVHZF6TQCPQ6PWDKPCP","res":{"statusCode":201},"responseTime":12.522825000000012,"msg":"request completed"} +{"level":30,"time":1790408018814,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JVYMVC1M9CPBB2A3R39","req":{"method":"GET","url":"/api/v1/staff/sync/status","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35806},"msg":"incoming request"} +{"level":30,"time":1790408018817,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JVYMVC1M9CPBB2A3R39","res":{"statusCode":200},"responseTime":2.794176000000334,"msg":"request completed"} +{"level":30,"time":1790408018818,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JW2EXB5S1H9YVT9GK45","req":{"method":"POST","url":"/api/v1/staff/imports/owner-workbook","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35792},"msg":"incoming request"} +{"level":30,"time":1790408018823,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JW2EXB5S1H9YVT9GK45","res":{"statusCode":202},"responseTime":4.881444999999985,"msg":"request completed"} +{"level":30,"time":1790408018834,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JWJVPG8V84QAPCEE014","req":{"method":"PATCH","url":"/api/v1/staff/employees/01M3EA4JW60F9X6AEXP33M4MDQ","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35792},"msg":"incoming request"} +{"level":30,"time":1790408018836,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JWJVPG8V84QAPCEE014","res":{"statusCode":200},"responseTime":2.368786999999429,"msg":"request completed"} +{"level":30,"time":1790408018837,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JWNGP1EJHDT3VJRAMN4","req":{"method":"POST","url":"/api/v1/staff/sync/pull","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35806},"msg":"incoming request"} +{"level":30,"time":1790408018840,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JWNGP1EJHDT3VJRAMN4","res":{"statusCode":200},"responseTime":2.5322159999996074,"msg":"request completed"} +{"level":30,"time":1790408018842,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JWTMTYJ05Y0GV6PQS6B","req":{"method":"POST","url":"/api/v1/staff/imports/owner-workbook","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35792},"msg":"incoming request"} +{"level":30,"time":1790408018846,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JWTMTYJ05Y0GV6PQS6B","res":{"statusCode":202},"responseTime":4.6687080000001515,"msg":"request completed"} +{"level":30,"time":1790408018853,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JX5JMS8NPRX3DHT88ZC","req":{"method":"PATCH","url":"/api/v1/staff/employees/01M3EA4JWYGKJW3S3SQW7QMCF1","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35792},"msg":"incoming request"} +{"level":30,"time":1790408018857,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JX5JMS8NPRX3DHT88ZC","res":{"statusCode":200},"responseTime":3.251942999999301,"msg":"request completed"} +{"level":30,"time":1790408018857,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JX9M65W8D65RMHR6D9Y","req":{"method":"POST","url":"/api/v1/staff/sync/devices","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35806},"msg":"incoming request"} +{"level":30,"time":1790408018859,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JX9M65W8D65RMHR6D9Y","res":{"statusCode":201},"responseTime":1.2874750000000859,"msg":"request completed"} +{"level":30,"time":1790408018860,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JXC3004KR4378VKCH5G","req":{"method":"POST","url":"/api/v1/staff/sync/push","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35792},"msg":"incoming request"} +{"level":30,"time":1790408018863,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JXC3004KR4378VKCH5G","res":{"statusCode":200},"responseTime":3.7642430000005334,"msg":"request completed"} +{"level":30,"time":1790408018866,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JXJBJV3807BHBFN5S1J","req":{"method":"POST","url":"/api/v1/staff/imports/owner-workbook","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35806},"msg":"incoming request"} +{"level":30,"time":1790408018871,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JXJBJV3807BHBFN5S1J","res":{"statusCode":202},"responseTime":5.396490000000085,"msg":"request completed"} +{"level":30,"time":1790408018879,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JXZX0ABKYVBY9ZTNTH9","req":{"method":"POST","url":"/api/v1/staff/imports/owner-workbook","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35792},"msg":"incoming request"} +{"level":30,"time":1790408018885,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JXZX0ABKYVBY9ZTNTH9","res":{"statusCode":202},"responseTime":5.91953199999989,"msg":"request completed"} +{"level":30,"time":1790408018893,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JYDQA2MT149ZXET8XDC","req":{"method":"POST","url":"/api/v1/staff/sync/devices","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35792},"msg":"incoming request"} +{"level":30,"time":1790408018895,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JYDQA2MT149ZXET8XDC","res":{"statusCode":201},"responseTime":1.6295439999994414,"msg":"request completed"} +{"level":30,"time":1790408018896,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JYGEHZECWTJNPV5CJVK","req":{"method":"POST","url":"/api/v1/staff/sync/push","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35806},"msg":"incoming request"} +{"level":30,"time":1790408018899,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JYGEHZECWTJNPV5CJVK","res":{"statusCode":200},"responseTime":3.3800209999999424,"msg":"request completed"} +{"level":30,"time":1790408018908,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JYWF1Z6Y8YFD24BMCNK","req":{"method":"POST","url":"/api/v1/staff/imports/owner-workbook","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35792},"msg":"incoming request"} +{"level":30,"time":1790408018913,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JYWF1Z6Y8YFD24BMCNK","res":{"statusCode":202},"responseTime":4.775786000000153,"msg":"request completed"} +{"level":30,"time":1790408018920,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JZ8P6JQC0MCXERDQG8A","req":{"method":"POST","url":"/api/v1/staff/sync/devices","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35792},"msg":"incoming request"} +{"level":30,"time":1790408018922,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JZ8P6JQC0MCXERDQG8A","res":{"statusCode":201},"responseTime":1.5908949999993638,"msg":"request completed"} +{"level":30,"time":1790408018923,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JZBFX4VJZTS4YKEPZRK","req":{"method":"POST","url":"/api/v1/staff/sync/push","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35806},"msg":"incoming request"} +{"level":50,"time":1790408018926,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JZBFX4VJZTS4YKEPZRK","req":{"method":"POST","url":"/api/v1/staff/sync/push","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35806},"res":{"statusCode":500},"err":{"type":"DatabaseError","message":"invalid input syntax for type timestamp with time zone: \"e2e-not-a-timestamp\"","stack":"error: invalid input syntax for type timestamp with time zone: \"e2e-not-a-timestamp\"\n at /workspace/krona-staff/node_modules/pg/lib/client.js:694:17\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async SyncService.executeCommand (/workspace/krona-staff/src/domain/sync/service.ts:755:9)\n at async (/workspace/krona-staff/src/domain/sync/service.ts:701:33)\n at async Database.tenantTransaction (/workspace/krona-staff/src/infrastructure/database.ts:30:22)\n at async Object. (/workspace/krona-staff/src/sync.ts:390:25)","length":180,"name":"error","severity":"ERROR","code":"22007","where":"unnamed portal parameter $6 = '...'","file":"datetime.c","line":"4140","routine":"DateTimeParseError"},"msg":"invalid input syntax for type timestamp with time zone: \"e2e-not-a-timestamp\""} +{"level":30,"time":1790408018927,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JZBFX4VJZTS4YKEPZRK","res":{"statusCode":500},"responseTime":3.56025099999988,"msg":"request completed"} +{"level":30,"time":1790408018929,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JZHQDMJQN1239C4STY6","req":{"method":"POST","url":"/api/v1/staff/session","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35792},"msg":"incoming request"} +{"level":30,"time":1790408018929,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JZHQDMJQN1239C4STY6","res":{"statusCode":200},"responseTime":0.275908999999956,"msg":"request completed"} +{"level":30,"time":1790408018931,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JZKAZRYGPJS1C4JH86J","req":{"method":"POST","url":"/api/v1/staff/sync/devices","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35806},"msg":"incoming request"} +{"level":30,"time":1790408018936,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4JZKAZRYGPJS1C4JH86J","res":{"statusCode":201},"responseTime":5.502994999999828,"msg":"request completed"} +{"level":30,"time":1790408018944,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K00QZ7RA4HCX365PH9C","req":{"method":"POST","url":"/api/v1/staff/imports/owner-workbook","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35792},"msg":"incoming request"} +{"level":30,"time":1790408018952,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K00QZ7RA4HCX365PH9C","res":{"statusCode":202},"responseTime":7.422302000000855,"msg":"request completed"} +{"level":30,"time":1790408018960,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K0GZZ935P4K7N775AKH","req":{"method":"POST","url":"/api/v1/staff/sync/devices","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35792},"msg":"incoming request"} +{"level":30,"time":1790408018961,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K0GZZ935P4K7N775AKH","res":{"statusCode":201},"responseTime":1.3733540000002904,"msg":"request completed"} +{"level":30,"time":1790408018962,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K0J9ZACFMJQKXWB42BF","req":{"method":"POST","url":"/api/v1/staff/sync/push","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35806},"msg":"incoming request"} +{"level":30,"time":1790408018966,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K0J9ZACFMJQKXWB42BF","res":{"statusCode":200},"responseTime":4.033708999999362,"msg":"request completed"} +{"level":30,"time":1790408018968,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K0R231R31H7Y82XKEFW","req":{"method":"POST","url":"/api/v1/staff/sync/devices","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35792},"msg":"incoming request"} +{"level":30,"time":1790408018969,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K0R231R31H7Y82XKEFW","res":{"statusCode":201},"responseTime":1.091668000000027,"msg":"request completed"} +{"level":30,"time":1790408018971,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K0VXYZRT371QPNE7KZA","req":{"method":"POST","url":"/api/v1/staff/sync/ack","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35806},"msg":"incoming request"} +{"level":30,"time":1790408018973,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K0VXYZRT371QPNE7KZA","res":{"statusCode":200},"responseTime":2.2560160000002725,"msg":"request completed"} +{"level":30,"time":1790408018975,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K0ZTN3QWGTMYH903DYA","req":{"method":"POST","url":"/api/v1/staff/sync/devices","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35792},"msg":"incoming request"} +{"level":30,"time":1790408018976,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K0ZTN3QWGTMYH903DYA","res":{"statusCode":201},"responseTime":1.3257619999994859,"msg":"request completed"} +{"level":30,"time":1790408018977,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K111C5QFY8DC05HAMNK","req":{"method":"POST","url":"/api/v1/staff/sync/devices/01M3EA4K0ZYSXA5WW5PZG2TNS5/revoke","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35806},"msg":"incoming request"} +{"level":30,"time":1790408018980,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K111C5QFY8DC05HAMNK","res":{"statusCode":200},"responseTime":2.1610540000001492,"msg":"request completed"} +{"level":30,"time":1790408018981,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K15V20PHSJGB9EQP4WN","req":{"method":"GET","url":"/api/v1/staff/sync/status","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35792},"msg":"incoming request"} +{"level":30,"time":1790408018982,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K15V20PHSJGB9EQP4WN","res":{"statusCode":403},"err":{"type":"ForbiddenError","message":"Устройство отозвано","stack":"ForbiddenError: Устройство отозвано\n at Object.forbidden (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:33:12)\n at handleSyncError (/workspace/krona-staff/src/sync.ts:443:39)\n at Object. (/workspace/krona-staff/src/sync.ts:249:9)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)","status":403,"statusCode":403,"expose":true},"msg":"Устройство отозвано"} +{"level":30,"time":1790408018982,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K15V20PHSJGB9EQP4WN","res":{"statusCode":403},"responseTime":1.4805010000000038,"msg":"request completed"} +{"level":30,"time":1790408019100,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K4VD2Y9VX05D0YVHRPQ","req":{"method":"GET","url":"/api/v1/staff/live","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35820},"msg":"incoming request"} +{"level":30,"time":1790408019100,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K4VD2Y9VX05D0YVHRPQ","res":{"statusCode":200},"responseTime":0.3551319999996849,"msg":"request completed"} +{"level":30,"time":1790408019106,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K52MQKWRNJHJ052QT1C","req":{"method":"GET","url":"/api/v1/staff/ready","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35824},"msg":"incoming request"} +{"level":30,"time":1790408019113,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K52MQKWRNJHJ052QT1C","res":{"statusCode":200},"responseTime":7.321270999999797,"msg":"request completed"} +{"level":30,"time":1790408019144,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K68VG1ZD7J17S2G4TZV","req":{"method":"GET","url":"/api/v1/staff/portal","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35820},"msg":"incoming request"} +{"level":30,"time":1790408019145,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K68VG1ZD7J17S2G4TZV","res":{"statusCode":401},"err":{"type":"UnauthorizedError","message":"Требуется действующий ключ доступа.","stack":"UnauthorizedError: Требуется действующий ключ доступа.\n at Object.unauthorized (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:25:12)\n at resolveToken (/workspace/krona-staff/src/portal.ts:1337:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:280:21)","status":401,"statusCode":401,"expose":true},"msg":"Требуется действующий ключ доступа."} +{"level":30,"time":1790408019145,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K68VG1ZD7J17S2G4TZV","res":{"statusCode":401},"responseTime":0.6766259999994872,"msg":"request completed"} +{"level":30,"time":1790408019147,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K6BA91KQ3B0K2DV1R8Z","req":{"method":"GET","url":"/api/v1/staff/portal","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35824},"msg":"incoming request"} +{"level":30,"time":1790408019149,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K6BA91KQ3B0K2DV1R8Z","res":{"statusCode":401},"err":{"type":"UnauthorizedError","message":"Требуется действующий ключ доступа.","stack":"UnauthorizedError: Требуется действующий ключ доступа.\n at Object.unauthorized (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:25:12)\n at resolveToken (/workspace/krona-staff/src/portal.ts:1337:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:280:21)","status":401,"statusCode":401,"expose":true},"msg":"Требуется действующий ключ доступа."} +{"level":30,"time":1790408019149,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K6BA91KQ3B0K2DV1R8Z","res":{"statusCode":401},"responseTime":2.714422000000013,"msg":"request completed"} +{"level":30,"time":1790408019151,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K6FC17V38828NK5AWDH","req":{"method":"GET","url":"/api/v1/staff/portal","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35820},"msg":"incoming request"} +{"level":30,"time":1790408019156,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K6FC17V38828NK5AWDH","res":{"statusCode":200},"responseTime":5.406590999999935,"msg":"request completed"} +{"level":30,"time":1790408019161,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K6SBM3C4B20HGWAFBMZ","req":{"method":"POST","url":"/api/v1/staff/imports/owner-workbook","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35824},"msg":"incoming request"} +{"level":30,"time":1790408019168,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K6SBM3C4B20HGWAFBMZ","res":{"statusCode":202},"responseTime":7.204690999999912,"msg":"request completed"} +{"level":30,"time":1790408019178,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K7AC5R9N6168RDHC6ZK","req":{"method":"POST","url":"/api/v1/staff/attendance/events","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35820},"msg":"incoming request"} +{"level":30,"time":1790408019181,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K7AC5R9N6168RDHC6ZK","res":{"statusCode":201},"responseTime":2.922958000000108,"msg":"request completed"} +{"level":30,"time":1790408019183,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K7FA1GFE2QZ11B20ZRS","req":{"method":"POST","url":"/api/v1/staff/imports/owner-workbook","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35824},"msg":"incoming request"} +{"level":30,"time":1790408019189,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K7FA1GFE2QZ11B20ZRS","res":{"statusCode":202},"responseTime":5.149693999999727,"msg":"request completed"} +{"level":30,"time":1790408019196,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K7WVTQDXRJXTNYDGR89","req":{"method":"POST","url":"/api/v1/staff/employees/01M3EA4K7MJGQJ2T2YKG46NF7B/access-token","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35820},"msg":"incoming request"} +{"level":30,"time":1790408019199,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K7WVTQDXRJXTNYDGR89","res":{"statusCode":200},"responseTime":2.3117400000001,"msg":"request completed"} +{"level":30,"time":1790408019200,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K80FDTYG9ES87Q9ZQ7W","req":{"method":"GET","url":"/api/v1/staff/portal","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35824},"msg":"incoming request"} +{"level":30,"time":1790408019200,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K80FDTYG9ES87Q9ZQ7W","res":{"statusCode":403},"err":{"type":"ForbiddenError","message":"Недостаточно прав для просмотра посещаемости.","stack":"ForbiddenError: Недостаточно прав для просмотра посещаемости.\n at Object.forbidden (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:33:12)\n at _Reply.sensibleForbidden [as forbidden] (/workspace/krona-staff/node_modules/@fastify/sensible/index.js:55:44)\n at Object. (/workspace/krona-staff/src/portal.ts:283:20)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)","status":403,"statusCode":403,"expose":true},"msg":"Недостаточно прав для просмотра посещаемости."} +{"level":30,"time":1790408019201,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K80FDTYG9ES87Q9ZQ7W","res":{"statusCode":403},"responseTime":0.48845000000073924,"msg":"request completed"} +{"level":30,"time":1790408019202,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K810TRXD0SQ27W7YDGR","req":{"method":"POST","url":"/api/v1/staff/employees","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35820},"msg":"incoming request"} +{"level":30,"time":1790408019202,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K810TRXD0SQ27W7YDGR","res":{"statusCode":403},"err":{"type":"ForbiddenError","message":"Недостаточно прав для этой операции.","stack":"ForbiddenError: Недостаточно прав для этой операции.\n at Object.forbidden (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:33:12)\n at requirePermission (/workspace/krona-staff/src/portal.ts:1383:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:454:23)","status":403,"statusCode":403,"expose":true},"msg":"Недостаточно прав для этой операции."} +{"level":30,"time":1790408019202,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K810TRXD0SQ27W7YDGR","res":{"statusCode":403},"responseTime":0.5087550000007468,"msg":"request completed"} +{"level":30,"time":1790408019203,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K8324R3A78MXKWG5GN2","req":{"method":"GET","url":"/api/v1/staff/portal","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35824},"msg":"incoming request"} +{"level":30,"time":1790408019205,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K8324R3A78MXKWG5GN2","res":{"statusCode":200},"responseTime":2.2520119999999224,"msg":"request completed"} +{"level":30,"time":1790408019207,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K87MB5BVVM753W72HHZ","req":{"method":"POST","url":"/api/v1/staff/imports/owner-workbook","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35820},"msg":"incoming request"} +{"level":30,"time":1790408019212,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K87MB5BVVM753W72HHZ","res":{"statusCode":202},"responseTime":5.460973000000195,"msg":"request completed"} +{"level":30,"time":1790408019220,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K8M7PQ0714YSD1M4CQP","req":{"method":"POST","url":"/api/v1/staff/employees/01M3EA4K8BXTNNKH3PQYXZJNBE/access-token","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35820},"msg":"incoming request"} +{"level":30,"time":1790408019222,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K8M7PQ0714YSD1M4CQP","res":{"statusCode":200},"responseTime":1.5780409999997573,"msg":"request completed"} +{"level":30,"time":1790408019222,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K8P75YVNTFTC53C6RE4","req":{"method":"GET","url":"/api/v1/staff/portal","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35824},"msg":"incoming request"} +{"level":30,"time":1790408019225,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K8P75YVNTFTC53C6RE4","res":{"statusCode":200},"responseTime":2.076332000000548,"msg":"request completed"} +{"level":30,"time":1790408019225,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K8S1H145G1H6N733Y63","req":{"method":"PATCH","url":"/api/v1/staff/employees/01M3EA4K8BXTNNKH3PQYXZJNBE","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35820},"msg":"incoming request"} +{"level":30,"time":1790408019227,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K8S1H145G1H6N733Y63","res":{"statusCode":200},"responseTime":1.5953489999992598,"msg":"request completed"} +{"level":30,"time":1790408019228,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K8WFVAZS9JJ3Y48JK1Z","req":{"method":"GET","url":"/api/v1/staff/portal","host":"127.0.0.1:35389","remoteAddress":"127.0.0.1","remotePort":35824},"msg":"incoming request"} +{"level":30,"time":1790408019228,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K8WFVAZS9JJ3Y48JK1Z","res":{"statusCode":401},"err":{"type":"UnauthorizedError","message":"Требуется действующий ключ доступа.","stack":"UnauthorizedError: Требуется действующий ключ доступа.\n at Object.unauthorized (/workspace/krona-staff/node_modules/@fastify/sensible/lib/httpErrors.js:25:12)\n at resolveToken (/workspace/krona-staff/src/portal.ts:1337:37)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async Object. (/workspace/krona-staff/src/portal.ts:280:21)","status":401,"statusCode":401,"expose":true},"msg":"Требуется действующий ключ доступа."} +{"level":30,"time":1790408019229,"pid":1688811,"hostname":"grok-bot-vm-420973429","reqId":"01M3EA4K8WFVAZS9JJ3Y48JK1Z","res":{"statusCode":401},"responseTime":0.9479200000005221,"msg":"request completed"}