chore: восстановление репозитория из снапшота v0.3.1

Прежняя git-история утрачена при переносе проекта на машину владельца
(снапшот без .git). Хэши коммитов в docs/reports/* относятся к утраченной
истории.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
sab.code.lab 2026-08-07 09:34:02 +02:00
commit 1c85091186
184 changed files with 33303 additions and 0 deletions

101
docs/deploy.md Normal file
View file

@ -0,0 +1,101 @@
# Деплой на shared-хостинг (чек-лист, V.2)
Дата: 2026-08-06. Выполняет ВЛАДЕЛЕЦ руками (V.1: агент прод не трогает).
Проходить целиком, частичные варианты запрещены (gotcha-partial-build).
## Артефакты деплоя (ВСЕ, их ТРИ)
1. **Статика сайта**: `apps/web/dist/` → web root хостинга (например,
`public_html/`). Сборка: `npm ci && npm run build` в `apps/web`
(Node 20+, локально) либо взять готовый dist из превью-версии.
2. **API**: содержимое `server/` раскладывается по web root ЧАСТЯМИ
(не целиком!): `server/api/``public_html/api/`,
`server/lib/``public_html/lib/`. Эндпоинты оказываются доступны
как `/api/*.php`. Пути жёсткие: PHP-файлы ищут lib как `../lib/`
(smoke-тест локально поднимает docroot = server/, поэтому на проде
web root = dist + содержимое server/).
3. **Конфиг + БД**: скопировать `server/config.example.php`
`public_html/config.php` (именно в КОРЕНЬ web root — db.php ищет его
как `__DIR__.'/../config.php'` от lib/), выставить `db_path` — путь
ВНЕ web root (например, `/home/<user>/go-learn.sqlite`). Сам файл БД
создастся сам при первом обращении (права на каталог — записываемые
для PHP). Также выставить `base_url` (полный URL сайта — идёт в письма
восстановления пароля) и `mail_from` (отправитель писем).
## Итоговая структура на хостинге
```text
public_html/
├── index.html, learn.html, play.html, … ← из dist (артефакт 1)
├── _astro/, assets/ ← из dist
├── .htaccess ← из dist + блок запрета ниже
├── api/ ← server/api/ (артефакт 2)
│ ├── health.php, register.php, login.php, logout.php, me.php,
│ ├── progress.php, captcha.php
│ └── password-reset/ (request.php, confirm.php)
├── lib/ ← server/lib/
│ └── auth.php, db.php, http.php, ratelimit.php
└── config.php ← созданный вручную (артефакт 3)
```
В корневой `.htaccess` (из dist) дописать блок из server/.htaccess:
```apache
<IfModule mod_authz_core.c>
<FilesMatch "(^config\.php$|\.sqlite(-wal|-shm)?$)">
Require all denied
</FilesMatch>
</IfModule>
```
## Порядок (каждый шаг — отдельное действие)
0. Проверки хостинга: PHP ≥ 8.0, модули pdo_sqlite, sqlite3
(phpinfo в панели или `php -v`/`php -m` по SSH, если есть).
Нет pdo_sqlite — стоп, вопрос хостеру.
1. Залить dist (артефакт 1).
2. Залить server/ (артефакт 2) и создать config.php (артефакт 3).
3. Smoke: открыть `/api/health.php` → ожидается `{"status":"ok"}`.
Не 200/не JSON — смотреть логи PHP в панели, НЕ править код на глазах.
4. Smoke вручную: регистрация на странице /register.html (с капчей)
→ вход → «Синхронизировать прогресс» → статус «Прогресс отправлен».
4.1. Проверка почты (этап 8.1): «Забыли пароль?» на /account.html →
письмо со ссылкой приходит и ссылка ведёт на
/password-reset.html?token=…. Не приходит — смотреть настройки
SPF/DKIM в панели хостинга; до решения восстановление считать
нерабочим (риск в PROJECT_STATE).
5. Проверить, что БД-файл появился по пути из config.php и НЕ доступен
по HTTP (попытка открыть его URL → 403/404).
6. HTTPS — включать ТОЛЬКО панелью хостинга (в .htaccess редиректа нет
намеренно, gotcha-https-redirect-proxy). После включения — повторить
шаги 34 по HTTPS.
## Канонические пути (V.5) — заполнить при первом деплое
- Web root: `____________`
- URL сайта: `____________`
- Путь БД (вне web root): `____________`
- Дата первого деплоя: `____________`
## Откат
Откат = перезаливка предыдущего dist и (при изменении server/) предыдущего
server/. Схема БД этапа 8 аддитивна (init-only), обратной миграции нет;
перед любым изменением схемы в будущем — дамп БД ДО деплоя (V.3).
## Бэкап и restore (V.7, минимум)
- Бэкап = копия файла SQLite (из панели файлового менеджера/SSH) +
config.php. Периодичность — после заметного роста числа пользователей
(ручная, SoT расписания — этот файл).
- Restore: остановить запись (выключить сайт в панели) → вернуть файл БД
на путь из config.php → smoke шаг 34. Проверка restore выполняется на
первом же бэкапе: распаковать копию под другим именем и открыть
`sqlite3 <файл> "SELECT count(*) FROM users;"` (или через панель).
## Чего НЕ делать
- Не класть config.php и БД в web root.
- Не включать HTTPS-редирект в .htaccess (только панель).
- Не править PHP/БД на проде напрямую: правка → локальный smoke.sh →
перезаливка.