vasyansk
a27ddc79e8
feat(server): graceful scheduler shutdown, /healthz, healthcheck mode
...
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01BwxdSt4reTm7Dj1oxRvpP3
2026-07-04 15:46:56 +07:00
vasyansk
c265d36bdb
docs: plan for tech-debt cleanup + docker compose
...
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01BwxdSt4reTm7Dj1oxRvpP3
2026-07-04 15:43:00 +07:00
vasyansk
f80d700a83
Merge feature/phase-3: scheduler, notifications (Telegram/Webhook), Prometheus metrics
...
Планировщик периодических проверок (read-only), уведомления по смене статуса
(bot_token шифруется, SSRF-guard с пиннингом IP + CGNAT), Prometheus /metrics.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01BwxdSt4reTm7Dj1oxRvpP3
2026-07-04 15:16:58 +07:00
vasyansk
504c4c081f
fix(phase3): skip templateless domains in scheduler; block CGNAT range in webhook SSRF guard
...
Domains imported without a template (TemplateID == nil) are a valid,
unconfigured state, not a failure — RunOnce now skips them before
calling checkDomain instead of letting LoadDomain's "no template" error
turn into StatusError and a spammy unknown->error notification.
isBlockedIP now also rejects 100.64.0.0/10 (RFC 6598 carrier-grade
NAT), which net.IP.IsPrivate() does not cover, closing an SSRF gap in
the webhook destination guard (both the pre-request check and the
per-dial check use isBlockedIP).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01BwxdSt4reTm7Dj1oxRvpP3
2026-07-04 14:58:09 +07:00
vasyansk
34422420ca
feat(web): расписание, каналы уведомлений, история проверок, drift-badge
2026-07-04 14:40:29 +07:00
vasyansk
45259b9720
feat(web,api): клиент/хуки расписания/каналов/истории + lastCheckStatus в domainResponse
...
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01BwxdSt4reTm7Dj1oxRvpP3
2026-07-04 14:24:02 +07:00
vasyansk
b31f886ae2
feat(server): запуск планировщика, /metrics, graceful shutdown
2026-07-04 14:14:00 +07:00
vasyansk
9475af441e
fix(scheduler): убрать двойной SaveCheckRun (Checker персистит), SetDrift через CountDriftDomains, resolved после error
2026-07-04 14:03:49 +07:00
vasyansk
23e02d6804
feat(scheduler): in-process планировщик проверок + смена статуса + уведомления + метрики
2026-07-04 13:53:06 +07:00
vasyansk
070a32717f
fix(sec): webhook SSRF-guard через Dialer.Control (закрытие DNS-rebinding TOCTOU)
2026-07-04 13:48:22 +07:00
vasyansk
29f448d4b5
fix(sec): санитизация Telegram-ошибок, SSRF-guard Webhook, чистка логов test-канала, go mod tidy, histogram-бакеты
2026-07-04 13:40:29 +07:00
vasyansk
5a2903ca1e
merge 3 wave: worktree-agent-ab476f3616a493a88
2026-07-04 13:32:02 +07:00
vasyansk
d3e83ee81f
merge 3 wave: worktree-agent-abf50211e004f196f
2026-07-04 13:32:02 +07:00
vasyansk
d184b12b29
merge 3 wave: worktree-agent-a23ea3cfa26561e67
2026-07-04 13:32:02 +07:00
vasyansk
7d4bf153d7
feat(api): CRUD расписания/каналов + тест-отправка + история проверок
...
Task 5 Фазы 3: GET/PUT /schedule (дефолт при отсутствии строки, валидация
interval>=60), POST/GET/DELETE /channels (секрет шифруется Cipher, никогда
не возвращается в ответах), POST /channels/{cid}/test через узкий
TestSender-интерфейс (200/502 без утечки секрета), GET /domains/{did}/history
(сначала GetDomain для project-scoping, затем ListCheckRuns — иначе IDOR
через check_runs, который сам по себе не scoped по project).
Добавлены store.GetDomain (обёртка над существующим sqlc-запросом) и
store.ListCheckRuns (новый запрос + sqlc regen) для поддержки истории.
2026-07-04 13:24:50 +07:00
vasyansk
e82fb0b13d
feat(notify): Telegram/Webhook нотификаторы + Dispatcher по каналам проекта
2026-07-04 13:19:21 +07:00
vasyansk
98d8dee413
feat(metrics): Prometheus registry (checks/drift/notifications) + /metrics handler
2026-07-04 13:18:58 +07:00
vasyansk
6fd847a909
feat(store): schedules, notification_channels, domain last_check_status + методы
2026-07-04 13:10:42 +07:00
vasyansk
1cdb32b747
docs: план реализации Фазы 3 (расписание, уведомления, метрики)
...
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-07-04 13:02:44 +07:00
vasyansk
6125af4bab
docs: детализация дизайна Фазы 3 (расписание, уведомления, метрики)
...
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-07-04 12:58:59 +07:00
vasyansk
0c21694ec4
merge: Фаза 2 — авторизация
...
- internal/store: миграция sessions/password + методы users/sessions/projects
- internal/auth: argon2id пароли + session store (sha256 токена)
- internal/api: auth-хендлеры (register/login/logout/me) + cookie, RequireAuth+RequireProjectAccess middleware
- IDOR закрыт: все /projects/{pid}/* под middleware, LoadDomainFull scoped, projectID из контекста
- web: AuthContext + клиент под cookie, Login/Register, protected routes, logout, 401→/login
Финальный ревью: READY TO MERGE, IDOR закрыт end-to-end. Go 105+/15 пакетов, web 58 тестов.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-07-03 21:40:45 +07:00
vasyansk
901eb51e2a
fix(auth): серверная проверка длины пароля, loading-guard и различение ошибок на auth-страницах
2026-07-03 21:33:03 +07:00
vasyansk
5a4d560e70
feat(web): Login/Register страницы, protected routes, logout
...
- ProtectedRoute: loading -> спиннер, !user -> /login, иначе children
- LoginPage/RegisterPage: field+react-hook-form/zod, ошибка через role=alert,
редирект на /domains при успехе/уже авторизован
- main.tsx: AuthProvider + QueryCache/MutationCache onError -> notifyUnauthorized
на UnauthorizedError (сброс сессии из кода вне React-дерева)
- AuthContext: logout и notifyUnauthorized чистят react-query кэш (qc.clear())
- Layout: email пользователя + кнопка Выйти
- App: /login и /register публичные (авторизованный -> /domains), остальное
под ProtectedRoute
Починка page-тестов (Accounts/Domains/Templates/DomainDiff/App): AuthProvider
+ мок api.auth.me, спай-ассерты обновлены под projectId-первым-аргументом
сигнатур api.* (T5).
2026-07-03 21:21:29 +07:00
vasyansk
222d6c0453
fix(web): null-guard в мутациях (no active project), AuthContext различает 401 и ошибки сервера
...
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01BwxdSt4reTm7Dj1oxRvpP3
2026-07-03 21:07:48 +07:00
vasyansk
b5d9e8f7ab
feat(web): AuthContext + клиент под cookie-сессии, projectId из контекста
2026-07-03 21:00:18 +07:00
vasyansk
4533b0ca25
feat(api): RequireAuth+RequireProjectAccess middleware, IDOR-scope check/apply по projectID
2026-07-03 20:47:40 +07:00
vasyansk
35ffe73ae3
fix(auth): wiring Auth/Sessions, нормализация email, GetUserByID для /me, 409 на дубль, timing-guard логина
2026-07-03 20:29:05 +07:00
vasyansk
aa0ef1c6a9
feat(api): auth-хендлеры register/login/logout/me + session cookie
2026-07-03 20:11:00 +07:00
vasyansk
a584cf5c37
fix(auth): VerifyPassword валидирует параметры/версию, не паникует на битом хэше
2026-07-03 19:58:54 +07:00
vasyansk
12b7945efc
feat(auth): argon2id пароли + session store (sha256 токена)
2026-07-03 19:50:11 +07:00
vasyansk
3bd237d562
feat(store): миграция sessions/password + методы users/sessions/projects
...
Фаза 2, Task 1: добавлена таблица sessions и nullable password_hash у
users, sqlc-запросы и *Store-обёртки (CreateUser, GetUserByEmail,
CreateProjectForUser, GetProjectOwned, GetUserProject, CreateSession,
GetSessionUser, DeleteSession, RegisterUser в транзакции), интеграционные
тесты на testcontainers.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01BwxdSt4reTm7Dj1oxRvpP3
2026-07-03 19:44:36 +07:00
vasyansk
bd82fe5509
docs: план реализации Фазы 2 (авторизация)
...
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-07-03 19:37:27 +07:00
vasyansk
fc5d3cdbae
docs: детализация дизайна Фазы 2 (авторизация)
...
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-07-03 19:33:12 +07:00
vasyansk
136708bdf0
merge: Фаза 1C — React SPA
...
- web/: Vite+React+TS+TanStack Query+shadcn/Tailwind, тёмная technical console
- API-клиент+типы+хуки (зеркало Go DTO), DEFAULT_PROJECT_ID
- DiffView+DomainDiffPage (prune-guard по умолчанию выключен)
- DomainsPage (импорт зон, привязка шаблона), AccountsPage (secret+Selectel), TemplatesPage+RecordEditor
- internal/web: embed SPA + SPA-fallback, cmd/server монтирование (API приоритетно)
Финальный ревью: READY TO MERGE. web 32 теста, Go 74/14 пакетов.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-07-03 19:17:45 +07:00
vasyansk
4140847a15
fix(web,server): плейсхолдер dist для воспроизводимой сборки + /api без слэша → API
...
Коммитим internal/web/dist/index.html как минимальный плейсхолдер, чтобы
//go:embed all:dist находил совпадения на чистом клоне без npm/`make web`
(CRITICAL: go build ./... падал с "pattern all:dist: no matching files
found"). .gitignore теперь игнорирует только реальные build-ассеты
(internal/web/dist/* кроме index.html); `make web` перезаписывает
плейсхолдер настоящей сборкой.
Также чинит MEDIUM: голый /api (без хвостового слэша) уходил в
SPA-fallback вместо API-роутера — вынесен isAPIPath() с явной проверкой
path == "/api", покрыт TestIsAPIPath.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01BwxdSt4reTm7Dj1oxRvpP3
2026-07-03 18:24:24 +07:00
vasyansk
bba72cc70f
feat(web,server): embed статики SPA + fallback, монтирование в cmd/server
2026-07-03 18:14:18 +07:00
vasyansk
388bf4aeb6
fix(web): валидация записей шаблона — пустые values не уходят в API, ошибки видимы
2026-07-03 18:10:10 +07:00
vasyansk
99e09d35fb
feat(web): TemplatesPage + RecordEditor — CRUD шаблонов с редактором записей
2026-07-03 18:02:08 +07:00
vasyansk
4e91211a89
feat(web): AccountsPage — CRUD учёток, secret-форма, инструкция Selectel
2026-07-03 17:52:59 +07:00
vasyansk
ef003230fa
fix(web): DomainsPage показывает ошибки привязки шаблона и удаления
2026-07-03 17:49:48 +07:00
vasyansk
0ce15d30a8
feat(web): DomainsPage — список, импорт зон, привязка шаблона
2026-07-03 17:43:49 +07:00
vasyansk
1412da9a31
feat(web): DiffView + DomainDiffPage с prune-guard по умолчанию выключенным
...
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01BwxdSt4reTm7Dj1oxRvpP3
2026-07-03 17:32:20 +07:00
vasyansk
267ffc4ed9
fix(web): Domain.templateId опционален (Go omitempty), String() на error
...
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-07-03 17:19:51 +07:00
vasyansk
6f82036e38
feat(web): типизированный API-клиент, типы DTO, TanStack Query хуки
2026-07-03 17:14:11 +07:00
vasyansk
41242973e1
feat(web): scaffold Vite+React+TS, Tailwind v4, shadcn, router, тёмная console-тема
2026-07-03 17:06:23 +07:00
vasyansk
93cbe538e2
docs: план реализации Фазы 1C (React SPA)
...
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-07-03 16:44:41 +07:00
vasyansk
fe85918407
docs: детализация дизайна Фазы 1C (React SPA)
...
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-07-03 16:40:22 +07:00
vasyansk
b329855c28
merge: Фаза 1B — persistence + REST API
...
- internal/config: env-конфиг (DSN, ENC-ключ, listen)
- internal/crypto: AES-256-GCM шифрование секретов
- internal/store: goose-миграции + seed, sqlc (pgx/v5, uuid override), dto JSONB, Repository, Loader/Recorder (testcontainers)
- internal/provider/registry: резолвинг провайдера
- internal/service: Check/Apply с guard на prune
- internal/api: chi REST — check/apply + CRUD accounts/templates/domains + import + PATCH привязки шаблона
- cmd/server: wiring
Финальный ревью: READY TO MERGE. 72 теста / 13 пакетов.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-07-03 15:33:36 +07:00
vasyansk
ddab6e2162
fix(store,api): идемпотентный import (UNIQUE+ON CONFLICT) + PATCH привязки шаблона к домену
2026-07-03 15:24:08 +07:00
vasyansk
2aca92d070
fix(api): tenant-проверка account/template в CreateDomain (HIGH), атомарный import через транзакцию (MEDIUM)
2026-07-03 15:08:16 +07:00