Commit graph

4 commits

Author SHA1 Message Date
nns c69114f8ab feat(s30): PruneAutoTestEntities + одноразовая зачистка стейджа (шаг 7/9)
HousekeepingJobs.PruneAutoTestEntitiesAsync — Hangfire-recurring (02:45 UTC
daily, Cron:PruneAutoTestEntities). Удаляет:
- orgs по regex autotest-паттерна в имени (quality-, soak-, UI-a11y-,
  SmokeOrgA/B-, PerfBaseline-, Reg-, RT-ratetest-, Probe Org, cat3*,
  visual-, factory-smoke-, mt6*, doc4*, auth2*, rep5*, rt8*, wiz9*,
  i18n*, twofa*, iso*, mob1*, axdet-, load-, s19-test- + любое имя
  с [0-9]{10,}) старше 3 дней + все их таблицы с OrganizationId;
- orphan autotest-юзеров (без удалённой org) по regex в email и доменам
  @e.kz / @test-fm.local.

Защищены: SuperAdmin (OrganizationId IS NULL), admin@food-market.local,
admin@demo-market.local, demo-*@food-market.local, market@email.com,
«Demo Market» и «Демо-магазин» — явные исключения.

deploy/stage-prune-autotest.sql — ровно та же логика как SQL-скрипт для
ручного запуска. Прогнал на stage: было 8653 user'ов / 8634 orgs →
стало 300 users / 305 orgs. SuperAdmin/demo/market остались.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-10-04 15:49:25 +05:00
nns 019c57ae3b feat(s25): autonomous continuous quality monitoring (8/8)
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
Hourly smoke watchdog + auto-fix loop + dashboard + multi-tenant guard
+ perf regression + cleanup job + README badge.

1. ~/quality-watchdog.sh (cron 5 * * * *) — 8 checks (~60s):
   /health/ready, signup→login→/api/me, GET products, Playwright UI
   smoke (3.1 product CRUD), /metrics format, /hubs/notifications
   negotiate with token, multi-tenant isolation, perf p95.
2. Auto-fix loop: 2× consecutive red → ~/.fm-watchdog/incident-*.txt
   + queue/0000-incident-* to bump it ahead of Server-Claude's
   sprint queue. fm-watchdog.sh sees prefix 0000- as next.
3. scripts/quality-dashboard.py — renders docs/quality-status.md
   (current emoji, 8-step table, perf baseline, 7-day history,
   24-run sparkline) + injects README badge 🟢/🟡/🔴.
4. Multi-tenant smoke: signup 2 orgs `quality-{epoch}-A/B`, create
   product in A, verify B sees 404/403 + total=0.
5. Perf regression: p95 over 10 reqs for /api/me, products,
   sales/retail/stats. Baseline = median of last 10 samples
   (robust to noise). >50% from baseline → alert. First 5 runs
   always green (warm-up).
6. HousekeepingJobs.PruneQualityTestOrgsAsync (cron 30 2 * * * UTC):
   finds orgs `quality-%` older than 24h, dynamically scans
   information_schema for tables with OrganizationId, iteratively
   DELETEs with FK-violation retry (up to 10 passes), then cleans
   AspNetUser*/OpenIddict* by email pattern `quality-%@test-fm.local`,
   finally users + organizations.
7. README badge: <!-- quality-badge --> marker updated each run.

Validated: stage deploy ✓, Hangfire job registered ✓, dry-run SQL on
24 stage candidates → 0 remaining ✓, 3 cron-triggered runs all 8/8
green (12:42/12:45/12:48 +05) ✓.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-08 12:50:35 +05:00
nns 346b7bfd48 feat(s20): Mapster + SSO scaffold + maintenance automation (7 пунктов)
Some checks failed
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
Docker Public / Build + push Public (push) Has been cancelled
Docker Public / Deploy Public on stage (push) Has been cancelled
1. TD-3 Mapster — Application/Mapping/MapsterConfig.cs с
   TypeAdapterConfig для Product, Counterparty + collections.
   ProductsController.List/Get/GetInternalAsync + CounterpartiesController.
   List/Get переведены на .ProjectToType<TDto>(MapsterConfig.Config).
   Inline Projection-Expression удалён.

2. SSO scaffold — Microsoft.AspNetCore.Authentication.Google + .MicrosoftAccount
   пакеты, условная регистрация в Program.cs (только если ClientId задан).
   ExternalAuthController с GET /api/auth/external/{provider} (Challenge или
   503 если не настроено), /callback (501 с email — invite-flow TODO),
   /providers (булевый список). docs/sso.md инструкция.

3. Stale-data cleanup — HousekeepingJobs расширен:
   PruneOrgAuditLogAsync (>90д из Cleanup:OrgAuditLogDays),
   PruneDraftsAsync (Supply/RetailSale/Demand старше 30д),
   PruneRevokedRefreshTokensAsync (raw SQL DELETE из OpenIddictTokens).
   3 новых cron'a в HangfireJobsConfigurator (03:00-03:20 UTC).

4. DB VACUUM automation — DatabaseMaintenanceJobs.VacuumTopTablesAsync:
   pg_total_relation_size → топ-5 таблиц → VACUUM (ANALYZE) per table
   с замером времени. Default cron еженедельно вс 04:00 UTC.

5. Disk usage monitoring — DiskMonitoringJob ежечасно: DriveInfo.AvailableFreeSpace
   на пути из Monitoring:DiskPaths (default "/opt,/var/lib/docker").
   <1GB → Telegram-alert на Monitoring:SuperAdminTelegramChatIds.
   Anti-spam cooldown 6h. Gauge food_market_disk_free_bytes{mount}.

6. Performance regression detection — ~/nightly-perf-check.sh после
   nightly-verify. Парсит /metrics, считает db_avg_ms, сравнивает с
   baseline в ~/.fm-watchdog/perf-baseline.json. Δ>30% → Telegram alert
   + baseline НЕ обновляется (sliding window).

7. Public-site analytics placeholder — Astro BaseLayout рендерит
   gtag/Yandex.Metrika только если задан PUBLIC_GA_ID / PUBLIC_YM_ID;
   иначе <script data-id="REPLACE_ME" data-doc="docs/analytics.md">
   маркер. docs/analytics.md с инструкцией подключения.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-07 21:54:12 +05:00
nns a74fa114d8 feat(hangfire): dashboard + scheduled cleanup джобы (P1-16)
Hangfire.PostgreSql storage (тот же ConnectionString:Default). Сервер
стартует только когда Hangfire:Enabled (true по умолчанию) — в
интеграционных тестах выключаем через env Hangfire__Enabled=false,
чтобы тесты не плодили служебные таблицы в одноразовом контейнере.

Dashboard на /hangfire с авторизационным фильтром SuperAdminHangfireFilter —
требует роли SuperAdmin (стандартный OpenIddict-токен валидируется
аутентификационным middleware'ом перед этим).

Recurring jobs (HangfireJobsConfigurator):
• prune-stock-movements — ежедневно 03:30 UTC, удаляет StockMovement
  старше 730 дней (Hangfire:Retention:StockMovementDays). За 30 минут
  до бэкапа, чтобы pg_dump не цеплял временные блокировки.
• prune-audit-log — ежедневно 03:45 UTC, удаляет super_admin_audit_log
  старше 90 дней (Hangfire:Retention:AuditLogDays).

Логика очистки в HousekeepingJobs (scoped, использует AppDbContext с
IgnoreQueryFilters — это межтенантная задача).

Тесты: 1 unit (PruneStockMovements удаляет только старые), 1 интеграционный
(dashboard не отвечает без Hangfire-сервера). Полный прогон:
24 unit + 32 integration = 56 зелёных.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 10:07:14 +05:00