netpulse-migrate замість PowerShell-скрипта: у контейнері немає ані psql, ані PowerShell, а тягнути клієнт Postgres в образ заради одного запуску — це половина дистрибутива на порожньому місці. Міграції вшиті через embed і переїхали в server/migrations: embed не бачить нічого за межами кореня свого модуля, а міграції поруч із бінарником, який їх накочує, не можуть розійтися версіями. Накочування під advisory-блокуванням: два інстанси при rolling update інакше застосували б ту саму міграцію двічі. Кожен файл в одній транзакції разом із записом у schema_migrations; виняток — continuous aggregates, які TimescaleDB забороняє в транзакції. Змінена вже застосована міграція зупиняє запуск: у різних інсталяціях інакше опиниться різна схема під одним номером. Перевірено на чистій базі: 23 міграції, 101 таблиця, повторний запуск каже «схема актуальна». Веб віддає сам API через embed: на self-hosted це прибирає з інструкції встановлення цілий компонент. Три політики кешування — назавжди для assets із хешем у імені, ніколи для index.html, коротко для решти. Знайдено живим прогоном: невідомий шлях під /api/ віддавав 200 з index.html, і клієнт падав на розборі HTML як JSON замість чесного 404. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
21 lines
1.4 KiB
SQL
21 lines
1.4 KiB
SQL
-- =====================================================================
|
||
-- NetPulse :: 0019_session_rotation_grace.sql
|
||
-- Ротація refresh-токена перестає ламати сесію при подвійному обміні.
|
||
--
|
||
-- Симптом, з якого почалося: сторінка просила логін після кожного
|
||
-- перезавантаження. React у режимі розробки виконує ефекти двічі, тож
|
||
-- відновлення сесії йшло двома запитами поспіль. Перший обмінював
|
||
-- токен і відкликав старий, другий приносив уже відкликаний — і
|
||
-- отримував «сесії немає».
|
||
--
|
||
-- Це не лише про режим розробки: дві вкладки, відкриті одночасно,
|
||
-- дають рівно ту саму гонку в проді.
|
||
-- =====================================================================
|
||
|
||
-- На що замінили токен. Дозволяє простежити ланцюг: пред'явлений
|
||
-- щойно відкликаний токен веде до свого наступника, а не в нікуди.
|
||
ALTER TABLE core.sessions
|
||
ADD COLUMN replaced_by uuid REFERENCES core.sessions(id) ON DELETE SET NULL;
|
||
|
||
CREATE INDEX sessions_replaced_idx ON core.sessions (replaced_by)
|
||
WHERE replaced_by IS NOT NULL;
|