Commit graph

70 commits

Author SHA1 Message Date
ac8ab3cc02 test(e2e): сценарии K6–K9, S9, A4 и N12-DATE из аудита владельца
Зачем: TASK-GROK-2 §3 — денежные дефекты K6–K9, S9, A4 и дата расчёта
были в AUDIT.md, но не покрыты стендом; без красных сценариев исправления
Codex нечем принимать.

Что (tests/e2e/50-money-and-errors.e2e.ts, всё красное и внесено в
known-defects.json):
- K6/D5: отклонение смены из подписанной ведомости → 409 или сторно.
  Сейчас падает на предусловии: подтверждение смены 500 (K3).
- K7/D2: две записи начисления за один день (две точки) и повторный
  импорт с другой суммой → итог = сумма по книге. Факт: 22200 вместо 33300.
- K8/D1: после подписи меняется ставка, затем проверочный пересчёт
  (предполагаемый контракт C4 GET /payroll/runs/:id/verify). Блокирован K3.
- K9/D3: официант по пресету waiter_upsell: params.shift_rate_minor не
  сохраняется (сам D3, до K3); далее начисление = оплата смены (после K3).
- S9: удаление точки с устройством мигратором → 23502 вместо удаления или
  23503 (публичного API удаления нет — так же, как в live-sync.mjs владельца).
- A4: тела 500 не должны содержать SQLSTATE и текст PostgreSQL.
- N12-DATE: month=2026-13 → 400 (факт 500, 22008); 2026-02-30 уже 400.
Прогон run-e2e: 45 red / 9 green, храповик OK.
2026-09-26 15:24:02 +07:00
0453168d70 test(e2e): двойные ID «владелец/мой» в названиях сценариев и known-defects
Зачем: аудит владельца (docs/audit/2026-09-26/AUDIT.md) стал основным
реестром дефектов; без сопоставления исполнители и приёмка говорят о
разных ID для одной ошибки (TASK-GROK-2 §2).

Что: теги переименованы по таблице владельца ([K3/N2], [K13/SYNC-A],
[S5/SYNC-C], [D6/OWN-01], [K17/OWN-10] и т. д.), ключи known-defects.json —
так же; N9–N12, F7, F10 остаются одиночными, как в таблице. Сверх таблицы,
по тексту AUDIT.md: K1/SYNC-I (анонимный доступ без токенов — это K1 на
/sync), K1/PILOT-1 (подстановки без :? в пилотном compose прямо названы в
K1), K2/PILOT-2 (NODE_ENV=development в пилоте — суть K2). SYNC-C0, SYNC-K,
OWN-03..06/08/09, PILOT-3 ID владельца не имеют. run-e2e принимает «/» в
теге. Прогон: 38 red / 9 green, храповик OK — те же сценарии, новые имена.
2026-09-26 15:21:22 +07:00
27499da191 ci: задача windows, включаемая переменной, когда появится раннер
Зачем: владелец требует проверку запуска стенда на Windows 11, но
Windows-раннера у git.ochenstarik.ru сейчас нет. Задача без подходящего
раннера висела бы в очереди и держала статус прогона «в ожидании»,
поэтому она выключена по умолчанию и включается переменной репозитория
KRONA_WINDOWS_RUNNER=true.

Что: npm ci, тест запуска без .cmd-обёрток (node vitest.mjs, без npx),
а при заданном секрете WINDOWS_E2E_PG_ADMIN_URL — полный run-e2e с
выгрузкой evidence артефактом. actionlint (метки docker, docker-host,
windows) — 0 замечаний. Сама задача ни разу не запускалась — не проверено.
2026-09-26 15:20:47 +07:00
fc20f75b55 test(e2e): evidence прогонов вне git, в CI — артефакт
Зачем: tests/e2e/evidence/ перезаписывается каждым прогоном (логи серверов
с ULID и портами, JSON vitest), поэтому любой запуск стенда менял
отслеживаемые файлы и засорял дифф (приёмка владельца, TASK-GROK-2 п.1).

Что: tests/e2e/evidence/ убран из индекса (git rm --cached) и добавлен в
корневой .gitignore (его же читает prettier, поэтому форматировать
сгенерированные файлы больше не нужно — вызов prettier из run-e2e убран).
В CI задача e2e выгружает папку артефактом e2e-evidence
(actions/upload-artifact, закреплён SHA v4.6.2; Forgejo 9.0.3 поддерживает
v4). Разовые доказательства, которые скрипты не перезаписывают (N5 до/после,
замер N13), перенесены в tests/e2e/report-evidence/ — на них ссылается
REPORT.md.
2026-09-26 15:20:28 +07:00
0aaa2f4d2d test(e2e): запуск vitest/tsx/prettier без .cmd-обёрток (Windows)
Зачем: проект разрабатывается под Windows, а стенд там не стартовал:
spawn('npx') и spawn('node_modules/.bin/tsx') без shell падают с ENOENT,
потому что в Windows это .cmd-файлы (приёмка владельца, TASK-GROK-2 п.1).

Что: scripts/test/node-commands.mjs находит JS-точки входа через
require.resolve (tsx/cli, vitest.mjs, prettier.cjs) и всегда запускает их
текущим node (process.execPath). Сервер запускается одним процессом
`node --import tsx src/server.ts`: CLI tsx порождает дочерний node, и под
Windows kill() родителя оставил бы сервер-сироту на порту. baseEnv()
передаёт дочерним процессам PATH и под win32 системные переменные
(SystemRoot, TEMP и др.), без которых node на Windows не работает с сетью,
но не наследует секреты родителя.

Проверка на Linux: tests/e2e/harness/node-commands.test.ts (входит в
npm test) — команды начинаются с process.execPath, без .cmd/.bin/npx,
файлы существуют; исходники стенда не вызывают npx и node_modules/.bin.
Реальный прогон на Windows 11 — не проверено (нет Windows-раннера).
2026-09-26 15:19:47 +07:00
537b784da3 docs(e2e): REPORT.md (описание PR) и свежие evidence прогона
Зачем: 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 по этому замеру.
2026-09-26 15:18:31 +07:00
045f696425 test(e2e): N13 — нагрузочная проверка гонки первого расчёта зарплаты
Зачем: владелец пометил N13 как «не воспроизведено», а в коде окно гонки
(SELECT ... FOR UPDATE по отсутствующей строке, затем INSERT ... ON CONFLICT
DO NOTHING со своим runId) видно. Нужен повторяемый замер на живом сервере
и реальной PostgreSQL 17, а не рассуждение.

Что: scripts/test/n13-race.mjs — 10/25/50 параллельных первых
POST /payroll/calculate, каждая попытка на новой точке, проверка статусов,
числа run_id, строк в staff_payroll_runs и «фантомных» run_id. Режим as-is
показывает, что сейчас всё упирается в N2 (500). Режим n2-bypass ставит
DEFAULT now() только в одноразовой БД скрипта (продукт и миграции не
меняются), чтобы увидеть саму гонку. Итог: 0 некорректных из 30 попыток;
причина (из кода) — случайная сериализация через upsert
ensureDefaultPayRules. Это записано в NOTES-FOR-EXECUTORS вместе с
рекомендацией явной блокировки и замечанием об утечке текста ошибок БД в 500.
2026-09-26 15:18:31 +07:00
82a2a7ca37 test(e2e): сценарии решений владельца (OWN-01..11) и заметки исполнителям
Зачем: решения владельца (роли точки/бухгалтера/директора, пакет зарплаты
с подписью директора, неизменяемость после подписи, зарплата по точке
фактической смены, согласие на биометрию) должны стать исполняемыми
критериями приёмки до того, как Codex начнёт этап 4, иначе реализацию
будет нечем проверить.

API ещё нет, поэтому тесты написаны против наиболее вероятного контракта
C1 (access-grants), C2 (payroll/batches, submit/sign/return,
notifications), C3 (biometric-consent, terminal enrollment); контракт и
инварианты описаны в tests/e2e/NOTES-FOR-EXECUTORS.md. Сейчас все OWN
красные (404 Route not found) и внесены в known-defects.json.
В NOTES также: найденные сценариями дефекты с указанием файлов,
конфликт NODE_ENV/standalone для pilot, N6, требования к раннеру docker-host.
2026-09-26 15:18:31 +07:00
c73c714611 test(e2e): проверка deploy/pilot/compose.yaml (PILOT-1..3)
Зачем: корневой compose.yaml уже проверяется tests/unit/deployment.test.ts,
а pilot-файл, который реально разворачивается у владельца, — нет. В нём
подстановки вида ${STANDALONE_MANAGER_TOKEN} без :? молча дают пустое
значение, а при пустых токенах standalone выдаёт права анониму (F2);
NODE_ENV=development в pilot отключает production-проверки config.ts.

- PILOT-1: каждая подстановка должна быть ${VAR:?сообщение};
- PILOT-2: ни один сервис не с NODE_ENV=development;
- PILOT-3: у app нет учётных данных мигратора (сейчас зелёный).
Файл в tests/e2e как *.e2e.ts: tests/unit вне разрешённых путей, а
красные пункты (дефекты deploy/, которые правят исполнители) идут через
known-defects.json и не ломают `npm run check`. Сейчас PILOT-1 и PILOT-2
красные: 14 подстановок без :?, app с NODE_ENV=development.
2026-09-26 15:18:31 +07:00
bc9b29dec8 ci: PostgreSQL 17 с ролями как в pilot, roundtrip миграций, e2e, SHA-пины
Зачем: прежний CI запускал миграции и тесты под POSTGRES_USER сервиса
(суперпользователь), не проверял откат миграций, не запускал e2e на
реальной БД, держал плавающие теги actions (F13) и выполнял docker build
в контейнере без Docker daemon.

- verify: bootstrap-админ сервиса только создаёт роли (provision-pg.mjs,
  пароли случайные); миграции up -> откат всех -> up -> up (no-op) ролью
  krona_migrator без SUPERUSER; `npm run check` с DATABASE_TEST_URL
  (app-роль) и DATABASE_TEST_MIGRATION_URL (очистка, см. N5); npm audit.
- format: prettier вынесен в отдельную задачу — он красный по 25 файлам
  (F14) и не должен маскировать статус verify/e2e.
- e2e: реальный сервер + PostgreSQL 17 через scripts/test/run-e2e.mjs.
  Выбран «храповик» known-defects.json, а не отдельная задача с
  continue-on-error: так CI зелёный, только если стенд работает и каждый
  красный сценарий — известный открытый дефект; новый красный сценарий
  (регрессия) или исправленный, но не вычеркнутый дефект делают задачу
  красной. continue-on-error скрыл бы и поломку самого стенда.
- docker-build: отдельная задача на метке `docker-host` только для push,
  после verify; без такого раннера она ждёт в очереди, не блокируя
  остальные.
- actions/checkout v4.4.0 и actions/setup-node v4.4.0 закреплены SHA
  (git ls-remote; одинаковы на github.com и code.forgejo.org).

Проверено: actionlint 1.7.12 (метки docker/docker-host объявлены как
self-hosted) — 0 замечаний; scripts/test/ci-local.sh повторяет шаги
verify/format/e2e на локальной PostgreSQL 17.11 (Forgejo-раннер реально
не запускался — не проверено).
2026-09-26 15:18:31 +07:00
c68370b890 test(e2e): форматировать сгенерированные json/md evidence prettier
Зачем: tests/e2e/evidence не входит в .prettierignore (файл вне разрешённых путей), и минифицированный JSON vitest делал бы npm run format:check красным из-за артефактов, а не из-за кода.
2026-09-26 15:18:31 +07:00
2548bd7bdf test(e2e): сценарии офлайн-синхронизации (/sync/*)
Зачем: бэкенд офлайн-синхронизации (миграция 0011) покрыт только
юнит-тестами без реальной БД. Сценарии на живом сервере показывают, как
терминал реально взаимодействует с сервером, и фиксируют границы
доверия к устройству.

Проверяется правильное поведение: устройство не подтверждает смены и не
утверждает табель сам (SYNC-A/B); начальная загрузка работает (SYNC-C0,
сейчас 500 «column status does not exist» — у staff_org_units нет
status) и не теряет сущности после 100-й (SYNC-C); правки из портала
видны в инкрементальном pull (SYNC-D); отметки уволенных и вне окна
времени отклоняются (SYNC-E/J); точка устройства сохраняется, чужая
отклоняется (SYNC-F); битая команда не роняет пакет (SYNC-G); CSRF и
анонимная регистрация устройств запрещены (SYNC-H/I); ack не принимает
курсор из будущего (SYNC-K). SYNC-L — позитивный контроль отзыва.
2026-09-26 15:18:31 +07:00
397954be0a test(e2e): сценарии дефектов основного API (N1-N4, N9-N12, F2-F4, F7, F10)
Зачем: каждый открытый дефект аудита должен иметь исполняемый сценарий
на реальной БД, который проверяет ПРАВИЛЬНОЕ поведение. Тогда красный
тест = открытый дефект, а исправление видно по смене цвета, без ручной
перепроверки.

- N1 POST /employees -> 201; N2 подтверждение смены, расчёт, утверждение
  и сумма начисления 8 ч x синтетическая ставка; N4 пересекающиеся
  периоды не начисляют смену дважды (сейчас блокирован N2 — это видно в
  сообщении assert как «предусловие, см. N2»);
- N3 SSRF: подписка на https://127.0.0.1:<порт> должна отклоняться, и
  локальный слушатель не должен получить соединение;
- N9, N12, N10, N11, F2 (процесс без токенов), F3, F4 (отдельный процесс),
  F7, F10.
Сотрудники для сценариев, не относящихся к N1, создаются импортом, чтобы
один дефект не маскировал остальные. Все данные синтетические (E2E-*),
ставка 123,45 ₽/ч заведомо не реальная.
2026-09-26 15:18:31 +07:00
646e8d4f22 test(e2e): стенд с реальным сервером и PostgreSQL 17
Зачем: 156 зелёных тестов на fakeDatabase не поймали, что ключевые
сценарии (создание сотрудника, подтверждение смены, расчёт зарплаты)
всегда падают на реальной PostgreSQL. Нужен приёмочный стенд, который
проверяет продукт как чёрный ящик: настоящий процесс сервера, настоящая
БД, роли как в pilot, но с минимальными привилегиями.

- tests/e2e/harness/global-setup.ts: создаёт БД и роли через
  scripts/test/provision-pg.mjs, применяет миграции ролью krona_migrator
  (NOSUPERUSER), поднимает `tsx src/server.ts` под krona_staff_app с
  токенами/VAPID из crypto.randomBytes; три процесса: с токенами, без
  токенов (как корневой compose.yaml) и отдельный для проверки rate limit;
  логи серверов пишутся в tests/e2e/evidence/.
- *.e2e.ts и отдельный vitest.e2e.config.ts: e2e не попадают в `npm test`,
  поэтому `npm run check` не требует БД и не краснеет от известных дефектов.
- [HARNESS]/[CTRL] — позитивные контроли (версия PG >= 17, атрибуты ролей,
  app-роль не видит schema_migrations, RBAC, уволенный теряет доступ):
  если они красные, красные дефектные сценарии ничего не доказывают.
- scripts/test/run-e2e.mjs: «храповик» известных дефектов по
  tests/e2e/known-defects.json (новый красный или исправленный-но-не-
  вычеркнутый ID = exit 1), таблица e2e-table.md и проверка, что в
  evidence нет ничего похожего на секреты стенда.

Логи названы *.txt, т.к. *.log в .gitignore.
2026-09-26 15:18:31 +07:00
4f3e5c621a style(test): prettier для tenant-isolation.test.ts
Зачем: файл уже до правки N5 не проходил prettier --check (часть F14); форматирование вынесено в отдельный коммит, чтобы смысловая правка N5 читалась отдельно от шума.
2026-09-26 15:18:31 +07:00
19a028970d test(integration): очистка tenant-isolation ролью мигратора (N5)
Зачем: afterAll удалял строки соединением роли приложения, а у
krona_staff_app намеренно нет DELETE на staff_employees. На реальной
PostgreSQL 17 тест проходил, но файл падал в afterAll ("permission denied
for table staff_employees", exit 1), поэтому любой CI с DATABASE_TEST_URL
был бы красным не из-за дефекта продукта, а из-за самого теста.
Выдавать app-роли DELETE ради теста нельзя: это ослабило бы модель прав.

Что сделано:
- очистка идёт отдельным соединением роли мигратора
  (DATABASE_TEST_MIGRATION_URL или DATABASE_MIGRATION_URL, который CI уже
  задаёт); так как FORCE RLS действует и на владельца таблиц, в транзакции
  выставляется app.tenant_id; удаляются строки обоих тестовых tenant;
- очистка выполняется и в beforeAll, чтобы остатки прошлого упавшего
  прогона не ломали уникальные ключи (EMP-PUSH-1, DEV-A);
- без URL мигратора тест падает с понятной ошибкой, а не оставляет мусор.

До: tests/e2e/evidence/n5-before.txt (1 passed, suite FAIL, exit=1).
После: tests/e2e/evidence/n5-after.txt (два прогона подряд, exit=0).
2026-09-26 15:18:31 +07:00
5ac248660a test(db): стенд PostgreSQL с мигратором без SUPERUSER
Зачем: аудит показал, что 156 зелёных тестов на fakeDatabase не заметили,
что создание сотрудника, подтверждение смены и расчёт зарплаты всегда
падают на реальной PostgreSQL. Чтобы тесты и CI проверяли реальный SQL,
нужен воспроизводимый стенд с ролями как в pilot, но с минимальными
привилегиями:

- scripts/test/provision-pg.mjs: bootstrap-админ (только как DBA/entrypoint)
  создаёт krona_migrator (NOSUPERUSER NOCREATEDB NOCREATEROLE, владелец БД и
  схемы public) и krona_staff_app (NOSUPERUSER NOBYPASSRLS NOINHERIT); пароли
  crypto.randomBytes, пишутся только в env-файл 0600, в вывод не попадают.
  scripts/create-app-role.mjs здесь не используется, т.к. без SUPERUSER он
  падает (находка N6, продуктовый код не трогаем).
- scripts/test/migrate-roundtrip.mjs: up -> откат всех миграций -> up ->
  повторный up должен быть no-op; ролью мигратора, как требует AGENTS.md.

Проверено на PostgreSQL 17.11: 11 миграций применены, откачены, применены
повторно, третий up пустой.
2026-09-26 15:18:31 +07:00
f5ac179623 docs(audit): add 2026-09-26 audit, acceptance and executor tasks
Some checks are pending
ci / verify (push) Waiting to run
Executors could not see the audit: Grok reported that the owner's
AUDIT.md and evidence never reached it, so its scenarios could not be
mapped to the audit IDs. Keeping the audit, the acceptance report and
the task for each executor in the repository lets Codex, Antigravity
and Grok take work and report through git.

The live-check scripts are stored as .mjs.txt so the project linter,
which type-checks every .mjs file, does not break for everyone; the
maintained version of these checks is Grok's harness in tests/e2e.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 15:13:56 +07:00
Ochenstarik
331e4909c9 feat(portal): rebuild staff operational workspace
Some checks are pending
ci / verify (push) Waiting to run
2026-09-26 14:13:21 +07:00
Ochenstarik
778ba2d15b fix(portal): hide login after successful session
Some checks are pending
ci / verify (push) Waiting to run
2026-09-26 13:50:36 +07:00
Ochenstarik
3595792ef3 merge: offline sync backend with library portal
Some checks are pending
ci / verify (push) Waiting to run
2026-09-26 13:28:50 +07:00
Ochenstarik
5ee75177b9 feat(sync): add offline sync backend foundation
- Add PostgreSQL migrations with strict RLS policies (0011)
- Introduce SyncService for handling auth, token-based registration
- Add payload size and replay attack mitigations
- Provide HTTP fastify routes (pull, push, ack, device management)
- Validate openapi contracts and add comprehensive tests
2026-09-26 13:10:27 +07:00
Ochenstarik
1812870dd3 feat(portal): align workspace with Krona library 2026-09-26 12:58:51 +07:00
Ochenstarik
3e2054480c fix(push): isolate employee data and preserve platform outbox
Some checks are pending
ci / verify (push) Waiting to run
2026-09-26 12:31:10 +07:00
Ochenstarik
2f1bdf549d test(push): tenant isolation and web-push idempotency tests 2026-09-26 12:08:36 +07:00
Ochenstarik
87a6a447c2 feat(pwa): mobile-first employee portal with offline sync and push integration 2026-09-26 12:08:31 +07:00
Ochenstarik
fb1270a0a8 feat(notification): employee push subscriptions, rls migrations, and web-push dispatcher 2026-09-26 12:08:26 +07:00
Ochenstarik
f74aa6d7f5 fix(import): provision workbook profession catalog
Some checks are pending
ci / verify (push) Waiting to run
2026-09-24 21:25:13 +07:00
Ochenstarik
9ea9a004ed feat(ui): align Staff portal with Krona library 2026-09-24 21:14:20 +07:00
Ochenstarik
5b159f785c feat(staff): import workbook professions and dated payroll 2026-09-24 21:14:03 +07:00
Ochenstarik
4fe2f8799a fix(terminal): secure local state and background IPC 2026-09-24 21:13:46 +07:00
Ochenstarik
96a28f575f test(tenant): fix payroll ledger isolation query and verify migration rls 2026-09-24 19:11:45 +07:00
Ochenstarik
37da6f0418 feat(payroll): automatic payroll calculation, owner schemes, and UI integration 2026-09-24 19:00:25 +07:00
Ochenstarik
c08a7e6af1 fix(finance): preserve imported corrections 2026-09-24 18:28:58 +07:00
Ochenstarik
1007f929c2 fix(finance): cast derived revenue parameters 2026-09-24 18:25:56 +07:00
Ochenstarik
88804a0eea feat(staff): add finance calendar and employee portal 2026-09-24 18:12:24 +07:00
Ochenstarik
057ec75b26 fix(terminal): handle locked scans consistently 2026-09-24 18:09:42 +07:00
Ochenstarik
0f530dc633 fix: read terminal release version reliably
Some checks failed
ci / verify (push) Has been cancelled
2026-09-24 17:13:14 +07:00
Ochenstarik
df0da37d5c merge: integrate server portal and work sessions 2026-09-24 17:06:04 +07:00
Ochenstarik
6e5a1ad404 merge: integrate production terminal 2026-09-24 17:06:03 +07:00
Ochenstarik
2f6b367638 feat: reconcile and review attendance sessions 2026-09-24 17:00:08 +07:00
Ochenstarik
29c70e0107 refactor(terminal): decouple scanner via IFingerprintScanner factory and fix test cancellation token 2026-09-24 16:54:41 +07:00
Ochenstarik
39f0840087 Fix IPC framing, add global pipe name, and auto-reconnect tests 2026-09-24 16:49:07 +07:00
Ochenstarik
b3fdec1eb2 test(terminal): add comprehensive unit test suite covering scanner mock, deduplication, sync, and security 2026-09-24 16:37:59 +07:00
Ochenstarik
7ca8966084 docs(terminal): add API requirements, driver distribution policy, and SLK20R hardware report 2026-09-24 16:37:52 +07:00
Ochenstarik
b2f7a68589 feat(installer): update release build script and NSIS installer with Windows Service and driver detection 2026-09-24 16:37:48 +07:00
Ochenstarik
32e3c6f7f7 feat: add manager employee and timesheet workflows 2026-09-24 16:32:30 +07:00
Ochenstarik
71660745a5 feat(terminal): wire attendance tracker, tray states, fingerprint enrollment wizard, and re-authorization 2026-09-24 16:28:20 +07:00
Ochenstarik
fecf7e5911 chore: remove build artifacts from KronaStaffService and update .gitignore 2026-09-24 16:22:50 +07:00
Ochenstarik
0bd88142b8 feat(service): add KronaStaffService Windows Service with IPC and offline sync worker 2026-09-24 16:22:33 +07:00