From e8ce6f251e18d7fff2cfad358167ccc7ec4a18db Mon Sep 17 00:00:00 2001 From: Valery Petrov Date: Wed, 3 Jun 2026 18:37:53 +0300 Subject: [PATCH] issues/27: sync prod from k3s-test --- .vitepress/config.mts | 20 +- infrastructure/test-contour/git-flow.md | 5 +- .../test-contour/guides/gitea-ci.md | 14 +- .../test-contour/guides/overview.md | 5 +- infrastructure/test-contour/guides/redmine.md | 198 ++++ infrastructure/test-contour/index.md | 10 + .../k3s-test-reference/_generate.py | 365 +++++++ .../k3s-test-reference/docs-pointers.md | 14 + .../test-contour/k3s-test-reference/index.md | 62 ++ .../k3s-test-reference/root-and-artifacts.md | 23 + .../k3s-test-reference/scripts.md | 57 ++ .../k3s-test-reference/sova-adminpanel.md | 358 +++++++ .../k3s-test-reference/sova-backend.md | 751 +++++++++++++++ .../k3s-test-reference/sova-cabinet.md | 888 ++++++++++++++++++ .../k3s-test-reference/sova-deploy.md | 264 ++++++ .../k3s-test-reference/sova-docs-repo.md | 210 +++++ .../k3s-test-reference/sova-mocks.md | 66 ++ .../k3s-test-reference/sova-platform.md | 36 + .../k3s-test-reference/sova-redmine.md | 21 + .../screenshots/21-redmine-login.png | Bin 0 -> 27226 bytes .../screenshots/22-redmine-home.png | Bin 0 -> 39372 bytes .../test-contour/screenshots/README.md | 4 + .../test-contour/test-contour-article.md | 41 +- 23 files changed, 3393 insertions(+), 19 deletions(-) create mode 100644 infrastructure/test-contour/guides/redmine.md create mode 100644 infrastructure/test-contour/k3s-test-reference/_generate.py create mode 100644 infrastructure/test-contour/k3s-test-reference/docs-pointers.md create mode 100644 infrastructure/test-contour/k3s-test-reference/index.md create mode 100644 infrastructure/test-contour/k3s-test-reference/root-and-artifacts.md create mode 100644 infrastructure/test-contour/k3s-test-reference/scripts.md create mode 100644 infrastructure/test-contour/k3s-test-reference/sova-adminpanel.md create mode 100644 infrastructure/test-contour/k3s-test-reference/sova-backend.md create mode 100644 infrastructure/test-contour/k3s-test-reference/sova-cabinet.md create mode 100644 infrastructure/test-contour/k3s-test-reference/sova-deploy.md create mode 100644 infrastructure/test-contour/k3s-test-reference/sova-docs-repo.md create mode 100644 infrastructure/test-contour/k3s-test-reference/sova-mocks.md create mode 100644 infrastructure/test-contour/k3s-test-reference/sova-platform.md create mode 100644 infrastructure/test-contour/k3s-test-reference/sova-redmine.md create mode 100644 infrastructure/test-contour/screenshots/21-redmine-login.png create mode 100644 infrastructure/test-contour/screenshots/22-redmine-home.png diff --git a/.vitepress/config.mts b/.vitepress/config.mts index eace33d..47f654b 100644 --- a/.vitepress/config.mts +++ b/.vitepress/config.mts @@ -103,10 +103,28 @@ export default defineConfig({ { text: 'Gitea: теги и CI/CD', link: '/infrastructure/test-contour/guides/gitea-ci' }, { text: 'ArgoCD: приложения', link: '/infrastructure/test-contour/guides/argocd' }, { text: 'Grafana / Prometheus / Loki', link: '/infrastructure/test-contour/guides/monitoring' }, + { text: 'Redmine', link: '/infrastructure/test-contour/guides/redmine' }, { text: 'Что сделано + перенос на сервер', link: '/infrastructure/test-contour/test-contour-article' }, { text: 'Git-flow: ветки и релизы', link: '/infrastructure/test-contour/git-flow' }, { text: 'Система тегов CI/CD', link: '/infrastructure/test-contour/tags' }, - { text: 'ArgoCD: sova-root и data-test', link: '/infrastructure/test-contour/argocd-apps' } + { text: 'ArgoCD: sova-root и data-test', link: '/infrastructure/test-contour/argocd-apps' }, + { + text: 'Справочник k3s-test (все файлы)', + collapsed: true, + items: [ + { text: 'Обзор', link: '/infrastructure/test-contour/k3s-test-reference/' }, + { text: 'scripts/', link: '/infrastructure/test-contour/k3s-test-reference/scripts' }, + { text: 'sova-deploy/', link: '/infrastructure/test-contour/k3s-test-reference/sova-deploy' }, + { text: 'sova-platform/', link: '/infrastructure/test-contour/k3s-test-reference/sova-platform' }, + { text: 'sova-mocks/', link: '/infrastructure/test-contour/k3s-test-reference/sova-mocks' }, + { text: 'sova-redmine/', link: '/infrastructure/test-contour/k3s-test-reference/sova-redmine' }, + { text: 'sova-backend/', link: '/infrastructure/test-contour/k3s-test-reference/sova-backend' }, + { text: 'sova-adminpanel/', link: '/infrastructure/test-contour/k3s-test-reference/sova-adminpanel' }, + { text: 'sova-cabinet/', link: '/infrastructure/test-contour/k3s-test-reference/sova-cabinet' }, + { text: 'sova-docs/', link: '/infrastructure/test-contour/k3s-test-reference/sova-docs-repo' }, + { text: 'Корень и артеfacts', link: '/infrastructure/test-contour/k3s-test-reference/root-and-artifacts' } + ] + } ] }, { text: 'Эксплуатация', link: '/operations/maintenance' } diff --git a/infrastructure/test-contour/git-flow.md b/infrastructure/test-contour/git-flow.md index d4de1f3..c0f2c42 100644 --- a/infrastructure/test-contour/git-flow.md +++ b/infrastructure/test-contour/git-flow.md @@ -194,9 +194,8 @@ Hotfix **не** мержится через `test` → `stage` целиком ### Test — **работает сейчас** -| Триггер | Тег `*-test` на ветке `test` (релиз) **или** ручной запуск | -| Тесты вручную | Gitea → **Actions** → **Run workflow** → ветка `prod` / `test` / `stage` | -| Pipeline на тег | test → build-and-push → deploy-gitops | +| Триггер | Тег `*-test` на ветке `test` | +| Pipeline | test → build-and-push → deploy-gitops | | GitOps | `apps/{app}/values-test.yaml` в `sova-deploy` | | ArgoCD | `backend-test`, `cabinet-test`, … | | URLs | `*.test.sova.local`, `docs.sova.local` | diff --git a/infrastructure/test-contour/guides/gitea-ci.md b/infrastructure/test-contour/guides/gitea-ci.md index 018f1bb..cdc092e 100644 --- a/infrastructure/test-contour/guides/gitea-ci.md +++ b/infrastructure/test-contour/guides/gitea-ci.md @@ -22,19 +22,9 @@ ![Организация sova](../screenshots/02-gitea-org-sova.png) -## 3. Gitea Actions — когда запускается pipeline +## 3. Gitea Actions — pipeline на push тега -**Feature-ветки** (`issues/27`, `feature/*`) — **не запускают** CI автоматически. - -| Событие | Что происходит | -|---------|----------------| -| Push в `issues/27` / PR | ничего | -| **Run workflow** вручную (Actions) | только job **test**, ветка `prod` / `test` / `stage` | -| Push **тега** `backend-v*-test` и т.п. | полный pipeline: test → build → deploy-gitops | - -Ручной прогон тестов: **Actions** → workflow **backend-ci-cd** → **Run workflow** → выбрать `test` (или `prod` / `stage`). - -Workflow на push тега: +Workflow в каждом app-репозитории: 1. **test** — unit/build проверки 2. **build-and-push** — образ в Container Registry diff --git a/infrastructure/test-contour/guides/overview.md b/infrastructure/test-contour/guides/overview.md index f749b85..caa5f8b 100644 --- a/infrastructure/test-contour/guides/overview.md +++ b/infrastructure/test-contour/guides/overview.md @@ -1,11 +1,11 @@ # Визуальные гайды test-контура {#overview} -Пошаговые инструкции со **скриншотами** реального UI песочницы: Gitea CI, ArgoCD, Grafana, Prometheus и Loki. +Пошаговые инструкции со **скриншотами** реального UI песочницы: Gitea CI, ArgoCD, Grafana, Prometheus, Loki, **Redmine**. Перед просмотром добавьте в `/etc/hosts` IP VM (см. `./scripts/print-urls.sh`): ``` -192.168.252.2 git.sova.local argocd.sova.local grafana.sova.local prometheus.sova.local docs.sova.local +192.168.252.2 git.sova.local argocd.sova.local grafana.sova.local prometheus.sova.local docs.sova.local redmine.sova.local ``` ## Разделы @@ -15,6 +15,7 @@ | [Gitea: теги и CI/CD](./gitea-ci) | push тега → Actions → registry → deploy-gitops | | [ArgoCD: приложения](./argocd) | Applications, sync, backend vs sova-root vs data-test | | [Grafana, Prometheus, Loki](./monitoring) | метрики, targets, логи в Explore | +| [Redmine](./redmine) | задачи, Git-flow, интеграция с Gitea, скриншоты UI | ## Обновление скриншотов diff --git a/infrastructure/test-contour/guides/redmine.md b/infrastructure/test-contour/guides/redmine.md new file mode 100644 index 0000000..099eb8e --- /dev/null +++ b/infrastructure/test-contour/guides/redmine.md @@ -0,0 +1,198 @@ +# Redmine в test-контуре + +> Внедрено в test-контуре **29–30.05.2026**. Sentry из контура **удалён** (≈10 GiB RAM) — для ошибок приложений используйте [Grafana → Loki](./monitoring.md). + +**Redmine** — issue tracker для задач разработки. В test-контуре он связан с Git-flow: коммиты с `Refs #N` / `Fixes #N` можно привязать к задачам; интеграция с Gitea настраивается вручную (см. ниже). + +## URL и доступы + +| Сервис | URL | Логин | Пароль | +|--------|-----|-------|--------| +| **Redmine** | http://redmine.sova.local | `admin` | `SovaRedmineTest2026!` | +| Gitea | http://git.sova.local | `gitea_admin` | `.generated/platform-credentials.env` | + +Добавить в `/etc/hosts` (IP из `multipass info sova-test` или `./scripts/print-urls.sh`): + +``` +192.168.252.2 redmine.sova.local +``` + +Пароль test-контура также в `sova-deploy/apps/redmine/values-test.yaml`. + +--- + +## Интерфейс + +![Redmine: страница входа](../screenshots/21-redmine-login.png) + +*Страница входа Redmine.* + +![Redmine: главная](../screenshots/22-redmine-home.png) + +*Главная Redmine: проекты и задачи.* + +### Проект и задача по умолчанию + +После bootstrap (`./scripts/bootstrap-redmine.sh`): + +| Объект | Значение | +|--------|----------| +| Проект | **Sova Platform** (`sova-platform`) | +| Пример задачи | [#27 CRUD для новых сущностей в API](http://redmine.sova.local/issues/27) | + +Задача #27 описывает CRUD для сущностей (новости, акции, заболевания, центры, статьи, услуги) — эталон для работы по Git-flow в test-контуре. + +--- + +## Архитектура + +```mermaid +flowchart LR + subgraph gitops [GitOps] + SD[sova-deploy main] + RT[ArgoCD redmine-test] + SP[ArgoCD sova-projects] + end + subgraph cluster [k3s] + RM[Redmine pod] + PG[(PostgreSQL redmine_test)] + MP[Mailpit SMTP] + ING[Ingress redmine.sova.local] + end + SD --> RT --> RM + SD --> SP + RM --> PG + RM --> MP + ING --> RM +``` + +| Компонент | Решение | +|-----------|---------| +| Chart | `sova-deploy/apps/redmine/` → Bitnami wrapper | +| Образ | `bitnamilegacy/redmine:6.0.5-debian-12-r0` | +| Namespace | `redmine` | +| PostgreSQL | БД `redmine_test` в `sova-data-test` (общий `postgresql-test`) | +| SMTP | Mailpit `mailpit.sova-mocks.svc.cluster.local:1025` (письма в UI Mailpit) | +| Ingress | `redmine.sova.local` (`deploy-platform-ingress.sh`) | +| ArgoCD | Application `redmine-test` в `argocd/apps/platform-tools.yaml` | +| AppProject | namespace `redmine` в `argocd/projects/sova-project.yaml`, GitOps через `sova-projects` | + +--- + +## Деплой + +### Через ArgoCD (основной путь) + +После push `sova-deploy` в Gitea приложение `redmine-test` синхронизируется автоматически (`sova-root` → `platform-tools.yaml`). + +Проверка: + +```bash +kubectl get application redmine-test -n argocd +kubectl get pods -n redmine +curl -s -o /dev/null -w "%{http_code}\n" http://redmine.sova.local/ +``` + +### Вручную (bootstrap кластера) + +```bash +cd k3s-test +source ./scripts/use-kubeconfig.sh + +# Helm + ingress + ArgoCD Application +./scripts/deploy-redmine.sh + +# Проект sova-platform + задача #27 через REST API +./scripts/deploy-redmine.sh --bootstrap +# или отдельно: +./scripts/bootstrap-redmine.sh +``` + +`bootstrap-redmine.sh`: + +1. Включает REST API в PostgreSQL (`rest_api_enabled`). +2. Создаёт проект `sova-platform`, если его нет. +3. Создаёт задачу **#27** с описанием CRUD (если ещё не существует). + +--- + +## Git-flow и коммиты + +Регламент сообщений коммитов (связь с Redmine): + +``` +feat(adminpanel): content CRUD (Refs #27) +fix(cabinet): registration on test contour (Fixes #45) +``` + +| Маркер | Эффект | +|--------|--------| +| `Refs #N` | ссылка на задачу; при webhook — ревизия в Redmine | +| `Fixes #N` | кликабельная ссылка в Gitea (external tracker) | + +Ветки: `prod` / `test` / `stage` — см. [Git-flow](../git-flow.md) и [Gitea CI](./gitea-ci.md). + +--- + +## Интеграция Gitea ↔ Redmine + +Автоматизация через Gitea API **не включена** — только инструкции: + +```bash +./scripts/setup-gitea-redmine-integration.sh +``` + +Скрипт выводит шаги: + +1. **External Issue Tracker** (каждый repo: backend, adminpanel, cabinet, docs) + URL: `http://redmine.sova.local/issues/{index}` + +2. **Webhook** (Push → ревизии в задаче) + URL: `http://redmine.sova.local/github_hook?project_id=` + Требует plugin `redmine_github_hook` в custom-образе `sova-redmine/` (опционально, не в базовом деплое). + +Базовый test-контур работает без webhook: задачи создаются в UI или через `bootstrap-redmine.sh`, коммиты помечаются `Refs #N` вручную в сообщении. + +--- + +## Troubleshooting + +| Проблема | Решение | +|----------|---------| +| `redmine-test` InvalidSpecError (namespace) | Применить `argocd/projects/sova-project.yaml`; проверить ArgoCD app `sova-projects` | +| Redmine ImagePullBackOff | `global.security.allowInsecureImages: true`; образ `bitnamilegacy/redmine` | +| DB connection error | БД `redmine_test` в `sova-data-test`; job `db-init` / SQL в `data/test/` | +| HTTP 502 / pod CrashLoop | `kubectl logs -n redmine deploy/redmine-test`; проверить PostgreSQL | +| REST API 403 | `./scripts/bootstrap-redmine.sh` включает `rest_api_enabled` | +| Письма не приходят | Ожидаемо в test: SMTP → Mailpit, не реальная почта | + +Проверка БД: + +```bash +kubectl exec -n sova-data-test postgresql-test-0 -- \ + env PGPASSWORD=sova_test_pass psql -U sova_test -d redmine_test -c '\dt' | head +``` + +--- + +## Файлы в репозитории + +| Путь | Назначение | +|------|------------| +| `sova-deploy/apps/redmine/` | Helm chart + `values-test.yaml` | +| `sova-deploy/argocd/apps/platform-tools.yaml` | Application `redmine-test` | +| `sova-deploy/argocd/apps/sova-projects.yaml` | GitOps для AppProject (namespace `redmine`) | +| `scripts/deploy-redmine.sh` | Helm + ingress + ArgoCD | +| `scripts/bootstrap-redmine.sh` | Проект + задача #27 | +| `scripts/setup-gitea-redmine-integration.sh` | Инструкции Gitea ↔ Redmine | +| `sova-redmine/` | Custom image с `redmine_github_hook` (опционально) | + +--- + +## Связанные разделы + +- [Grafana / Loki](./monitoring.md) — логи pod'ов (вместо Sentry) +- [Git-flow](../git-flow.md) — ветки и PR +- [Gitea CI](./gitea-ci.md) — pipeline и теги +- [ArgoCD: приложения](./argocd.md) — sync и health +- [Практическое руководство](../../../presentation-practical-guide.md) diff --git a/infrastructure/test-contour/index.md b/infrastructure/test-contour/index.md index 908e516..17142d2 100644 --- a/infrastructure/test-contour/index.md +++ b/infrastructure/test-contour/index.md @@ -12,6 +12,7 @@ - [Gitea: теги и CI/CD](./guides/gitea-ci) - [ArgoCD: приложения](./guides/argocd) - [Grafana / Prometheus / Loki](./guides/monitoring) +- [Redmine](./guides/redmine) — задачи и Git-flow *(30.05.2026)* ### Текстовая документация @@ -20,4 +21,13 @@ - [Система тегов CI/CD](./tags) — формат тегов и release-скрипт - [ArgoCD: sova-root и data-test](./argocd-apps) — зачем эти приложения и почему «нельзя войти» +### Справочник файлов k3s-test + +Полный перечень **~1085 файлов** с назначением каждого: + +- [Обзор справочника](./k3s-test-reference/) — дерево каталогов, типовые сценарии +- [scripts/](./k3s-test-reference/scripts) · [sova-deploy/](./k3s-test-reference/sova-deploy) · [sova-platform/](./k3s-test-reference/sova-platform) +- [sova-mocks/](./k3s-test-reference/sova-mocks) · [sova-redmine/](./k3s-test-reference/sova-redmine) +- [sova-backend/](./k3s-test-reference/sova-backend) · [sova-adminpanel/](./k3s-test-reference/sova-adminpanel) · [sova-cabinet/](./k3s-test-reference/sova-cabinet) · [sova-docs/](./k3s-test-reference/sova-docs-repo) + Исходники: репозиторий `sova/docs` в Gitea, локально — `k3s-test/sova-docs/`. diff --git a/infrastructure/test-contour/k3s-test-reference/_generate.py b/infrastructure/test-contour/k3s-test-reference/_generate.py new file mode 100644 index 0000000..492f0f2 --- /dev/null +++ b/infrastructure/test-contour/k3s-test-reference/_generate.py @@ -0,0 +1,365 @@ +#!/usr/bin/env python3 +"""Generate k3s-test file reference markdown from repo tree.""" +from __future__ import annotations + +import os +import re +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[4] # k3s-test/ +OUT = Path(__file__).resolve().parent + +SKIP_PARTS = { + "node_modules", ".git", "vendor", "dist", ".vitepress/cache", + ".vitepress/dist", ".terraform", ".tmp-chart", ".phpunit", +} +SKIP_NAMES = {".DS_Store"} + + +def should_skip(rel: str) -> bool: + parts = Path(rel).parts + if any(p in SKIP_PARTS for p in parts): + return True + if Path(rel).name in SKIP_NAMES: + return True + if "public/build" in rel: + return True + return False + + +def describe(rel: str) -> str: + name = Path(rel).name + p = rel.lower() + + # Extension-based defaults + ext = Path(rel).suffix.lower() + ext_map = { + ".sh": "Shell-скрипт", + ".py": "Python-скрипт", + ".yaml": "YAML-конфиг / Helm / K8s", + ".yml": "YAML-конфиг / docker-compose", + ".md": "Документация Markdown", + ".json": "JSON-данные / конфиг", + ".sql": "SQL (schema или seed)", + ".php": "PHP (Symfony)", + ".twig": "Twig-шаблон", + ".js": "JavaScript", + ".jsx": "React-компонент", + ".scss": "SCSS-стили", + ".css": "CSS-стили", + ".svg": "SVG-иконка / изображение", + ".png": "PNG-изображение", + ".jpg": "JPEG-изображение", + ".ico": "Favicon", + ".pdf": "PDF-документ", + ".pem": "TLS/JWT ключ", + ".tf": "Terraform", + ".hcl": "Terraform lock", + ".tfvars": "Terraform переменные", + ".tpl": "Helm template partial", + ".tgz": "Vendored Helm subchart", + ".lock": "Lockfile (Helm/composer/yarn)", + ".html": "HTML", + ".mts": "TypeScript (VitePress config)", + ".ts": "TypeScript", + ".mjs": "ES module (Node)", + ".env": "Переменные окружения", + ".xml": "XML-конфиг", + ".zip": "Архив", + ".tar": "Docker image tarball", + ".woff": "Web-font", + ".ttf": "TrueType font", + ".eot": "Embedded OpenType font", + } + + # Known files + known = { + "readme.md": "Главный README k3s-test", + "plan-sentry-redmine.md": "План Redmine (Sentry удалён из контура)", + "presentation-practical-guide.md": "Практическое руководство / демо для команды", + ".gitignore": "Git ignore rules", + "dockerfile": "Docker multistage build", + "compose.yaml": "Docker Compose (Symfony)", + "compose.override.yaml": "Локальные overrides Compose", + "docker-compose.yml": "Docker Compose (моки / cabinet dev)", + "package.json": "NPM/Yarn зависимости и scripts", + "composer.json": "PHP Composer зависимости", + "composer.lock": "Composer lockfile", + "yarn.lock": "Yarn lockfile", + "webpack.config.js": "Webpack Encore конфиг", + "vite.config.js": "Vite bundler конфиг", + "nginx.conf": "nginx конфиг контейнера", + "index.php": "HTTP front controller Symfony", + "index.html": "HTML entry (Vite/React)", + "console": "Symfony CLI entry", + "phpunit": "PHPUnit runner wrapper", + "build.yml": "Gitea Actions CI pipeline", + "config.mts": "VitePress: nav, sidebar, mermaid", + "manifest.json": "Метаданные скриншотов", + "env.js": "Runtime API URL (adminpanel)", + "entrypoint.sh": "Container entrypoint (env injection)", + "all.yaml": "Combined Helm template (Deployment/Service/Ingress)", + "values.yaml": "Базовые Helm values", + "values-test.yaml": "Overrides для test-контура", + "values-stage.yaml": "Overrides для stage-контура", + "chart.yaml": "Helm chart metadata", + "app-of-apps.yaml": "ArgoCD root Application (sova-root)", + "platform-tools.yaml": "ArgoCD: monitoring, Gitea Actions, Redmine", + "test-contour.yaml": "ArgoCD: приложения test-контура", + "sova-projects.yaml": "ArgoCD GitOps: AppProject definitions", + "sova-project.yaml": "ArgoCD AppProject RBAC и namespaces", + "db-init-jobs.yaml": "K8s Jobs: schema → seed SQL", + "release-tag.sh": "Создать git tag → Gitea CI → GitOps", + "bootstrap-multipass.sh": "Полный bootstrap VM + k3s + platform", + "deploy-test-stack.sh": "Деплой приложений test-контура", + "prepare-db-init.sh": "Генерация schema/seed SQL из monorepo", + "sync-from-monorepo.sh": "Синхронизация кода из родительского monorepo", + "use-kubeconfig.sh": "export KUBECONFIG=~/.kube/sova-test-config", + "print-urls.sh": "URL всех сервисов и пароли platform", + "smoke-test.sh": "Smoke-проверки HTTP + kubectl", + "testsdk.js": "Stub WrSDK/SmartCaptcha для *.sova.local", + "slideshow_controller.js": "Stimulus: lazy import owl.carousel", + "services_stub.yaml": "Stub-клиенты SMS/Calltouch/Captcha для test", + "services.php": "PHP DI bindings по APP_ENV", + } + if name.lower() in known: + return known[name.lower()] + + script_desc = { + "scripts/bootstrap-argocd.sh": "ArgoCD AppProject + Applications (sova-root, data-test, test-contour)", + "scripts/bootstrap-gitea-ci-secrets.sh": "Gitea Actions secrets: registry, deploy SSH key", + "scripts/bootstrap-gitea-runner.sh": "Установка Gitea Actions runner в k3s", + "scripts/bootstrap-gitea.sh": "Bootstrap Gitea: org sova, repos, admin user", + "scripts/bootstrap-redmine.sh": "REST API: проект sova-platform + задача #27", + "scripts/bootstrap-vm.sh": "Generic VM bootstrap helper", + "scripts/build-images.sh": "Сборка Docker-образов всех приложений (local-test/test tag)", + "scripts/configure-k3s-registry.sh": "k3s registries.yaml → pull из git.sova.local", + "scripts/deploy-monitoring-logs.sh": "Helm: Loki + Promtail (логи в Grafana)", + "scripts/deploy-platform-ingress.sh": "Ingress rules: Gitea, ArgoCD, Grafana, Redmine, docs", + "scripts/deploy-platform.sh": "Platform stack: ingress, ArgoCD, Gitea, Prometheus/Grafana", + "scripts/deploy-redmine.sh": "Helm Redmine + ingress + ArgoCD app redmine-test", + "scripts/deploy-sentry-redmine.sh": "Alias → deploy-redmine.sh (Sentry удалён)", + "scripts/import-images-to-vm.sh": "docker load .images/*.tar в Multipass VM", + "scripts/install-k3s-multipass.sh": "Установка k3s внутри Multipass VM", + "scripts/k3d-bootstrap.sh": "k3d cluster + ingress + apps (Mac без Multipass)", + "scripts/migrate-monorepo-branch.sh": "Demo: миграция ветки monorepo для issue #27", + "scripts/prepare-db-init.py": "Split SQL на schema/seed (helper для prepare-db-init.sh)", + "scripts/print-test-users.sh": "Тестовые логины/пароли приложений", + "scripts/release-test-tag.sh": "Wrapper → release-tag.sh (backward compat)", + "scripts/resize-multipass-vm.sh": "Увеличить CPU/RAM Multipass VM", + "scripts/setup-git-flow-branches.sh": "Создать prod/test/stage в Gitea repos", + "scripts/setup-gitea-branch-protection.sh": "Branch protection: PR-only на env-ветки", + "scripts/setup-gitea-redmine-integration.sh": "Инструкции Gitea ↔ Redmine (manual UI)", + "scripts/capture-platform-screenshots/capture.mjs": "Playwright: снять UI platform screenshots", + "scripts/capture-platform-screenshots/harness-check.mjs": "Проверка prerequisites screenshot harness", + "scripts/capture-platform-screenshots/reg-e2e.mjs": "E2E: сценарий регистрации cabinet", + "scripts/capture-platform-screenshots/run.sh": "Entry point: полный pipeline скриншотов", + } + if rel in script_desc: + return script_desc[rel] + + if "wiremock/mappings" in p or "charts/mocks/mappings" in p: + stub = name.replace(".json", "").replace("-", " ") + return f"WireMock stub: {stub}" + if "/migrations/version" in p: + return "Doctrine migration" + if "/entity/" in p: + return f"Doctrine entity: {name.replace('.php', '')}" + if "/repository/" in p: + return f"Doctrine repository: {name.replace('.php', '')}" + if "/controller/" in p and ext == ".php": + return f"Symfony controller: {name.replace('.php', '')}" + if "/command/" in p and ext == ".php": + return f"Console command: {name.replace('.php', '')}" + if "/service/" in p and ext == ".php": + return f"Service: {name.replace('.php', '')}" + if "/dto/" in p or "/dto\\" in p: + return f"DTO: {name.replace('.php', '')}" + if "/form/" in p and ext == ".php": + return f"Form type: {name.replace('.php', '')}" + if "/messagehandler/" in p: + return f"Messenger handler: {name.replace('.php', '')}" + if "/message/" in p and ext == ".php": + return f"Messenger message: {name.replace('.php', '')}" + if "/controllers/" in p and name.endswith("_controller.js"): + return f"Stimulus controller: {name.replace('_controller.js', '')}" + if "/pages/" in p and ext == ".jsx": + return f"React page: {name.replace('.jsx', '')}" + if "/api/api" in p and ext == ".js": + return f"RTK Query API slice: {name.replace('.js', '')}" + if "/components/" in p and ext == ".jsx": + return f"React component: {name.replace('.jsx', '')}" + if "/hooks/" in p and ext == ".jsx": + return f"React hook: {name.replace('.jsx', '')}" + if "/templates/" in p and ext == ".twig": + return f"Twig template: {rel.split('templates/')[-1]}" + if "/config/packages/" in p: + return f"Symfony bundle config: {name}" + if "/assets/sass/" in p: + return f"SCSS entry: {name}" + if "/screenshots/" in p and ext == ".png": + return f"Скриншот UI: {name}" + if "/forms-screenshots/" in p and ext == ".png": + return f"Скриншот формы cabinet: {name}" + if "/backend-scenarios/" in p: + return f"Сценарий backend: {name.replace('.md', '')}" + if "/apps/" in p and ext == ".md": + return f"Документация приложения: {name.replace('.md', '')}" + if "/infrastructure/" in p and ext == ".md": + return f"Инфра-документация: {name.replace('.md', '')}" + if "platform-credentials.env" in p: + return "Сгенерированные креды platform (не в git)" + if ".images/" in p and ext == ".tar": + return f"Saved Docker image для import-images-to-vm.sh" + if "ci-ssh/" in p: + return "SSH-ключ Gitea Actions → sova-deploy GitOps" + + if ext in ext_map: + return ext_map[ext] + return "Файл проекта" + + +def collect(prefix: str) -> list[tuple[str, str]]: + base = ROOT / prefix if prefix else ROOT + files: list[tuple[str, str]] = [] + for path in sorted(base.rglob("*")): + if not path.is_file(): + continue + rel = path.relative_to(ROOT).as_posix() + if should_skip(rel): + continue + if prefix and not rel.startswith(prefix.rstrip("/")): + continue + files.append((rel, describe(rel))) + return files + + +def md_table(rows: list[tuple[str, str]], path_col: str = "Путь") -> str: + if not rows: + return "_Нет файлов._\n" + lines = [f"| {path_col} | Назначение |", "|------|------------|"] + for rel, desc in rows: + lines.append(f"| `{rel}` | {desc} |") + return "\n".join(lines) + "\n" + + +def group_by_dir(files: list[tuple[str, str]]) -> dict[str, list[tuple[str, str]]]: + groups: dict[str, list[tuple[str, str]]] = {} + for rel, desc in files: + parent = str(Path(rel).parent) + groups.setdefault(parent if parent != "." else "(root)", []).append((rel, desc)) + return dict(sorted(groups.items())) + + +def write_page(filename: str, title: str, intro: str, files: list[tuple[str, str]], grouped: bool = True) -> None: + body = [f"# {title}\n", intro, f"\n**Файлов:** {len(files)}\n"] + if grouped: + for dirname, rows in group_by_dir(files).items(): + body.append(f"\n## `{dirname}/`\n\n") + body.append(md_table(rows, "Файл")) + else: + body.append("\n") + body.append(md_table(files)) + (OUT / filename).write_text("\n".join(body), encoding="utf-8") + + +SECTIONS = [ + ("scripts.md", "scripts/", "Скрипты k3s-test", "Все shell/Python/Node скрипты bootstrap, deploy, CI и утилит. Запускать из каталога `k3s-test/`."), + ("sova-deploy.md", "sova-deploy/", "sova-deploy: Helm и ArgoCD", "GitOps-репозиторий: Helm charts приложений, data layer, ArgoCD Applications и platform values."), + ("sova-platform.md", "sova-platform/", "sova-platform: Terraform", "Terraform для Multipass VM и установки k3s на single-node."), + ("sova-mocks.md", "sova-mocks/", "sova-mocks: WireMock и Mailpit", "Моки внешних API (MIS, Calltouch, Captcha) и SMTP для test-контура."), + ("sova-redmine.md", "sova-redmine/", "sova-redmine: custom image", "Опциональный custom Docker-образ Redmine с plugin github_hook."), + ("docs-pointers.md", "docs/", "docs/: указатели", "Короткие markdown-файлы со ссылками на VitePress."), + ("sova-backend.md", "sova-backend/", "sova-backend: Symfony API", "Backend API для adminpanel и интеграций. Копия из monorepo + test-специфичные правки."), + ("sova-adminpanel.md", "sova-adminpanel/", "sova-adminpanel: React admin", "React + Vite admin panel для CRUD контента и специалистов."), + ("sova-cabinet.md", "sova-cabinet/", "sova-cabinet: Symfony ЛК", "Личный кабинет пациента: регистрация, запись, оплата."), + ("sova-docs-repo.md", "sova-docs/", "sova-docs: сайт документации", "VitePress-сайт (монорепо docs + test-contour). Собирается в Docker и деплоится как docs-test."), +] + +ROOT_FILES = [ + "README.md", "plan-sentry-redmine.md", "presentation-practical-guide.md", ".gitignore", +] + + +def main() -> None: + for filename, prefix, title, intro in SECTIONS: + files = collect(prefix) + write_page(filename, title, intro, files) + + # Root + generated + images + root_rows: list[tuple[str, str]] = [] + for name in ROOT_FILES: + p = ROOT / name + if p.exists(): + root_rows.append((name, describe(name))) + for prefix in [".generated/", ".images/"]: + root_rows.extend(collect(prefix)) + + write_page( + "root-and-artifacts.md", + "Корень k3s-test и артеfacts", + "Файлы в корне `k3s-test/`, сгенерированные креды и tar-образы для offline import.\n\n" + "> **Не документируем:** `.tmp-chart/` (legacy Sentry chart, 456 upstream-файлов), " + "`vendor/`, `node_modules/`, `public/build/` (сборка Webpack), `.terraform/providers/`.", + root_rows, + grouped=False, + ) + + # Index + total = sum(len(collect(p)) for _, p, _, _ in SECTIONS) + len(root_rows) + index = [ + "# Справочник файлов k3s-test\n", + "Полный перечень файлов песочницы `k3s-test/` с кратким назначением каждого.", + "Для понимания **как пользоваться** контуром начните с [обзора test-контура](../) и [статьи «что сделано»](../test-contour-article).", + "Этот справочник отвечает на вопрос **«что лежит в каком файле»**.\n", + f"**Документировано файлов:** ~{total} (без vendor/node_modules/dist/.tmp-chart).\n", + "## Дерево каталогов\n", + "```", + "k3s-test/", + "├── README.md, plan-sentry-redmine.md, presentation-practical-guide.md", + "├── .generated/ # platform-credentials.env, CI SSH keys", + "├── .images/ # *.tar для import-images-to-vm.sh", + "├── docs/ # указатели на VitePress", + "├── scripts/ # bootstrap, deploy, CI, smoke", + "├── sova-adminpanel/ # React admin + Gitea CI", + "├── sova-backend/ # Symfony API + Gitea CI", + "├── sova-cabinet/ # Symfony ЛК + Gitea CI", + "├── sova-deploy/ # Helm + ArgoCD GitOps", + "├── sova-docs/ # VitePress documentation site", + "├── sova-mocks/ # WireMock + Mailpit", + "├── sova-platform/ # Terraform k3s bootstrap", + "└── sova-redmine/ # custom Redmine image (optional)", + "```\n", + "## Разделы справочника\n", + "| Раздел | Файлов | Описание |", + "|--------|--------|----------|", + ] + for filename, prefix, title, _ in SECTIONS: + n = len(collect(prefix)) + link = filename.replace(".md", "") + index.append(f"| [{title}](./{link}) | {n} | `{prefix}` |") + index.append(f"| [Корень и артеfacts](./root-and-artifacts) | {len(root_rows)} | README, `.generated/`, `.images/` |") + index.extend([ + "\n## Типовые сценарии (какие скрипты вызывать)\n", + "| Сценарий | Команды |", + "|----------|---------|", + "| **Первый запуск (Multipass)** | `bootstrap-multipass.sh` → `build-images.sh` → `import-images-to-vm.sh` → `deploy-platform.sh` → `deploy-test-stack.sh` |", + "| **Первый запуск (k3d на Mac)** | `sync-from-monorepo.sh` → `build-images.sh` → `k3d-bootstrap.sh` |", + "| **Старт/стоп VM** | `multipass start sova-test` / `multipass stop sova-test` → `source scripts/use-kubeconfig.sh` |", + "| **Релиз приложения** | `scripts/release-tag.sh {backend\\|adminpanel\\|cabinet\\|docs} {tag} test` |", + "| **Обновить БД test** | `prepare-db-init.sh` → удалить job db-init → redeploy data-test |", + "| **Redmine** | `deploy-redmine.sh --bootstrap` |", + "| **Скриншоты для доков** | `capture-platform-screenshots/run.sh` |", + "\n## Связанная документация\n", + "- [Git-flow](../git-flow) — ветки prod/test/stage", + "- [Система тегов](../tags) — `{component}-v{semver}-{env}`", + "- [ArgoCD приложения](../argocd-apps) — sova-root, data-test", + "- [Gitea CI](./guides/gitea-ci) — pipeline и registry", + "- [Redmine](./guides/redmine) — issue tracker", + ]) + (OUT / "index.md").write_text("\n".join(index), encoding="utf-8") + print(f"Generated {len(SECTIONS)+2} pages, ~{total} files") + + +if __name__ == "__main__": + main() diff --git a/infrastructure/test-contour/k3s-test-reference/docs-pointers.md b/infrastructure/test-contour/k3s-test-reference/docs-pointers.md new file mode 100644 index 0000000..5029744 --- /dev/null +++ b/infrastructure/test-contour/k3s-test-reference/docs-pointers.md @@ -0,0 +1,14 @@ +# docs/: указатели + +Короткие markdown-файлы со ссылками на VitePress. + +**Файлов:** 2 + + +## `docs/` + + +| Файл | Назначение | +|------|------------| +| `docs/git-flow.md` | Документация Markdown | +| `docs/test-contour-article.md` | Документация Markdown | diff --git a/infrastructure/test-contour/k3s-test-reference/index.md b/infrastructure/test-contour/k3s-test-reference/index.md new file mode 100644 index 0000000..8f5eba5 --- /dev/null +++ b/infrastructure/test-contour/k3s-test-reference/index.md @@ -0,0 +1,62 @@ +# Справочник файлов k3s-test + +Полный перечень файлов песочницы `k3s-test/` с кратким назначением каждого. +Для понимания **как пользоваться** контуром начните с [обзора test-контура](../) и [статьи «что сделано»](../test-contour-article). +Этот справочник отвечает на вопрос **«что лежит в каком файле»**. + +**Документировано файлов:** ~1086 (без vendor/node_modules/dist/.tmp-chart). + +## Дерево каталогов + +``` +k3s-test/ +├── README.md, plan-sentry-redmine.md, presentation-practical-guide.md +├── .generated/ # platform-credentials.env, CI SSH keys +├── .images/ # *.tar для import-images-to-vm.sh +├── docs/ # указатели на VitePress +├── scripts/ # bootstrap, deploy, CI, smoke +├── sova-adminpanel/ # React admin + Gitea CI +├── sova-backend/ # Symfony API + Gitea CI +├── sova-cabinet/ # Symfony ЛК + Gitea CI +├── sova-deploy/ # Helm + ArgoCD GitOps +├── sova-docs/ # VitePress documentation site +├── sova-mocks/ # WireMock + Mailpit +├── sova-platform/ # Terraform k3s bootstrap +└── sova-redmine/ # custom Redmine image (optional) +``` + +## Разделы справочника + +| Раздел | Файлов | Описание | +|--------|--------|----------| +| [Скрипты k3s-test](./scripts) | 38 | `scripts/` | +| [sova-deploy: Helm и ArgoCD](./sova-deploy) | 56 | `sova-deploy/` | +| [sova-platform: Terraform](./sova-platform) | 10 | `sova-platform/` | +| [sova-mocks: WireMock и Mailpit](./sova-mocks) | 19 | `sova-mocks/` | +| [sova-redmine: custom image](./sova-redmine) | 2 | `sova-redmine/` | +| [docs/: указатели](./docs-pointers) | 2 | `docs/` | +| [sova-backend: Symfony API](./sova-backend) | 277 | `sova-backend/` | +| [sova-adminpanel: React admin](./sova-adminpanel) | 129 | `sova-adminpanel/` | +| [sova-cabinet: Symfony ЛК](./sova-cabinet) | 428 | `sova-cabinet/` | +| [sova-docs: сайт документации](./sova-docs-repo) | 114 | `sova-docs/` | +| [Корень и артеfacts](./root-and-artifacts) | 11 | README, `.generated/`, `.images/` | + +## Типовые сценарии (какие скрипты вызывать) + +| Сценарий | Команды | +|----------|---------| +| **Первый запуск (Multipass)** | `bootstrap-multipass.sh` → `build-images.sh` → `import-images-to-vm.sh` → `deploy-platform.sh` → `deploy-test-stack.sh` | +| **Первый запуск (k3d на Mac)** | `sync-from-monorepo.sh` → `build-images.sh` → `k3d-bootstrap.sh` | +| **Старт/стоп VM** | `multipass start sova-test` / `multipass stop sova-test` → `source scripts/use-kubeconfig.sh` | +| **Релиз приложения** | `scripts/release-tag.sh {backend\|adminpanel\|cabinet\|docs} {tag} test` | +| **Обновить БД test** | `prepare-db-init.sh` → удалить job db-init → redeploy data-test | +| **Redmine** | `deploy-redmine.sh --bootstrap` | +| **Скриншоты для доков** | `capture-platform-screenshots/run.sh` | + +## Связанная документация + +- [Git-flow](../git-flow) — ветки prod/test/stage +- [Система тегов](../tags) — `{component}-v{semver}-{env}` +- [ArgoCD приложения](../argocd-apps) — sova-root, data-test +- [Gitea CI](./guides/gitea-ci) — pipeline и registry +- [Redmine](./guides/redmine) — issue tracker \ No newline at end of file diff --git a/infrastructure/test-contour/k3s-test-reference/root-and-artifacts.md b/infrastructure/test-contour/k3s-test-reference/root-and-artifacts.md new file mode 100644 index 0000000..027436b --- /dev/null +++ b/infrastructure/test-contour/k3s-test-reference/root-and-artifacts.md @@ -0,0 +1,23 @@ +# Корень k3s-test и артеfacts + +Файлы в корне `k3s-test/`, сгенерированные креды и tar-образы для offline import. + +> **Не документируем:** `.tmp-chart/` (legacy Sentry chart, 456 upstream-файлов), `vendor/`, `node_modules/`, `public/build/` (сборка Webpack), `.terraform/providers/`. + +**Файлов:** 11 + + + +| Путь | Назначение | +|------|------------| +| `README.md` | Главный README k3s-test | +| `plan-sentry-redmine.md` | План Redmine (Sentry удалён из контура) | +| `presentation-practical-guide.md` | Практическое руководство / демо для команды | +| `.gitignore` | Git ignore rules | +| `.generated/ci-ssh/sova-deploy` | SSH-ключ Gitea Actions → sova-deploy GitOps | +| `.generated/ci-ssh/sova-deploy.pub` | SSH-ключ Gitea Actions → sova-deploy GitOps | +| `.generated/platform-credentials.env` | Сгенерированные креды platform (не в git) | +| `.images/sova-adminpanel-local-test.tar` | Saved Docker image для import-images-to-vm.sh | +| `.images/sova-backend-local-test.tar` | Saved Docker image для import-images-to-vm.sh | +| `.images/sova-cabinet-local-test.tar` | Saved Docker image для import-images-to-vm.sh | +| `.images/sova-docs-local-test.tar` | Saved Docker image для import-images-to-vm.sh | diff --git a/infrastructure/test-contour/k3s-test-reference/scripts.md b/infrastructure/test-contour/k3s-test-reference/scripts.md new file mode 100644 index 0000000..e0e451b --- /dev/null +++ b/infrastructure/test-contour/k3s-test-reference/scripts.md @@ -0,0 +1,57 @@ +# Скрипты k3s-test + +Все shell/Python/Node скрипты bootstrap, deploy, CI и утилит. Запускать из каталога `k3s-test/`. + +**Файлов:** 38 + + +## `scripts/` + + +| Файл | Назначение | +|------|------------| +| `scripts/bootstrap-argocd.sh` | ArgoCD AppProject + Applications (sova-root, data-test, test-contour) | +| `scripts/bootstrap-gitea-ci-secrets.sh` | Gitea Actions secrets: registry, deploy SSH key | +| `scripts/bootstrap-gitea-runner.sh` | Установка Gitea Actions runner в k3s | +| `scripts/bootstrap-gitea.sh` | Bootstrap Gitea: org sova, repos, admin user | +| `scripts/bootstrap-multipass.sh` | Полный bootstrap VM + k3s + platform | +| `scripts/bootstrap-redmine.sh` | REST API: проект sova-platform + задача #27 | +| `scripts/bootstrap-vm.sh` | Generic VM bootstrap helper | +| `scripts/build-images.sh` | Сборка Docker-образов всех приложений (local-test/test tag) | +| `scripts/configure-k3s-registry.sh` | k3s registries.yaml → pull из git.sova.local | +| `scripts/deploy-monitoring-logs.sh` | Helm: Loki + Promtail (логи в Grafana) | +| `scripts/deploy-platform-ingress.sh` | Ingress rules: Gitea, ArgoCD, Grafana, Redmine, docs | +| `scripts/deploy-platform.sh` | Platform stack: ingress, ArgoCD, Gitea, Prometheus/Grafana | +| `scripts/deploy-redmine.sh` | Helm Redmine + ingress + ArgoCD app redmine-test | +| `scripts/deploy-sentry-redmine.sh` | Alias → deploy-redmine.sh (Sentry удалён) | +| `scripts/deploy-test-stack.sh` | Деплой приложений test-контура | +| `scripts/import-images-to-vm.sh` | docker load .images/*.tar в Multipass VM | +| `scripts/install-k3s-multipass.sh` | Установка k3s внутри Multipass VM | +| `scripts/k3d-bootstrap.sh` | k3d cluster + ingress + apps (Mac без Multipass) | +| `scripts/migrate-monorepo-branch.sh` | Demo: миграция ветки monorepo для issue #27 | +| `scripts/prepare-db-init.py` | Split SQL на schema/seed (helper для prepare-db-init.sh) | +| `scripts/prepare-db-init.sh` | Генерация schema/seed SQL из monorepo | +| `scripts/print-test-users.sh` | Тестовые логины/пароли приложений | +| `scripts/print-urls.sh` | URL всех сервисов и пароли platform | +| `scripts/release-tag.sh` | Создать git tag → Gitea CI → GitOps | +| `scripts/release-test-tag.sh` | Wrapper → release-tag.sh (backward compat) | +| `scripts/resize-multipass-vm.sh` | Увеличить CPU/RAM Multipass VM | +| `scripts/setup-git-flow-branches.sh` | Создать prod/test/stage в Gitea repos | +| `scripts/setup-gitea-branch-protection.sh` | Branch protection: PR-only на env-ветки | +| `scripts/setup-gitea-redmine-integration.sh` | Инструкции Gitea ↔ Redmine (manual UI) | +| `scripts/smoke-test.sh` | Smoke-проверки HTTP + kubectl | +| `scripts/sync-from-monorepo.sh` | Синхронизация кода из родительского monorepo | +| `scripts/use-kubeconfig.sh` | export KUBECONFIG=~/.kube/sova-test-config | + + +## `scripts/capture-platform-screenshots/` + + +| Файл | Назначение | +|------|------------| +| `scripts/capture-platform-screenshots/capture.mjs` | Playwright: снять UI platform screenshots | +| `scripts/capture-platform-screenshots/harness-check.mjs` | Проверка prerequisites screenshot harness | +| `scripts/capture-platform-screenshots/package-lock.json` | JSON-данные / конфиг | +| `scripts/capture-platform-screenshots/package.json` | NPM/Yarn зависимости и scripts | +| `scripts/capture-platform-screenshots/reg-e2e.mjs` | E2E: сценарий регистрации cabinet | +| `scripts/capture-platform-screenshots/run.sh` | Entry point: полный pipeline скриншотов | diff --git a/infrastructure/test-contour/k3s-test-reference/sova-adminpanel.md b/infrastructure/test-contour/k3s-test-reference/sova-adminpanel.md new file mode 100644 index 0000000..d901ad1 --- /dev/null +++ b/infrastructure/test-contour/k3s-test-reference/sova-adminpanel.md @@ -0,0 +1,358 @@ +# sova-adminpanel: React admin + +React + Vite admin panel для CRUD контента и специалистов. + +**Файлов:** 129 + + +## `sova-adminpanel/` + + +| Файл | Назначение | +|------|------------| +| `sova-adminpanel/.gitignore` | Git ignore rules | +| `sova-adminpanel/Dockerfile` | Docker multistage build | +| `sova-adminpanel/README.md` | Главный README k3s-test | +| `sova-adminpanel/babel.config.js` | JavaScript | +| `sova-adminpanel/eslint.config.js` | JavaScript | +| `sova-adminpanel/index.html` | HTML entry (Vite/React) | +| `sova-adminpanel/jest.config.js` | JavaScript | +| `sova-adminpanel/jest.setup.js` | JavaScript | +| `sova-adminpanel/package.json` | NPM/Yarn зависимости и scripts | +| `sova-adminpanel/vite.config.js` | Vite bundler конфиг | + + +## `sova-adminpanel/.gitea/workflows/` + + +| Файл | Назначение | +|------|------------| +| `sova-adminpanel/.gitea/workflows/build.yml` | Gitea Actions CI pipeline | + + +## `sova-adminpanel/docker/` + + +| Файл | Назначение | +|------|------------| +| `sova-adminpanel/docker/entrypoint.sh` | Container entrypoint (env injection) | +| `sova-adminpanel/docker/nginx.conf` | nginx конфиг контейнера | + + +## `sova-adminpanel/public/` + + +| Файл | Назначение | +|------|------------| +| `sova-adminpanel/public/env.js` | Runtime API URL (adminpanel) | +| `sova-adminpanel/public/robots.txt` | Файл проекта | + + +## `sova-adminpanel/src/` + + +| Файл | Назначение | +|------|------------| +| `sova-adminpanel/src/App.jsx` | React-компонент | +| `sova-adminpanel/src/main.jsx` | React-компонент | + + +## `sova-adminpanel/src/api/` + + +| Файл | Назначение | +|------|------------| +| `sova-adminpanel/src/api/apiArticle.js` | RTK Query API slice: apiArticle | +| `sova-adminpanel/src/api/apiCertificate.js` | RTK Query API slice: apiCertificate | +| `sova-adminpanel/src/api/apiContent.js` | RTK Query API slice: apiContent | +| `sova-adminpanel/src/api/apiDepartment.js` | RTK Query API slice: apiDepartment | +| `sova-adminpanel/src/api/apiDisease.js` | RTK Query API slice: apiDisease | +| `sova-adminpanel/src/api/apiFilial.js` | RTK Query API slice: apiFilial | +| `sova-adminpanel/src/api/apiIDoctor.js` | RTK Query API slice: apiIDoctor | +| `sova-adminpanel/src/api/apiKodoper.js` | RTK Query API slice: apiKodoper | +| `sova-adminpanel/src/api/apiLocation.js` | RTK Query API slice: apiLocation | +| `sova-adminpanel/src/api/apiMedicalCenter.js` | RTK Query API slice: apiMedicalCenter | +| `sova-adminpanel/src/api/apiNews.js` | RTK Query API slice: apiNews | +| `sova-adminpanel/src/api/apiSitePromo.js` | RTK Query API slice: apiSitePromo | +| `sova-adminpanel/src/api/apiSiteServices.js` | RTK Query API slice: apiSiteServices | +| `sova-adminpanel/src/api/apiSlice.js` | RTK Query API slice: apiSlice | +| `sova-adminpanel/src/api/apiSpecialist.js` | RTK Query API slice: apiSpecialist | +| `sova-adminpanel/src/api/apiStock.js` | RTK Query API slice: apiStock | + + +## `sova-adminpanel/src/assets/` + + +| Файл | Назначение | +|------|------------| +| `sova-adminpanel/src/assets/icon.png` | PNG-изображение | +| `sova-adminpanel/src/assets/image-placeholder.png` | PNG-изображение | +| `sova-adminpanel/src/assets/logo.png` | PNG-изображение | +| `sova-adminpanel/src/assets/photo-placeholder.png` | PNG-изображение | +| `sova-adminpanel/src/assets/video-placeholder.png` | PNG-изображение | + + +## `sova-adminpanel/src/components/Button/` + + +| Файл | Назначение | +|------|------------| +| `sova-adminpanel/src/components/Button/Button.jsx` | React component: Button | +| `sova-adminpanel/src/components/Button/Button.module.scss` | SCSS-стили | + + +## `sova-adminpanel/src/components/Docs/` + + +| Файл | Назначение | +|------|------------| +| `sova-adminpanel/src/components/Docs/Certificates.jsx` | React component: Certificates | +| `sova-adminpanel/src/components/Docs/Portfolio.jsx` | React component: Portfolio | +| `sova-adminpanel/src/components/Docs/Stocks.jsx` | React component: Stocks | + + +## `sova-adminpanel/src/components/Editors/` + + +| Файл | Назначение | +|------|------------| +| `sova-adminpanel/src/components/Editors/CertEditor.jsx` | React component: CertEditor | +| `sova-adminpanel/src/components/Editors/TextEditor.jsx` | React component: TextEditor | + + +## `sova-adminpanel/src/components/Forms/` + + +| Файл | Назначение | +|------|------------| +| `sova-adminpanel/src/components/Forms/EditElementForm.jsx` | React component: EditElementForm | + + +## `sova-adminpanel/src/components/Input/` + + +| Файл | Назначение | +|------|------------| +| `sova-adminpanel/src/components/Input/Input.jsx` | React component: Input | +| `sova-adminpanel/src/components/Input/PhoneInput.jsx` | React component: PhoneInput | +| `sova-adminpanel/src/components/Input/TagKodoperStatic.jsx` | React component: TagKodoperStatic | +| `sova-adminpanel/src/components/Input/TagStaticInput.jsx` | React component: TagStaticInput | +| `sova-adminpanel/src/components/Input/Taginput.jsx` | React component: Taginput | + + +## `sova-adminpanel/src/components/Modals/` + + +| Файл | Назначение | +|------|------------| +| `sova-adminpanel/src/components/Modals/DcodeModal.jsx` | React component: DcodeModal | +| `sova-adminpanel/src/components/Modals/KodoperModal.jsx` | React component: KodoperModal | +| `sova-adminpanel/src/components/Modals/Modal.jsx` | React component: Modal | +| `sova-adminpanel/src/components/Modals/ResponseModals.jsx` | React component: ResponseModals | +| `sova-adminpanel/src/components/Modals/StockModal.jsx` | React component: StockModal | + + +## `sova-adminpanel/src/components/Navbar/` + + +| Файл | Назначение | +|------|------------| +| `sova-adminpanel/src/components/Navbar/Navbar.jsx` | React component: Navbar | +| `sova-adminpanel/src/components/Navbar/Navbar.module.scss` | SCSS-стили | + + +## `sova-adminpanel/src/components/Paginations/` + + +| Файл | Назначение | +|------|------------| +| `sova-adminpanel/src/components/Paginations/PageNav.jsx` | React component: PageNav | + + +## `sova-adminpanel/src/components/Placeholders/` + + +| Файл | Назначение | +|------|------------| +| `sova-adminpanel/src/components/Placeholders/ErrorComponent.jsx` | React component: ErrorComponent | +| `sova-adminpanel/src/components/Placeholders/LoadingComponent.jsx` | React component: LoadingComponent | +| `sova-adminpanel/src/components/Placeholders/NotFindElement.jsx` | React component: NotFindElement | + + +## `sova-adminpanel/src/components/Sidebar/` + + +| Файл | Назначение | +|------|------------| +| `sova-adminpanel/src/components/Sidebar/Sidebar.jsx` | React component: Sidebar | + + +## `sova-adminpanel/src/components/SidebarNavItem/` + + +| Файл | Назначение | +|------|------------| +| `sova-adminpanel/src/components/SidebarNavItem/SidebarNavItem.jsx` | React component: SidebarNavItem | +| `sova-adminpanel/src/components/SidebarNavItem/SidebarNavItem.module.scss` | SCSS-стили | + + +## `sova-adminpanel/src/components/Table/` + + +| Файл | Назначение | +|------|------------| +| `sova-adminpanel/src/components/Table/FilterBar.jsx` | React component: FilterBar | +| `sova-adminpanel/src/components/Table/TBody.jsx` | React component: TBody | +| `sova-adminpanel/src/components/Table/THead.jsx` | React component: THead | + + +## `sova-adminpanel/src/components/UserBurger/` + + +| Файл | Назначение | +|------|------------| +| `sova-adminpanel/src/components/UserBurger/UserBurger.jsx` | React component: UserBurger | + + +## `sova-adminpanel/src/config/` + + +| Файл | Назначение | +|------|------------| +| `sova-adminpanel/src/config/api.js` | JavaScript | +| `sova-adminpanel/src/config/contentResources.js` | JavaScript | + + +## `sova-adminpanel/src/hooks/` + + +| Файл | Назначение | +|------|------------| +| `sova-adminpanel/src/hooks/useLostLocations.jsx` | React hook: useLostLocations | +| `sova-adminpanel/src/hooks/useNewSpecialistId.jsx` | React hook: useNewSpecialistId | +| `sova-adminpanel/src/hooks/useOutsideClick.jsx` | React hook: useOutsideClick | +| `sova-adminpanel/src/hooks/useSortedPaginated.jsx` | React hook: useSortedPaginated | +| `sova-adminpanel/src/hooks/useSorting.jsx` | React hook: useSorting | +| `sova-adminpanel/src/hooks/useSpecialist.jsx` | React hook: useSpecialist | +| `sova-adminpanel/src/hooks/useSpecialistFilter.jsx` | React hook: useSpecialistFilter | + + +## `sova-adminpanel/src/pages/` + + +| Файл | Назначение | +|------|------------| +| `sova-adminpanel/src/pages/AddArticlePage.jsx` | React page: AddArticlePage | +| `sova-adminpanel/src/pages/AddDiseasePage.jsx` | React page: AddDiseasePage | +| `sova-adminpanel/src/pages/AddMedicalCenterPage.jsx` | React page: AddMedicalCenterPage | +| `sova-adminpanel/src/pages/AddNewsPage.jsx` | React page: AddNewsPage | +| `sova-adminpanel/src/pages/AddSitePromoPage.jsx` | React page: AddSitePromoPage | +| `sova-adminpanel/src/pages/AddSiteServicesPage.jsx` | React page: AddSiteServicesPage | +| `sova-adminpanel/src/pages/AddSpecialistPage.jsx` | React page: AddSpecialistPage | +| `sova-adminpanel/src/pages/AddStockPage.jsx` | React page: AddStockPage | +| `sova-adminpanel/src/pages/ArticleListPage.jsx` | React page: ArticleListPage | +| `sova-adminpanel/src/pages/DepartmentsListPage.jsx` | React page: DepartmentsListPage | +| `sova-adminpanel/src/pages/DiseaseListPage.jsx` | React page: DiseaseListPage | +| `sova-adminpanel/src/pages/EditArticlePage.jsx` | React page: EditArticlePage | +| `sova-adminpanel/src/pages/EditDepartmentPage.jsx` | React page: EditDepartmentPage | +| `sova-adminpanel/src/pages/EditDiseasePage.jsx` | React page: EditDiseasePage | +| `sova-adminpanel/src/pages/EditFilialPage.jsx` | React page: EditFilialPage | +| `sova-adminpanel/src/pages/EditMedicalCenterPage.jsx` | React page: EditMedicalCenterPage | +| `sova-adminpanel/src/pages/EditNewsPage.jsx` | React page: EditNewsPage | +| `sova-adminpanel/src/pages/EditSitePromoPage.jsx` | React page: EditSitePromoPage | +| `sova-adminpanel/src/pages/EditSiteServicesPage.jsx` | React page: EditSiteServicesPage | +| `sova-adminpanel/src/pages/EditSpecialistPage.jsx` | React page: EditSpecialistPage | +| `sova-adminpanel/src/pages/EditStockPage.jsx` | React page: EditStockPage | +| `sova-adminpanel/src/pages/FilialsListPage.jsx` | React page: FilialsListPage | +| `sova-adminpanel/src/pages/HomePage.jsx` | React page: HomePage | +| `sova-adminpanel/src/pages/InfoclinicListPage.jsx` | React page: InfoclinicListPage | +| `sova-adminpanel/src/pages/LoginPage.jsx` | React page: LoginPage | +| `sova-adminpanel/src/pages/LostDoctorsPage.jsx` | React page: LostDoctorsPage | +| `sova-adminpanel/src/pages/MainPage.jsx` | React page: MainPage | +| `sova-adminpanel/src/pages/MedicalCenterListPage.jsx` | React page: MedicalCenterListPage | +| `sova-adminpanel/src/pages/NewsListPage.jsx` | React page: NewsListPage | +| `sova-adminpanel/src/pages/NotFoundPage.jsx` | React page: NotFoundPage | +| `sova-adminpanel/src/pages/PricesListPage.jsx` | React page: PricesListPage | +| `sova-adminpanel/src/pages/SitePromoListPage.jsx` | React page: SitePromoListPage | +| `sova-adminpanel/src/pages/SiteServicesListPage.jsx` | React page: SiteServicesListPage | +| `sova-adminpanel/src/pages/SpecialistListPage.jsx` | React page: SpecialistListPage | +| `sova-adminpanel/src/pages/SpecialistTable.jsx` | React page: SpecialistTable | +| `sova-adminpanel/src/pages/StoksListPage.jsx` | React page: StoksListPage | +| `sova-adminpanel/src/pages/UserPage.jsx` | React page: UserPage | + + +## `sova-adminpanel/src/pages/__test__/` + + +| Файл | Назначение | +|------|------------| +| `sova-adminpanel/src/pages/__test__/LoginPage.test.jsx` | React page: LoginPage.test | + + +## `sova-adminpanel/src/pages/content/` + + +| Файл | Назначение | +|------|------------| +| `sova-adminpanel/src/pages/content/ContentEditPage.jsx` | React page: ContentEditPage | +| `sova-adminpanel/src/pages/content/ContentListPage.jsx` | React page: ContentListPage | +| `sova-adminpanel/src/pages/content/index.jsx` | React page: index | + + +## `sova-adminpanel/src/routes/` + + +| Файл | Назначение | +|------|------------| +| `sova-adminpanel/src/routes/ProtectedRoute.jsx` | React-компонент | + + +## `sova-adminpanel/src/routes/__test__/` + + +| Файл | Назначение | +|------|------------| +| `sova-adminpanel/src/routes/__test__/ProtectedRoute.test.js` | JavaScript | + + +## `sova-adminpanel/src/store/` + + +| Файл | Назначение | +|------|------------| +| `sova-adminpanel/src/store/store.js` | JavaScript | + + +## `sova-adminpanel/src/store/slice/` + + +| Файл | Назначение | +|------|------------| +| `sova-adminpanel/src/store/slice/authSlice.js` | JavaScript | +| `sova-adminpanel/src/store/slice/regionSlice.js` | JavaScript | +| `sova-adminpanel/src/store/slice/utilsSlice.js` | JavaScript | + + +## `sova-adminpanel/src/store/slice/__test__/` + + +| Файл | Назначение | +|------|------------| +| `sova-adminpanel/src/store/slice/__test__/authSlice.test.js` | JavaScript | + + +## `sova-adminpanel/src/styles/` + + +| Файл | Назначение | +|------|------------| +| `sova-adminpanel/src/styles/_colors.scss` | SCSS-стили | +| `sova-adminpanel/src/styles/theme-override.scss` | SCSS-стили | + + +## `sova-adminpanel/src/utils/` + + +| Файл | Назначение | +|------|------------| +| `sova-adminpanel/src/utils/parseSaveError.js` | JavaScript | diff --git a/infrastructure/test-contour/k3s-test-reference/sova-backend.md b/infrastructure/test-contour/k3s-test-reference/sova-backend.md new file mode 100644 index 0000000..c6421b3 --- /dev/null +++ b/infrastructure/test-contour/k3s-test-reference/sova-backend.md @@ -0,0 +1,751 @@ +# sova-backend: Symfony API + +Backend API для adminpanel и интеграций. Копия из monorepo + test-специфичные правки. + +**Файлов:** 277 + + +## `sova-backend/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/.cursorignore ` | Файл проекта | +| `sova-backend/.editorconfig` | Файл проекта | +| `sova-backend/.env.ci` | Файл проекта | +| `sova-backend/.env.dev` | Файл проекта | +| `sova-backend/.env.test` | Файл проекта | +| `sova-backend/.gitignore` | Git ignore rules | +| `sova-backend/Dockerfile` | Docker multistage build | +| `sova-backend/compose.override.yaml` | Локальные overrides Compose | +| `sova-backend/compose.yaml` | Docker Compose (Symfony) | +| `sova-backend/composer.json` | PHP Composer зависимости | +| `sova-backend/importmap.php` | PHP (Symfony) | +| `sova-backend/issues-27.html` | HTML | +| `sova-backend/mr.diff` | Файл проекта | +| `sova-backend/phpunit.dist.xml` | XML-конфиг | + + +## `sova-backend/.gitea/workflows/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/.gitea/workflows/build.yml` | Gitea Actions CI pipeline | + + +## `sova-backend/assets/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/assets/app.js` | JavaScript | +| `sova-backend/assets/bootstrap.js` | JavaScript | +| `sova-backend/assets/controllers.json` | JSON-данные / конфиг | +| `sova-backend/assets/stimulus_bootstrap.js` | JavaScript | + + +## `sova-backend/assets/controllers/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/assets/controllers/csrf_protection_controller.js` | Stimulus controller: csrf_protection | +| `sova-backend/assets/controllers/hello_controller.js` | Stimulus controller: hello | + + +## `sova-backend/assets/styles/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/assets/styles/app.css` | CSS-стили | + + +## `sova-backend/bin/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/bin/console` | Symfony CLI entry | +| `sova-backend/bin/phpunit` | PHPUnit runner wrapper | + + +## `sova-backend/config/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/config/bundles.php` | PHP (Symfony) | +| `sova-backend/config/preload.php` | PHP (Symfony) | +| `sova-backend/config/reference.php` | PHP (Symfony) | +| `sova-backend/config/routes.yaml` | YAML-конфиг / Helm / K8s | +| `sova-backend/config/services.php` | PHP DI bindings по APP_ENV | +| `sova-backend/config/services.yaml` | YAML-конфиг / Helm / K8s | +| `sova-backend/config/services_stub.yaml` | Stub-клиенты SMS/Calltouch/Captcha для test | + + +## `sova-backend/config/packages/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/config/packages/asset_mapper.yaml` | Symfony bundle config: asset_mapper.yaml | +| `sova-backend/config/packages/cache.yaml` | Symfony bundle config: cache.yaml | +| `sova-backend/config/packages/csrf.yaml` | Symfony bundle config: csrf.yaml | +| `sova-backend/config/packages/debug.yaml` | Symfony bundle config: debug.yaml | +| `sova-backend/config/packages/doctrine.yaml` | Symfony bundle config: doctrine.yaml | +| `sova-backend/config/packages/doctrine_migrations.yaml` | Symfony bundle config: doctrine_migrations.yaml | +| `sova-backend/config/packages/framework.yaml` | Symfony bundle config: framework.yaml | +| `sova-backend/config/packages/lexik_jwt_authentication.yaml` | Symfony bundle config: lexik_jwt_authentication.yaml | +| `sova-backend/config/packages/lock.yaml` | Symfony bundle config: lock.yaml | +| `sova-backend/config/packages/mailer.yaml` | Symfony bundle config: mailer.yaml | +| `sova-backend/config/packages/messenger.yaml` | Symfony bundle config: messenger.yaml | +| `sova-backend/config/packages/monolog.yaml` | Symfony bundle config: monolog.yaml | +| `sova-backend/config/packages/nelmio_api_doc.yaml` | Symfony bundle config: nelmio_api_doc.yaml | +| `sova-backend/config/packages/nelmio_cors.yaml` | Symfony bundle config: nelmio_cors.yaml | +| `sova-backend/config/packages/notifier.yaml` | Symfony bundle config: notifier.yaml | +| `sova-backend/config/packages/property_info.yaml` | Symfony bundle config: property_info.yaml | +| `sova-backend/config/packages/routing.yaml` | Symfony bundle config: routing.yaml | +| `sova-backend/config/packages/scheduler.yaml` | Symfony bundle config: scheduler.yaml | +| `sova-backend/config/packages/security.yaml` | Symfony bundle config: security.yaml | +| `sova-backend/config/packages/serializer.yaml` | Symfony bundle config: serializer.yaml | +| `sova-backend/config/packages/translation.yaml` | Symfony bundle config: translation.yaml | +| `sova-backend/config/packages/twig.yaml` | Symfony bundle config: twig.yaml | +| `sova-backend/config/packages/ux_turbo.yaml` | Symfony bundle config: ux_turbo.yaml | +| `sova-backend/config/packages/validator.yaml` | Symfony bundle config: validator.yaml | +| `sova-backend/config/packages/web_profiler.yaml` | Symfony bundle config: web_profiler.yaml | + + +## `sova-backend/config/packages/dev/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/config/packages/dev/web_profiler.yaml` | Symfony bundle config: web_profiler.yaml | + + +## `sova-backend/config/routes/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/config/routes/framework.yaml` | YAML-конфиг / Helm / K8s | +| `sova-backend/config/routes/nelmio_api_doc.yaml` | YAML-конфиг / Helm / K8s | +| `sova-backend/config/routes/security.yaml` | YAML-конфиг / Helm / K8s | +| `sova-backend/config/routes/web_profiler.yaml` | YAML-конфиг / Helm / K8s | + + +## `sova-backend/docker/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/docker/fpm-pool.conf` | Файл проекта | + + +## `sova-backend/docker/nginx/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/docker/nginx/default.conf` | Файл проекта | + + +## `sova-backend/migrations/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/migrations/.gitignore` | Git ignore rules | +| `sova-backend/migrations/Version20260213132749.php` | Doctrine migration | +| `sova-backend/migrations/Version20260213132759.php` | Doctrine migration | +| `sova-backend/migrations/Version20260311212936.php` | Doctrine migration | +| `sova-backend/migrations/Version20260417120000.php` | Doctrine migration | +| `sova-backend/migrations/Version20260515142000.php` | Doctrine migration | + + +## `sova-backend/public/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/public/favicon.ico` | Favicon | +| `sova-backend/public/index.php` | HTTP front controller Symfony | +| `sova-backend/public/robots.txt` | Файл проекта | +| `sova-backend/public/swagger.json` | JSON-данные / конфиг | + + +## `sova-backend/public/images/logo/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/public/images/logo/comfort.jpg` | JPEG-изображение | +| `sova-backend/public/images/logo/sovamed.png` | PNG-изображение | +| `sova-backend/public/images/logo/sovenok.png` | PNG-изображение | +| `sova-backend/public/images/logo/wmtmed.png` | PNG-изображение | + + +## `sova-backend/src/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Kernel.php` | PHP (Symfony) | +| `sova-backend/src/Schedule.php` | PHP (Symfony) | + + +## `sova-backend/src/Command/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Command/BitrixUpdateDoctorsCommand.php` | Console command: BitrixUpdateDoctorsCommand | +| `sova-backend/src/Command/BitrixUpdateReviewsCommand.php` | Console command: BitrixUpdateReviewsCommand | +| `sova-backend/src/Command/ClearScheduleCacheCommand.php` | Console command: ClearScheduleCacheCommand | +| `sova-backend/src/Command/UploadDepartmentsCommand.php` | Console command: UploadDepartmentsCommand | +| `sova-backend/src/Command/UploadDiseasesCommand.php` | Console command: UploadDiseasesCommand | +| `sova-backend/src/Command/UploadDoctorsCommand.php` | Console command: UploadDoctorsCommand | +| `sova-backend/src/Command/UploadFilialsCommand.php` | Console command: UploadFilialsCommand | +| `sova-backend/src/Command/UploadMedicalCentersCommand.php` | Console command: UploadMedicalCentersCommand | +| `sova-backend/src/Command/UploadNewsCommand.php` | Console command: UploadNewsCommand | +| `sova-backend/src/Command/UploadPriceCommand.php` | Console command: UploadPriceCommand | +| `sova-backend/src/Command/UploadPriceDepCommand.php` | Console command: UploadPriceDepCommand | +| `sova-backend/src/Command/UploadPromoCommand.php` | Console command: UploadPromoCommand | +| `sova-backend/src/Command/UploadSiteServicesCommand.php` | Console command: UploadSiteServicesCommand | + + +## `sova-backend/src/Controller/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Controller/.gitignore` | Git ignore rules | +| `sova-backend/src/Controller/ArticleController.php` | Symfony controller: ArticleController | +| `sova-backend/src/Controller/CalltouchController.php` | Symfony controller: CalltouchController | +| `sova-backend/src/Controller/DefaultController.php` | Symfony controller: DefaultController | +| `sova-backend/src/Controller/DepartmentController.php` | Symfony controller: DepartmentController | +| `sova-backend/src/Controller/DiseaseController.php` | Symfony controller: DiseaseController | +| `sova-backend/src/Controller/FilialController.php` | Symfony controller: FilialController | +| `sova-backend/src/Controller/HelperController.php` | Symfony controller: HelperController | +| `sova-backend/src/Controller/InfoclinicaController.php` | Symfony controller: InfoclinicaController | +| `sova-backend/src/Controller/LocationController.php` | Symfony controller: LocationController | +| `sova-backend/src/Controller/MedicalCenterController.php` | Symfony controller: MedicalCenterController | +| `sova-backend/src/Controller/NewsController.php` | Symfony controller: NewsController | +| `sova-backend/src/Controller/PriceDepartmentController.php` | Symfony controller: PriceDepartmentController | +| `sova-backend/src/Controller/PriceListController.php` | Symfony controller: PriceListController | +| `sova-backend/src/Controller/PromoController.php` | Symfony controller: PromoController | +| `sova-backend/src/Controller/ReviewController.php` | Symfony controller: ReviewController | +| `sova-backend/src/Controller/ServiceController.php` | Symfony controller: ServiceController | +| `sova-backend/src/Controller/SiteServiceController.php` | Symfony controller: SiteServiceController | +| `sova-backend/src/Controller/SpecialistController.php` | Symfony controller: SpecialistController | +| `sova-backend/src/Controller/SpecialistDcodeDescriptionController.php` | Symfony controller: SpecialistDcodeDescriptionController | +| `sova-backend/src/Controller/SpecialistDocsController.php` | Symfony controller: SpecialistDocsController | +| `sova-backend/src/Controller/StockController.php` | Symfony controller: StockController | +| `sova-backend/src/Controller/UserController.php` | Symfony controller: UserController | +| `sova-backend/src/Controller/UsrlogController.php` | Symfony controller: UsrlogController | +| `sova-backend/src/Controller/WebGetDocinfoController.php` | Symfony controller: WebGetDocinfoController | +| `sova-backend/src/Controller/XmlFeedController.php` | Symfony controller: XmlFeedController | + + +## `sova-backend/src/Dto/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Dto/AnonymousReserveRequestDto.php` | DTO: AnonymousReserveRequestDto | +| `sova-backend/src/Dto/CalltouchCreateRequestDto.php` | DTO: CalltouchCreateRequestDto | +| `sova-backend/src/Dto/FileUploadDto.php` | DTO: FileUploadDto | +| `sova-backend/src/Dto/RegionDto.php` | DTO: RegionDto | +| `sova-backend/src/Dto/RegistrationDto.php` | DTO: RegistrationDto | +| `sova-backend/src/Dto/ReviewInputDto.php` | DTO: ReviewInputDto | +| `sova-backend/src/Dto/ScheduleDayDto.php` | DTO: ScheduleDayDto | +| `sova-backend/src/Dto/ScheduleDto.php` | DTO: ScheduleDto | +| `sova-backend/src/Dto/SpecialistFilterDto.php` | DTO: SpecialistFilterDto | +| `sova-backend/src/Dto/UserAuthDto.php` | DTO: UserAuthDto | +| `sova-backend/src/Dto/UserLoginDto.php` | DTO: UserLoginDto | +| `sova-backend/src/Dto/UserUidAuthDto.php` | DTO: UserUidAuthDto | + + +## `sova-backend/src/Dto/Content/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Dto/Content/ContentFilterDto.php` | DTO: ContentFilterDto | + + +## `sova-backend/src/Entity/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Entity/.gitignore` | Git ignore rules | +| `sova-backend/src/Entity/AlertSms.php` | Doctrine entity: AlertSms | +| `sova-backend/src/Entity/Article.php` | Doctrine entity: Article | +| `sova-backend/src/Entity/Banner.php` | Doctrine entity: Banner | +| `sova-backend/src/Entity/Department.php` | Doctrine entity: Department | +| `sova-backend/src/Entity/Disease.php` | Doctrine entity: Disease | +| `sova-backend/src/Entity/Filial.php` | Doctrine entity: Filial | +| `sova-backend/src/Entity/Idoctor.php` | Doctrine entity: Idoctor | +| `sova-backend/src/Entity/Location.php` | Doctrine entity: Location | +| `sova-backend/src/Entity/MarkKiosk.php` | Doctrine entity: MarkKiosk | +| `sova-backend/src/Entity/MedicalCenter.php` | Doctrine entity: MedicalCenter | +| `sova-backend/src/Entity/News.php` | Doctrine entity: News | +| `sova-backend/src/Entity/PriceDepartment.php` | Doctrine entity: PriceDepartment | +| `sova-backend/src/Entity/PriceList.php` | Doctrine entity: PriceList | +| `sova-backend/src/Entity/Promo.php` | Doctrine entity: Promo | +| `sova-backend/src/Entity/Record.php` | Doctrine entity: Record | +| `sova-backend/src/Entity/Review.php` | Doctrine entity: Review | +| `sova-backend/src/Entity/Schedule.php` | Doctrine entity: Schedule | +| `sova-backend/src/Entity/SiteService.php` | Doctrine entity: SiteService | +| `sova-backend/src/Entity/Specialist.php` | Doctrine entity: Specialist | +| `sova-backend/src/Entity/SpecialistDcodeDescription.php` | Doctrine entity: SpecialistDcodeDescription | +| `sova-backend/src/Entity/SpecialistDocs.php` | Doctrine entity: SpecialistDocs | +| `sova-backend/src/Entity/Stock.php` | Doctrine entity: Stock | +| `sova-backend/src/Entity/User.php` | Doctrine entity: User | +| `sova-backend/src/Entity/WebGetDocinfo.php` | Doctrine entity: WebGetDocinfo | +| `sova-backend/src/Entity/WidgetForm.php` | Doctrine entity: WidgetForm | +| `sova-backend/src/Entity/WidgetFormInput.php` | Doctrine entity: WidgetFormInput | + + +## `sova-backend/src/Entity/Behavior/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Entity/Behavior/UpdateTimestampTrait.php` | Doctrine entity: UpdateTimestampTrait | + + +## `sova-backend/src/EventListener/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/EventListener/JsonExceptionHandler.php` | PHP (Symfony) | + + +## `sova-backend/src/Form/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Form/WidgetFormInputType.php` | Form type: WidgetFormInputType | +| `sova-backend/src/Form/WidgetFormType.php` | Form type: WidgetFormType | + + +## `sova-backend/src/Message/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Message/GetAnonymousReserveRequestMessage.php` | Messenger message: GetAnonymousReserveRequestMessage | +| `sova-backend/src/Message/GetScheduleMessage.php` | Messenger message: GetScheduleMessage | +| `sova-backend/src/Message/GetSpecialistPictureMessage.php` | Messenger message: GetSpecialistPictureMessage | + + +## `sova-backend/src/MessageHandler/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/MessageHandler/GetAnonymousReserveRequestMessageHandler.php` | Messenger handler: GetAnonymousReserveRequestMessageHandler | +| `sova-backend/src/MessageHandler/GetScheduleMessageHandler.php` | Messenger handler: GetScheduleMessageHandler | +| `sova-backend/src/MessageHandler/GetSpecialistPictureMessageHandler.php` | Messenger handler: GetSpecialistPictureMessageHandler | + + +## `sova-backend/src/Repository/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Repository/.gitignore` | Git ignore rules | +| `sova-backend/src/Repository/AlertSmsRepository.php` | Doctrine repository: AlertSmsRepository | +| `sova-backend/src/Repository/ArticleRepository.php` | Doctrine repository: ArticleRepository | +| `sova-backend/src/Repository/BannerRepository.php` | Doctrine repository: BannerRepository | +| `sova-backend/src/Repository/ContentFilterTrait.php` | Doctrine repository: ContentFilterTrait | +| `sova-backend/src/Repository/DepartmentRepository.php` | Doctrine repository: DepartmentRepository | +| `sova-backend/src/Repository/DiseaseRepository.php` | Doctrine repository: DiseaseRepository | +| `sova-backend/src/Repository/FilialRepository.php` | Doctrine repository: FilialRepository | +| `sova-backend/src/Repository/IdoctorRepository.php` | Doctrine repository: IdoctorRepository | +| `sova-backend/src/Repository/LocationRepository.php` | Doctrine repository: LocationRepository | +| `sova-backend/src/Repository/MarkKioskRepository.php` | Doctrine repository: MarkKioskRepository | +| `sova-backend/src/Repository/MedicalCenterRepository.php` | Doctrine repository: MedicalCenterRepository | +| `sova-backend/src/Repository/NewsRepository.php` | Doctrine repository: NewsRepository | +| `sova-backend/src/Repository/PriceDepartmentRepository.php` | Doctrine repository: PriceDepartmentRepository | +| `sova-backend/src/Repository/PriceListRepository.php` | Doctrine repository: PriceListRepository | +| `sova-backend/src/Repository/PromoRepository.php` | Doctrine repository: PromoRepository | +| `sova-backend/src/Repository/RecordRepository.php` | Doctrine repository: RecordRepository | +| `sova-backend/src/Repository/ReviewRepository.php` | Doctrine repository: ReviewRepository | +| `sova-backend/src/Repository/ScheduleRepository.php` | Doctrine repository: ScheduleRepository | +| `sova-backend/src/Repository/SiteServiceRepository.php` | Doctrine repository: SiteServiceRepository | +| `sova-backend/src/Repository/SpecialistDcodeDescriptionRepository.php` | Doctrine repository: SpecialistDcodeDescriptionRepository | +| `sova-backend/src/Repository/SpecialistDocsRepository.php` | Doctrine repository: SpecialistDocsRepository | +| `sova-backend/src/Repository/SpecialistRepository.php` | Doctrine repository: SpecialistRepository | +| `sova-backend/src/Repository/StockRepository.php` | Doctrine repository: StockRepository | +| `sova-backend/src/Repository/UserRepository.php` | Doctrine repository: UserRepository | +| `sova-backend/src/Repository/WebGetDocinfoRepository.php` | Doctrine repository: WebGetDocinfoRepository | +| `sova-backend/src/Repository/WidgetFormInputRepository.php` | Doctrine repository: WidgetFormInputRepository | +| `sova-backend/src/Repository/WidgetFormRepository.php` | Doctrine repository: WidgetFormRepository | + + +## `sova-backend/src/Serializer/Normalizer/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Serializer/Normalizer/FilialNormalizer.php` | PHP (Symfony) | +| `sova-backend/src/Serializer/Normalizer/SpecialistDocsNormalizer.php` | PHP (Symfony) | +| `sova-backend/src/Serializer/Normalizer/SpecialistNormalizer.php` | PHP (Symfony) | +| `sova-backend/src/Serializer/Normalizer/StockNormalizer.php` | PHP (Symfony) | + + +## `sova-backend/src/Service/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Service/DiseaseCrudService.php` | Service: DiseaseCrudService | +| `sova-backend/src/Service/MedicalCenterCrudService.php` | Service: MedicalCenterCrudService | +| `sova-backend/src/Service/NewsCrudService.php` | Service: NewsCrudService | +| `sova-backend/src/Service/PromoCrudService.php` | Service: PromoCrudService | +| `sova-backend/src/Service/SiteServiceCrudService.php` | Service: SiteServiceCrudService | + + +## `sova-backend/src/Service/Bitrix/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Service/Bitrix/BitrixService.php` | Service: BitrixService | + + +## `sova-backend/src/Service/Client/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Service/Client/AbstractHttpClientService.php` | Service: AbstractHttpClientService | +| `sova-backend/src/Service/Client/BitrixClientService.php` | Service: BitrixClientService | +| `sova-backend/src/Service/Client/CalltouchClientService.php` | Service: CalltouchClientService | +| `sova-backend/src/Service/Client/InfoclinicaClientService.php` | Service: InfoclinicaClientService | +| `sova-backend/src/Service/Client/SmartCaptchaClientService.php` | Service: SmartCaptchaClientService | +| `sova-backend/src/Service/Client/Sms4bClientService.php` | Service: Sms4bClientService | +| `sova-backend/src/Service/Client/SmsruClientService.php` | Service: SmsruClientService | + + +## `sova-backend/src/Service/Client/Interfaces/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Service/Client/Interfaces/AbstractHttpClientServiceInterface.php` | Service: AbstractHttpClientServiceInterface | +| `sova-backend/src/Service/Client/Interfaces/BitrixClientServiceInterface.php` | Service: BitrixClientServiceInterface | +| `sova-backend/src/Service/Client/Interfaces/CalltouchClientServiceInterface.php` | Service: CalltouchClientServiceInterface | +| `sova-backend/src/Service/Client/Interfaces/InfoclinicaClientServiceInterface.php` | Service: InfoclinicaClientServiceInterface | +| `sova-backend/src/Service/Client/Interfaces/SmartCaptchaClientServiceInterface.php` | Service: SmartCaptchaClientServiceInterface | +| `sova-backend/src/Service/Client/Interfaces/SmsClientServiceInterface.php` | Service: SmsClientServiceInterface | + + +## `sova-backend/src/Service/Client/Stub/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Service/Client/Stub/AlwaysValidSmartCaptchaClientService.php` | Service: AlwaysValidSmartCaptchaClientService | +| `sova-backend/src/Service/Client/Stub/NoopCalltouchClientService.php` | Service: NoopCalltouchClientService | +| `sova-backend/src/Service/Client/Stub/NoopSmsClientService.php` | Service: NoopSmsClientService | + + +## `sova-backend/src/Service/Crud/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Service/Crud/CrudResponder.php` | Service: CrudResponder | + + +## `sova-backend/src/Service/Crypt/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Service/Crypt/AESCryptService.php` | Service: AESCryptService | + + +## `sova-backend/src/Service/Crypt/Interfaces/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Service/Crypt/Interfaces/AESCryptServiceInterface.php` | Service: AESCryptServiceInterface | + + +## `sova-backend/src/Service/DecoderJWT/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Service/DecoderJWT/JWTDecoderService.php` | Service: JWTDecoderService | + + +## `sova-backend/src/Service/DecoderJWT/Interfaces/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Service/DecoderJWT/Interfaces/JWTDecoderServiceInterface.php` | Service: JWTDecoderServiceInterface | + + +## `sova-backend/src/Service/Department/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Service/Department/DepartmentService.php` | Service: DepartmentService | + + +## `sova-backend/src/Service/ErrorHandler/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Service/ErrorHandler/ScheduleErrorHandlerService.php` | Service: ScheduleErrorHandlerService | + + +## `sova-backend/src/Service/FileUploader/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Service/FileUploader/FileUploaderService.php` | Service: FileUploaderService | + + +## `sova-backend/src/Service/FileUploader/Interfaces/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Service/FileUploader/Interfaces/FileUploaderServiceInterface.php` | Service: FileUploaderServiceInterface | + + +## `sova-backend/src/Service/Filial/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Service/Filial/FilialService.php` | Service: FilialService | + + +## `sova-backend/src/Service/Helper/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Service/Helper/HelperService.php` | Service: HelperService | + + +## `sova-backend/src/Service/Image/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Service/Image/ImageService.php` | Service: ImageService | + + +## `sova-backend/src/Service/Image/Interfaces/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Service/Image/Interfaces/ImageServiceInterface.php` | Service: ImageServiceInterface | + + +## `sova-backend/src/Service/Location/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Service/Location/LocationService.php` | Service: LocationService | + + +## `sova-backend/src/Service/Mail/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Service/Mail/SendMailConfig.php` | Service: SendMailConfig | +| `sova-backend/src/Service/Mail/SendMailService.php` | Service: SendMailService | + + +## `sova-backend/src/Service/Pagination/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Service/Pagination/Paginator.php` | Service: Paginator | + + +## `sova-backend/src/Service/Performance/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Service/Performance/PerformanceTrackerService.php` | Service: PerformanceTrackerService | + + +## `sova-backend/src/Service/PriceList/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Service/PriceList/PriceListService.php` | Service: PriceListService | + + +## `sova-backend/src/Service/ScheduleCache/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Service/ScheduleCache/ScheduleCacheService.php` | Service: ScheduleCacheService | + + +## `sova-backend/src/Service/Sequence/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Service/Sequence/SequenceService.php` | Service: SequenceService | + + +## `sova-backend/src/Service/Specialist/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Service/Specialist/SpecialistService.php` | Service: SpecialistService | + + +## `sova-backend/src/Service/Specialist/Interfaces/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Service/Specialist/Interfaces/SpecialistServiceInterface.php` | Service: SpecialistServiceInterface | + + +## `sova-backend/src/Service/Translite/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Service/Translite/TransliteService.php` | Service: TransliteService | + + +## `sova-backend/src/Service/Translite/Interfaces/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Service/Translite/Interfaces/TransliteServiceInterface.php` | Service: TransliteServiceInterface | + + +## `sova-backend/src/Service/User/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Service/User/AuthenticationService.php` | Service: AuthenticationService | +| `sova-backend/src/Service/User/RegistrationService.php` | Service: RegistrationService | +| `sova-backend/src/Service/User/UserProfileService.php` | Service: UserProfileService | + + +## `sova-backend/src/Service/User/Interfaces/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Service/User/Interfaces/AuthenticationServiceInterface.php` | Service: AuthenticationServiceInterface | +| `sova-backend/src/Service/User/Interfaces/RegistrationServiceInterface.php` | Service: RegistrationServiceInterface | +| `sova-backend/src/Service/User/Interfaces/UserProfileServiceInterface.php` | Service: UserProfileServiceInterface | + + +## `sova-backend/src/Service/XmlFeedGenerator/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/src/Service/XmlFeedGenerator/XmlFeedGeneratorService.php` | Service: XmlFeedGeneratorService | +| `sova-backend/src/Service/XmlFeedGenerator/XmlFeedGeneratorV1Service.php` | Service: XmlFeedGeneratorV1Service | + + +## `sova-backend/templates/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/templates/base.html.twig` | Twig template: base.html.twig | +| `sova-backend/templates/base_plain.html.twig` | Twig template: base_plain.html.twig | + + +## `sova-backend/templates/bundles/NelmioApiDocBundle/SwaggerUi/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/templates/bundles/NelmioApiDocBundle/SwaggerUi/index.html.twig` | Twig template: bundles/NelmioApiDocBundle/SwaggerUi/index.html.twig | + + +## `sova-backend/templates/service/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/templates/service/comingsoon.html.twig` | Twig template: service/comingsoon.html.twig | + + +## `sova-backend/tests/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/tests/bootstrap.php` | PHP (Symfony) | + + +## `sova-backend/tests/Controller/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/tests/Controller/CalltouchControllerTest.php` | Symfony controller: CalltouchControllerTest | +| `sova-backend/tests/Controller/CertificateControllerTest.php` | Symfony controller: CertificateControllerTest | +| `sova-backend/tests/Controller/InfoclinicaControllerTest.php` | Symfony controller: InfoclinicaControllerTest | +| `sova-backend/tests/Controller/InfoclinicaDoctorControllerTest.php` | Symfony controller: InfoclinicaDoctorControllerTest | +| `sova-backend/tests/Controller/LocationControllerTest.php` | Symfony controller: LocationControllerTest | +| `sova-backend/tests/Controller/ServiceControllerTest.php` | Symfony controller: ServiceControllerTest | +| `sova-backend/tests/Controller/StockControllerTest.php` | Symfony controller: StockControllerTest | + + +## `sova-backend/tests/Service/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/tests/Service/AESCryptServiceTest.php` | Service: AESCryptServiceTest | +| `sova-backend/tests/Service/BitrixServiceTest.php` | Service: BitrixServiceTest | +| `sova-backend/tests/Service/CalltouchClientServiceTest.php` | Service: CalltouchClientServiceTest | +| `sova-backend/tests/Service/ImageServiceTest.php` | Service: ImageServiceTest | +| `sova-backend/tests/Service/InfoclinicaClientServiceTest.php` | Service: InfoclinicaClientServiceTest | +| `sova-backend/tests/Service/MessageSenderServiceTest.php` | Service: MessageSenderServiceTest | +| `sova-backend/tests/Service/SchedulerTransportTest.php` | Service: SchedulerTransportTest | +| `sova-backend/tests/Service/Sms4bClientServiceTest.php` | Service: Sms4bClientServiceTest | +| `sova-backend/tests/Service/SmsruClientServiceTest.php` | Service: SmsruClientServiceTest | + + +## `sova-backend/translations/` + + +| Файл | Назначение | +|------|------------| +| `sova-backend/translations/.gitignore` | Git ignore rules | diff --git a/infrastructure/test-contour/k3s-test-reference/sova-cabinet.md b/infrastructure/test-contour/k3s-test-reference/sova-cabinet.md new file mode 100644 index 0000000..67b2bb2 --- /dev/null +++ b/infrastructure/test-contour/k3s-test-reference/sova-cabinet.md @@ -0,0 +1,888 @@ +# sova-cabinet: Symfony ЛК + +Личный кабинет пациента: регистрация, запись, оплата. + +**Файлов:** 428 + + +## `sova-cabinet/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/.env` | Файл проекта | +| `sova-cabinet/.env.ci` | Файл проекта | +| `sova-cabinet/.env.dev` | Файл проекта | +| `sova-cabinet/.env.test` | Файл проекта | +| `sova-cabinet/.gitignore` | Git ignore rules | +| `sova-cabinet/.phpunit.result.cache` | Файл проекта | +| `sova-cabinet/Dockerfile` | Docker multistage build | +| `sova-cabinet/composer.json` | PHP Composer зависимости | +| `sova-cabinet/composer.lock` | Composer lockfile | +| `sova-cabinet/docker-compose.yml` | Docker Compose (моки / cabinet dev) | +| `sova-cabinet/issues-27.html` | HTML | +| `sova-cabinet/mr.diff` | Файл проекта | +| `sova-cabinet/package.json` | NPM/Yarn зависимости и scripts | +| `sova-cabinet/phpunit.xml.dist` | Файл проекта | +| `sova-cabinet/symfony.lock` | Lockfile (Helm/composer/yarn) | +| `sova-cabinet/webpack.config.js` | Webpack Encore конфиг | +| `sova-cabinet/yarn.lock` | Yarn lockfile | + + +## `sova-cabinet/.gitea/workflows/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/.gitea/workflows/build.yml` | Gitea Actions CI pipeline | + + +## `sova-cabinet/assets/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/assets/bootstrap.js` | JavaScript | +| `sova-cabinet/assets/controllers.json` | JSON-данные / конфиг | +| `sova-cabinet/assets/loader_bitrix.js` | JavaScript | +| `sova-cabinet/assets/loader_sovamed.js` | JavaScript | +| `sova-cabinet/assets/loader_widget.js` | JavaScript | +| `sova-cabinet/assets/loader_wmtmed.js` | JavaScript | +| `sova-cabinet/assets/window.js` | JavaScript | + + +## `sova-cabinet/assets/components/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/assets/components/helper.js` | JavaScript | +| `sova-cabinet/assets/components/loader.js` | JavaScript | +| `sova-cabinet/assets/components/misSession.js` | JavaScript | +| `sova-cabinet/assets/components/onlineMode.js` | JavaScript | +| `sova-cabinet/assets/components/record.js` | JavaScript | +| `sova-cabinet/assets/components/testSdk.js` | Stub WrSDK/SmartCaptcha для *.sova.local | +| `sova-cabinet/assets/components/validator.js` | JavaScript | + + +## `sova-cabinet/assets/controllers/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/assets/controllers/alertSystem_controller.js` | Stimulus controller: alertSystem | +| `sova-cabinet/assets/controllers/bannersRegion_controller.js` | Stimulus controller: bannersRegion | +| `sova-cabinet/assets/controllers/calendar_controller.js` | Stimulus controller: calendar | +| `sova-cabinet/assets/controllers/caseHistory_controller.js` | Stimulus controller: caseHistory | +| `sova-cabinet/assets/controllers/changePatient_controller.js` | Stimulus controller: changePatient | +| `sova-cabinet/assets/controllers/changeRegion_controller.js` | Stimulus controller: changeRegion | +| `sova-cabinet/assets/controllers/checkScheduleBitrix_controller.js` | Stimulus controller: checkScheduleBitrix | +| `sova-cabinet/assets/controllers/checkSchedule_controller.js` | Stimulus controller: checkSchedule | +| `sova-cabinet/assets/controllers/cookieNotice_controller.js` | Stimulus controller: cookieNotice | +| `sova-cabinet/assets/controllers/datePicker_controller.js` | Stimulus controller: datePicker | +| `sova-cabinet/assets/controllers/docYuorHome_controller.js` | Stimulus controller: docYuorHome | +| `sova-cabinet/assets/controllers/doc_controller.js` | Stimulus controller: doc | +| `sova-cabinet/assets/controllers/favoritesBtn_controller.js` | Stimulus controller: favoritesBtn | +| `sova-cabinet/assets/controllers/favoritesNaw_controller.js` | Stimulus controller: favoritesNaw | +| `sova-cabinet/assets/controllers/favorites_controller.js` | Stimulus controller: favorites | +| `sova-cabinet/assets/controllers/filterMenu_controller.js` | Stimulus controller: filterMenu | +| `sova-cabinet/assets/controllers/inputMask_controller.js` | Stimulus controller: inputMask | +| `sova-cabinet/assets/controllers/jivo_controller.js` | Stimulus controller: jivo | +| `sova-cabinet/assets/controllers/kinderFilter_controller.js` | Stimulus controller: kinderFilter | +| `sova-cabinet/assets/controllers/menu_controller.js` | Stimulus controller: menu | +| `sova-cabinet/assets/controllers/mobileSearchOrderByInput_controller.js` | Stimulus controller: mobileSearchOrderByInput | +| `sova-cabinet/assets/controllers/modal_controller.js` | Stimulus controller: modal | +| `sova-cabinet/assets/controllers/passwordShow_controller.js` | Stimulus controller: passwordShow | +| `sova-cabinet/assets/controllers/payment_controller.js` | Stimulus controller: payment | +| `sova-cabinet/assets/controllers/priceList_controller.js` | Stimulus controller: priceList | +| `sova-cabinet/assets/controllers/quickDateRange_controller.js` | Stimulus controller: quickDateRange | +| `sova-cabinet/assets/controllers/reference_controller.js` | Stimulus controller: reference | +| `sova-cabinet/assets/controllers/registration_controller.js` | Stimulus controller: registration | +| `sova-cabinet/assets/controllers/resetPassword_controller.js` | Stimulus controller: resetPassword | +| `sova-cabinet/assets/controllers/scrollTop_controller.js` | Stimulus controller: scrollTop | +| `sova-cabinet/assets/controllers/searchButton_controller.js` | Stimulus controller: searchButton | +| `sova-cabinet/assets/controllers/searchNameInput_controller.js` | Stimulus controller: searchNameInput | +| `sova-cabinet/assets/controllers/searchOrderByInput_controller.js` | Stimulus controller: searchOrderByInput | +| `sova-cabinet/assets/controllers/securityCard_controller.js` | Stimulus controller: securityCard | +| `sova-cabinet/assets/controllers/selectpicker_controller.js` | Stimulus controller: selectpicker | +| `sova-cabinet/assets/controllers/serviceDesk_controller.js` | Stimulus controller: serviceDesk | +| `sova-cabinet/assets/controllers/setting_controller.js` | Stimulus controller: setting | +| `sova-cabinet/assets/controllers/signin_controller.js` | Stimulus controller: signin | +| `sova-cabinet/assets/controllers/slideshow_controller.js` | Stimulus: lazy import owl.carousel | +| `sova-cabinet/assets/controllers/smartCaptcha_controller.js` | Stimulus controller: smartCaptcha | +| `sova-cabinet/assets/controllers/specialistView_controller.js` | Stimulus controller: specialistView | +| `sova-cabinet/assets/controllers/swaggerUI_controller.js` | Stimulus controller: swaggerUI | +| `sova-cabinet/assets/controllers/uslugi_controller.js` | Stimulus controller: uslugi | +| `sova-cabinet/assets/controllers/widgets_controller.js` | Stimulus controller: widgets | + + +## `sova-cabinet/assets/fonts/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/assets/fonts/Circe-Bold.eot` | Embedded OpenType font | +| `sova-cabinet/assets/fonts/Circe-Bold.ttf` | TrueType font | +| `sova-cabinet/assets/fonts/Circe-Bold.woff` | Web-font | +| `sova-cabinet/assets/fonts/Circe-ExtraBold.eot` | Embedded OpenType font | +| `sova-cabinet/assets/fonts/Circe-ExtraBold.ttf` | TrueType font | +| `sova-cabinet/assets/fonts/Circe-ExtraBold.woff` | Web-font | +| `sova-cabinet/assets/fonts/Circe-ExtraLight.eot` | Embedded OpenType font | +| `sova-cabinet/assets/fonts/Circe-ExtraLight.ttf` | TrueType font | +| `sova-cabinet/assets/fonts/Circe-ExtraLight.woff` | Web-font | +| `sova-cabinet/assets/fonts/Circe-Light.eot` | Embedded OpenType font | +| `sova-cabinet/assets/fonts/Circe-Light.ttf` | TrueType font | +| `sova-cabinet/assets/fonts/Circe-Light.woff` | Web-font | +| `sova-cabinet/assets/fonts/Circe-Regular.eot` | Embedded OpenType font | +| `sova-cabinet/assets/fonts/Circe-Regular.ttf` | TrueType font | +| `sova-cabinet/assets/fonts/Circe-Regular.woff` | Web-font | +| `sova-cabinet/assets/fonts/Circe-Thin.eot` | Embedded OpenType font | +| `sova-cabinet/assets/fonts/Circe-Thin.ttf` | TrueType font | +| `sova-cabinet/assets/fonts/Circe-Thin.woff` | Web-font | +| `sova-cabinet/assets/fonts/demo.html` | HTML | +| `sova-cabinet/assets/fonts/stylesheet.css` | CSS-стили | + + +## `sova-cabinet/assets/img/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/assets/img/3-staff.svg` | SVG-иконка / изображение | +| `sova-cabinet/assets/img/arrow-down.svg` | SVG-иконка / изображение | +| `sova-cabinet/assets/img/calendar-input.svg` | SVG-иконка / изображение | +| `sova-cabinet/assets/img/calendar.svg` | SVG-иконка / изображение | +| `sova-cabinet/assets/img/check.svg` | SVG-иконка / изображение | +| `sova-cabinet/assets/img/checkbox.svg` | SVG-иконка / изображение | +| `sova-cabinet/assets/img/checkbox_active.svg` | SVG-иконка / изображение | +| `sova-cabinet/assets/img/close.svg` | SVG-иконка / изображение | +| `sova-cabinet/assets/img/fake-img.jpg` | JPEG-изображение | +| `sova-cabinet/assets/img/favorites.svg` | SVG-иконка / изображение | +| `sova-cabinet/assets/img/filter-ico.svg` | SVG-иконка / изображение | +| `sova-cabinet/assets/img/filter.svg` | SVG-иконка / изображение | +| `sova-cabinet/assets/img/ny_top.png` | PNG-изображение | +| `sova-cabinet/assets/img/place.svg` | SVG-иконка / изображение | +| `sova-cabinet/assets/img/repeat-visit.svg` | SVG-иконка / изображение | +| `sova-cabinet/assets/img/search-ico.svg` | SVG-иконка / изображение | +| `sova-cabinet/assets/img/select-arrow-down.svg` | SVG-иконка / изображение | +| `sova-cabinet/assets/img/select-arrow-up.svg` | SVG-иконка / изображение | +| `sova-cabinet/assets/img/sova-bonus-logo.svg` | SVG-иконка / изображение | +| `sova-cabinet/assets/img/staff-icon.png` | PNG-изображение | +| `sova-cabinet/assets/img/up-arrow.svg` | SVG-иконка / изображение | +| `sova-cabinet/assets/img/user.svg` | SVG-иконка / изображение | + + +## `sova-cabinet/assets/sass/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/assets/sass/_fonts.scss` | SCSS entry: _fonts.scss | +| `sova-cabinet/assets/sass/bs4.scss` | SCSS entry: bs4.scss | +| `sova-cabinet/assets/sass/main.scss` | SCSS entry: main.scss | +| `sova-cabinet/assets/sass/main_bitrix.scss` | SCSS entry: main_bitrix.scss | +| `sova-cabinet/assets/sass/main_widget.scss` | SCSS entry: main_widget.scss | +| `sova-cabinet/assets/sass/main_wmtmed.scss` | SCSS entry: main_wmtmed.scss | + + +## `sova-cabinet/bin/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/bin/console` | Symfony CLI entry | +| `sova-cabinet/bin/phpunit` | PHPUnit runner wrapper | + + +## `sova-cabinet/config/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/config/bundles.php` | PHP (Symfony) | +| `sova-cabinet/config/preload.php` | PHP (Symfony) | +| `sova-cabinet/config/routes.yaml` | YAML-конфиг / Helm / K8s | +| `sova-cabinet/config/services.yaml` | YAML-конфиг / Helm / K8s | + + +## `sova-cabinet/config/packages/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/config/packages/assets.yaml` | Symfony bundle config: assets.yaml | +| `sova-cabinet/config/packages/cache.yaml` | Symfony bundle config: cache.yaml | +| `sova-cabinet/config/packages/doctrine.yaml` | Symfony bundle config: doctrine.yaml | +| `sova-cabinet/config/packages/doctrine_migrations.yaml` | Symfony bundle config: doctrine_migrations.yaml | +| `sova-cabinet/config/packages/framework.yaml` | Symfony bundle config: framework.yaml | +| `sova-cabinet/config/packages/knp_paginator.yaml` | Symfony bundle config: knp_paginator.yaml | +| `sova-cabinet/config/packages/mailer.yaml` | Symfony bundle config: mailer.yaml | +| `sova-cabinet/config/packages/nelmio_cors.yaml` | Symfony bundle config: nelmio_cors.yaml | +| `sova-cabinet/config/packages/notifier.yaml` | Symfony bundle config: notifier.yaml | +| `sova-cabinet/config/packages/routing.yaml` | Symfony bundle config: routing.yaml | +| `sova-cabinet/config/packages/security.yaml` | Symfony bundle config: security.yaml | +| `sova-cabinet/config/packages/sensio_framework_extra.yaml` | Symfony bundle config: sensio_framework_extra.yaml | +| `sova-cabinet/config/packages/translation.yaml` | Symfony bundle config: translation.yaml | +| `sova-cabinet/config/packages/twig.yaml` | Symfony bundle config: twig.yaml | +| `sova-cabinet/config/packages/validator.yaml` | Symfony bundle config: validator.yaml | +| `sova-cabinet/config/packages/webpack_encore.yaml` | Symfony bundle config: webpack_encore.yaml | + + +## `sova-cabinet/config/packages/dev/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/config/packages/dev/debug.yaml` | Symfony bundle config: debug.yaml | +| `sova-cabinet/config/packages/dev/monolog.yaml` | Symfony bundle config: monolog.yaml | +| `sova-cabinet/config/packages/dev/web_profiler.yaml` | Symfony bundle config: web_profiler.yaml | + + +## `sova-cabinet/config/packages/prod/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/config/packages/prod/deprecations.yaml` | Symfony bundle config: deprecations.yaml | +| `sova-cabinet/config/packages/prod/doctrine.yaml` | Symfony bundle config: doctrine.yaml | +| `sova-cabinet/config/packages/prod/monolog.yaml` | Symfony bundle config: monolog.yaml | +| `sova-cabinet/config/packages/prod/routing.yaml` | Symfony bundle config: routing.yaml | +| `sova-cabinet/config/packages/prod/webpack_encore.yaml` | Symfony bundle config: webpack_encore.yaml | + + +## `sova-cabinet/config/packages/test/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/config/packages/test/doctrine.yaml` | Symfony bundle config: doctrine.yaml | +| `sova-cabinet/config/packages/test/framework.yaml` | Symfony bundle config: framework.yaml | +| `sova-cabinet/config/packages/test/monolog.yaml` | Symfony bundle config: monolog.yaml | +| `sova-cabinet/config/packages/test/twig.yaml` | Symfony bundle config: twig.yaml | +| `sova-cabinet/config/packages/test/validator.yaml` | Symfony bundle config: validator.yaml | +| `sova-cabinet/config/packages/test/web_profiler.yaml` | Symfony bundle config: web_profiler.yaml | +| `sova-cabinet/config/packages/test/webpack_encore.yaml` | Symfony bundle config: webpack_encore.yaml | + + +## `sova-cabinet/config/routes/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/config/routes/annotations.yaml` | YAML-конфиг / Helm / K8s | + + +## `sova-cabinet/config/routes/dev/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/config/routes/dev/framework.yaml` | YAML-конфиг / Helm / K8s | +| `sova-cabinet/config/routes/dev/web_profiler.yaml` | YAML-конфиг / Helm / K8s | + + +## `sova-cabinet/docker/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/docker/fpm-pool.conf` | Файл проекта | + + +## `sova-cabinet/migrations/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/migrations/.gitignore` | Git ignore rules | +| `sova-cabinet/migrations/Version20250905084451.php` | Doctrine migration | +| `sova-cabinet/migrations/Version20250906131236.php` | Doctrine migration | +| `sova-cabinet/migrations/Version20250907100913.php` | Doctrine migration | + + +## `sova-cabinet/public/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/public/.htaccess` | Файл проекта | +| `sova-cabinet/public/comingSoon.php` | PHP (Symfony) | +| `sova-cabinet/public/favicon_sovamed.ico` | Favicon | +| `sova-cabinet/public/favicon_wmtmed.ico` | Favicon | +| `sova-cabinet/public/index.php` | HTTP front controller Symfony | +| `sova-cabinet/public/robots.txt` | Файл проекта | + + +## `sova-cabinet/public/comingSoon/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/public/comingSoon/bootstrap.min.css` | CSS-стили | + + +## `sova-cabinet/public/docs/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/public/docs/ids.pdf` | PDF-документ | +| `sova-cabinet/public/docs/oferta.pdf` | PDF-документ | +| `sova-cabinet/public/docs/online.pdf` | PDF-документ | +| `sova-cabinet/public/docs/onlinegos.pdf` | PDF-документ | +| `sova-cabinet/public/docs/soglasie-cabinet.pdf` | PDF-документ | +| `sova-cabinet/public/docs/soglasie-site.pdf` | PDF-документ | +| `sova-cabinet/public/docs/sovamed-cookie.pdf` | PDF-документ | +| `sova-cabinet/public/docs/vozvrat.pdf` | PDF-документ | +| `sova-cabinet/public/docs/wmtmed-cookie.pdf` | PDF-документ | + + +## `sova-cabinet/public/images/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/public/images/checkmark.png` | PNG-изображение | +| `sova-cabinet/public/images/eclipse.gif` | Файл проекта | +| `sova-cabinet/public/images/eisa.jpg` | JPEG-изображение | +| `sova-cabinet/public/images/logo-sova.jpg` | JPEG-изображение | +| `sova-cabinet/public/images/logo.png` | PNG-изображение | +| `sova-cabinet/public/images/logo.svg` | SVG-иконка / изображение | +| `sova-cabinet/public/images/logo_mobile.png` | PNG-изображение | +| `sova-cabinet/public/images/mobile-logo.svg` | SVG-иконка / изображение | +| `sova-cabinet/public/images/no_img.png` | PNG-изображение | + + +## `sova-cabinet/public/img/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/public/img/3-staff.svg` | SVG-иконка / изображение | +| `sova-cabinet/public/img/arrow-down.svg` | SVG-иконка / изображение | +| `sova-cabinet/public/img/calendar-input.svg` | SVG-иконка / изображение | +| `sova-cabinet/public/img/calendar.svg` | SVG-иконка / изображение | +| `sova-cabinet/public/img/check.svg` | SVG-иконка / изображение | +| `sova-cabinet/public/img/checkbox.svg` | SVG-иконка / изображение | +| `sova-cabinet/public/img/checkbox_active.svg` | SVG-иконка / изображение | +| `sova-cabinet/public/img/close.svg` | SVG-иконка / изображение | +| `sova-cabinet/public/img/fake-img.jpg` | JPEG-изображение | +| `sova-cabinet/public/img/favorites.svg` | SVG-иконка / изображение | +| `sova-cabinet/public/img/filter-ico.svg` | SVG-иконка / изображение | +| `sova-cabinet/public/img/filter.svg` | SVG-иконка / изображение | +| `sova-cabinet/public/img/logo.svg` | SVG-иконка / изображение | +| `sova-cabinet/public/img/mobile-logo.svg` | SVG-иконка / изображение | +| `sova-cabinet/public/img/place.svg` | SVG-иконка / изображение | +| `sova-cabinet/public/img/repeat-visit.svg` | SVG-иконка / изображение | +| `sova-cabinet/public/img/search-ico.svg` | SVG-иконка / изображение | +| `sova-cabinet/public/img/select-arrow-down.svg` | SVG-иконка / изображение | +| `sova-cabinet/public/img/select-arrow-up.svg` | SVG-иконка / изображение | +| `sova-cabinet/public/img/sova-bonus-logo.svg` | SVG-иконка / изображение | +| `sova-cabinet/public/img/staff-icon.png` | PNG-изображение | +| `sova-cabinet/public/img/up-arrow.svg` | SVG-иконка / изображение | +| `sova-cabinet/public/img/user.svg` | SVG-иконка / изображение | + + +## `sova-cabinet/public/img/logo/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/public/img/logo/2gis.png` | PNG-изображение | +| `sova-cabinet/public/img/logo/Google.png` | PNG-изображение | +| `sova-cabinet/public/img/logo/ProDoctorov.png` | PNG-изображение | +| `sova-cabinet/public/img/logo/ProDoctorovSpecialists.png` | PNG-изображение | +| `sova-cabinet/public/img/logo/YandexMap.png` | PNG-изображение | +| `sova-cabinet/public/img/logo/zoon.png` | PNG-изображение | + + +## `sova-cabinet/public/img/logo_wmt/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/public/img/logo_wmt/logo-pdf.jpg` | JPEG-изображение | +| `sova-cabinet/public/img/logo_wmt/logo.svg` | SVG-иконка / изображение | +| `sova-cabinet/public/img/logo_wmt/mobile-logo.png` | PNG-изображение | + + +## `sova-cabinet/public/widgets/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/public/widgets/_wf_cabinet.js` | JavaScript | +| `sova-cabinet/public/widgets/wf_cabinet.md` | Документация Markdown | +| `sova-cabinet/public/widgets/wf_cabinet.min.js` | JavaScript | + + +## `sova-cabinet/src/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/src/Kernel.php` | PHP (Symfony) | + + +## `sova-cabinet/src/Bundle/Bitrix/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/src/Bundle/Bitrix/Request.php` | PHP (Symfony) | + + +## `sova-cabinet/src/Bundle/Calltouch/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/src/Bundle/Calltouch/Request.php` | PHP (Symfony) | + + +## `sova-cabinet/src/Bundle/Crypt/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/src/Bundle/Crypt/AES.php` | PHP (Symfony) | + + +## `sova-cabinet/src/Bundle/Helper/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/src/Bundle/Helper/AmountInWords.php` | PHP (Symfony) | + + +## `sova-cabinet/src/Bundle/Infoclinica/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/src/Bundle/Infoclinica/.gitignore` | Git ignore rules | +| `sova-cabinet/src/Bundle/Infoclinica/Client.php` | PHP (Symfony) | +| `sova-cabinet/src/Bundle/Infoclinica/Region.php` | PHP (Symfony) | +| `sova-cabinet/src/Bundle/Infoclinica/Rest.php` | PHP (Symfony) | +| `sova-cabinet/src/Bundle/Infoclinica/certificate.pem` | TLS/JWT ключ | + + +## `sova-cabinet/src/Bundle/Notisend/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/src/Bundle/Notisend/Request.php` | PHP (Symfony) | + + +## `sova-cabinet/src/Bundle/Sms/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/src/Bundle/Sms/Manager.php` | PHP (Symfony) | + + +## `sova-cabinet/src/Bundle/Utils/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/src/Bundle/Utils/Logger.php` | PHP (Symfony) | + + +## `sova-cabinet/src/Bundle/Yandex/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/src/Bundle/Yandex/Direct.php` | PHP (Symfony) | + + +## `sova-cabinet/src/Command/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/src/Command/AesCommand.php` | Console command: AesCommand | +| `sova-cabinet/src/Command/BaseCommand.php` | Console command: BaseCommand | +| `sova-cabinet/src/Command/DiffDoctorsCommand.php` | Console command: DiffDoctorsCommand | +| `sova-cabinet/src/Command/DirectCommand.php` | Console command: DirectCommand | +| `sova-cabinet/src/Command/InfoclinicaCommand.php` | Console command: InfoclinicaCommand | +| `sova-cabinet/src/Command/UploadDepInfoclinicaCommand.php` | Console command: UploadDepInfoclinicaCommand | +| `sova-cabinet/src/Command/UploadDoctorsCommand.php` | Console command: UploadDoctorsCommand | +| `sova-cabinet/src/Command/UploadDoctorsInfoclinicaCommand.php` | Console command: UploadDoctorsInfoclinicaCommand | +| `sova-cabinet/src/Command/UploadDoctorsOnlineCommand.php` | Console command: UploadDoctorsOnlineCommand | +| `sova-cabinet/src/Command/UploadPriceDepInfoclinicaCommand.php` | Console command: UploadPriceDepInfoclinicaCommand | +| `sova-cabinet/src/Command/UploadPriceInfoclinicaCommand.php` | Console command: UploadPriceInfoclinicaCommand | +| `sova-cabinet/src/Command/UserCleanupCommand.php` | Console command: UserCleanupCommand | + + +## `sova-cabinet/src/Controller/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/src/Controller/.gitignore` | Git ignore rules | +| `sova-cabinet/src/Controller/BannerController.php` | Symfony controller: BannerController | +| `sova-cabinet/src/Controller/CalltouchAPIController.php` | Symfony controller: CalltouchAPIController | +| `sova-cabinet/src/Controller/CategoryPageController.php` | Symfony controller: CategoryPageController | +| `sova-cabinet/src/Controller/DefaultController.php` | Symfony controller: DefaultController | +| `sova-cabinet/src/Controller/DepartmentController.php` | Symfony controller: DepartmentController | +| `sova-cabinet/src/Controller/InternalAPIController.php` | Symfony controller: InternalAPIController | +| `sova-cabinet/src/Controller/PageController.php` | Symfony controller: PageController | +| `sova-cabinet/src/Controller/PublicAPIController.php` | Symfony controller: PublicAPIController | +| `sova-cabinet/src/Controller/ReviewSourceController.php` | Symfony controller: ReviewSourceController | +| `sova-cabinet/src/Controller/SecurityController.php` | Symfony controller: SecurityController | +| `sova-cabinet/src/Controller/SpecialistController.php` | Symfony controller: SpecialistController | +| `sova-cabinet/src/Controller/WidgetController.php` | Symfony controller: WidgetController | +| `sova-cabinet/src/Controller/WidgetFormController.php` | Symfony controller: WidgetFormController | +| `sova-cabinet/src/Controller/WidgetFormInputController.php` | Symfony controller: WidgetFormInputController | + + +## `sova-cabinet/src/Entity/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/src/Entity/.gitignore` | Git ignore rules | +| `sova-cabinet/src/Entity/AlertSms.php` | Doctrine entity: AlertSms | +| `sova-cabinet/src/Entity/Banner.php` | Doctrine entity: Banner | +| `sova-cabinet/src/Entity/CategoryPage.php` | Doctrine entity: CategoryPage | +| `sova-cabinet/src/Entity/City.php` | Doctrine entity: City | +| `sova-cabinet/src/Entity/Department.php` | Doctrine entity: Department | +| `sova-cabinet/src/Entity/DirectCompany.php` | Doctrine entity: DirectCompany | +| `sova-cabinet/src/Entity/DirectReport.php` | Doctrine entity: DirectReport | +| `sova-cabinet/src/Entity/Filial.php` | Doctrine entity: Filial | +| `sova-cabinet/src/Entity/LocationView.php` | Doctrine entity: LocationView | +| `sova-cabinet/src/Entity/Page.php` | Doctrine entity: Page | +| `sova-cabinet/src/Entity/Price.php` | Doctrine entity: Price | +| `sova-cabinet/src/Entity/PriceDepartment.php` | Doctrine entity: PriceDepartment | +| `sova-cabinet/src/Entity/PriceList.php` | Doctrine entity: PriceList | +| `sova-cabinet/src/Entity/Record.php` | Doctrine entity: Record | +| `sova-cabinet/src/Entity/Review.php` | Doctrine entity: Review | +| `sova-cabinet/src/Entity/ReviewSource.php` | Doctrine entity: ReviewSource | +| `sova-cabinet/src/Entity/SpecialistView.php` | Doctrine entity: SpecialistView | +| `sova-cabinet/src/Entity/User.php` | Doctrine entity: User | +| `sova-cabinet/src/Entity/Usrlog.php` | Doctrine entity: Usrlog | +| `sova-cabinet/src/Entity/WidgetForm.php` | Doctrine entity: WidgetForm | +| `sova-cabinet/src/Entity/WidgetFormInput.php` | Doctrine entity: WidgetFormInput | + + +## `sova-cabinet/src/EventListener/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/src/EventListener/SessionIdQueryCookieListener.php` | PHP (Symfony) | +| `sova-cabinet/src/EventListener/UserActivityListener.php` | PHP (Symfony) | +| `sova-cabinet/src/EventListener/UsrlogAuthListener.php` | PHP (Symfony) | + + +## `sova-cabinet/src/Form/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/src/Form/BannerType.php` | Form type: BannerType | +| `sova-cabinet/src/Form/CategoryPageType.php` | Form type: CategoryPageType | +| `sova-cabinet/src/Form/CityType.php` | Form type: CityType | +| `sova-cabinet/src/Form/DepartmentType.php` | Form type: DepartmentType | +| `sova-cabinet/src/Form/PageType.php` | Form type: PageType | +| `sova-cabinet/src/Form/PriceListAdminFormType.php` | Form type: PriceListAdminFormType | +| `sova-cabinet/src/Form/PriceListFormType.php` | Form type: PriceListFormType | +| `sova-cabinet/src/Form/ReferenceType.php` | Form type: ReferenceType | +| `sova-cabinet/src/Form/RefundType.php` | Form type: RefundType | +| `sova-cabinet/src/Form/RegistrationFormType.php` | Form type: RegistrationFormType | +| `sova-cabinet/src/Form/ReportFormType.php` | Form type: ReportFormType | +| `sova-cabinet/src/Form/ReviewSourceType.php` | Form type: ReviewSourceType | +| `sova-cabinet/src/Form/SettingType.php` | Form type: SettingType | +| `sova-cabinet/src/Form/SpecialistAdminSearchType.php` | Form type: SpecialistAdminSearchType | +| `sova-cabinet/src/Form/SpecialistSearchType.php` | Form type: SpecialistSearchType | +| `sova-cabinet/src/Form/SpecialistType.php` | Form type: SpecialistType | +| `sova-cabinet/src/Form/UsrlogType.php` | Form type: UsrlogType | +| `sova-cabinet/src/Form/WidgetFormInputType.php` | Form type: WidgetFormInputType | +| `sova-cabinet/src/Form/WidgetFormType.php` | Form type: WidgetFormType | + + +## `sova-cabinet/src/Repository/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/src/Repository/.gitignore` | Git ignore rules | +| `sova-cabinet/src/Repository/AlertSmsRepository.php` | Doctrine repository: AlertSmsRepository | +| `sova-cabinet/src/Repository/BannerRepository.php` | Doctrine repository: BannerRepository | +| `sova-cabinet/src/Repository/CategoryPageRepository.php` | Doctrine repository: CategoryPageRepository | +| `sova-cabinet/src/Repository/CityRepository.php` | Doctrine repository: CityRepository | +| `sova-cabinet/src/Repository/DepartmentRepository.php` | Doctrine repository: DepartmentRepository | +| `sova-cabinet/src/Repository/DirectCompanyRepository.php` | Doctrine repository: DirectCompanyRepository | +| `sova-cabinet/src/Repository/DirectReportRepository.php` | Doctrine repository: DirectReportRepository | +| `sova-cabinet/src/Repository/FilialRepository.php` | Doctrine repository: FilialRepository | +| `sova-cabinet/src/Repository/LocationViewRepository.php` | Doctrine repository: LocationViewRepository | +| `sova-cabinet/src/Repository/PageRepository.php` | Doctrine repository: PageRepository | +| `sova-cabinet/src/Repository/PriceDepartmentRepository.php` | Doctrine repository: PriceDepartmentRepository | +| `sova-cabinet/src/Repository/PriceListRepository.php` | Doctrine repository: PriceListRepository | +| `sova-cabinet/src/Repository/PriceRepository.php` | Doctrine repository: PriceRepository | +| `sova-cabinet/src/Repository/RecordRepository.php` | Doctrine repository: RecordRepository | +| `sova-cabinet/src/Repository/ReviewRepository.php` | Doctrine repository: ReviewRepository | +| `sova-cabinet/src/Repository/ReviewSourceRepository.php` | Doctrine repository: ReviewSourceRepository | +| `sova-cabinet/src/Repository/SpecialistViewRepository.php` | Doctrine repository: SpecialistViewRepository | +| `sova-cabinet/src/Repository/UserRepository.php` | Doctrine repository: UserRepository | +| `sova-cabinet/src/Repository/UsrlogRepository.php` | Doctrine repository: UsrlogRepository | +| `sova-cabinet/src/Repository/WidgetFormInputRepository.php` | Doctrine repository: WidgetFormInputRepository | +| `sova-cabinet/src/Repository/WidgetFormRepository.php` | Doctrine repository: WidgetFormRepository | + + +## `sova-cabinet/src/Security/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/src/Security/LoginFormAuthenticator.php` | PHP (Symfony) | + + +## `sova-cabinet/src/Service/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/src/Service/PriceListService.php` | Service: PriceListService | +| `sova-cabinet/src/Service/SpecialistMoreService.php` | Service: SpecialistMoreService | +| `sova-cabinet/src/Service/SpecialistService.php` | Service: SpecialistService | +| `sova-cabinet/src/Service/UserCleanupService.php` | Service: UserCleanupService | + + +## `sova-cabinet/src/Support/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/src/Support/OnlineMode.php` | PHP (Symfony) | + + +## `sova-cabinet/src/Twig/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/src/Twig/AppExtension.php` | PHP (Symfony) | + + +## `sova-cabinet/templates/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/templates/_calltouch.html.twig` | Twig template: _calltouch.html.twig | +| `sova-cabinet/templates/_change_region.html.twig` | Twig template: _change_region.html.twig | +| `sova-cabinet/templates/_metrika.html.twig` | Twig template: _metrika.html.twig | +| `sova-cabinet/templates/admin_base.html.twig` | Twig template: admin_base.html.twig | +| `sova-cabinet/templates/base.html.twig` | Twig template: base.html.twig | +| `sova-cabinet/templates/base_pdf.html.twig` | Twig template: base_pdf.html.twig | +| `sova-cabinet/templates/base_widget.html.twig` | Twig template: base_widget.html.twig | +| `sova-cabinet/templates/base_wmtmed.html.twig` | Twig template: base_wmtmed.html.twig | +| `sova-cabinet/templates/menu.html.twig` | Twig template: menu.html.twig | + + +## `sova-cabinet/templates/banner/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/templates/banner/_delete_form.html.twig` | Twig template: banner/_delete_form.html.twig | +| `sova-cabinet/templates/banner/_form.html.twig` | Twig template: banner/_form.html.twig | +| `sova-cabinet/templates/banner/edit.html.twig` | Twig template: banner/edit.html.twig | +| `sova-cabinet/templates/banner/index.html.twig` | Twig template: banner/index.html.twig | +| `sova-cabinet/templates/banner/new.html.twig` | Twig template: banner/new.html.twig | + + +## `sova-cabinet/templates/base/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/templates/base/_search_form_price.html.twig` | Twig template: base/_search_form_price.html.twig | +| `sova-cabinet/templates/base/doc.html.twig` | Twig template: base/doc.html.twig | +| `sova-cabinet/templates/base/doc_your_home.html.twig` | Twig template: base/doc_your_home.html.twig | +| `sova-cabinet/templates/base/favorites.html.twig` | Twig template: base/favorites.html.twig | +| `sova-cabinet/templates/base/help.html.twig` | Twig template: base/help.html.twig | +| `sova-cabinet/templates/base/index.html.twig` | Twig template: base/index.html.twig | +| `sova-cabinet/templates/base/paginator.html.twig` | Twig template: base/paginator.html.twig | +| `sova-cabinet/templates/base/patient.html.twig` | Twig template: base/patient.html.twig | +| `sova-cabinet/templates/base/price.html.twig` | Twig template: base/price.html.twig | +| `sova-cabinet/templates/base/price_list.html.twig` | Twig template: base/price_list.html.twig | + + +## `sova-cabinet/templates/category_page/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/templates/category_page/_delete_form.html.twig` | Twig template: category_page/_delete_form.html.twig | +| `sova-cabinet/templates/category_page/_form.html.twig` | Twig template: category_page/_form.html.twig | +| `sova-cabinet/templates/category_page/edit.html.twig` | Twig template: category_page/edit.html.twig | +| `sova-cabinet/templates/category_page/index.html.twig` | Twig template: category_page/index.html.twig | +| `sova-cabinet/templates/category_page/new.html.twig` | Twig template: category_page/new.html.twig | +| `sova-cabinet/templates/category_page/show.html.twig` | Twig template: category_page/show.html.twig | + + +## `sova-cabinet/templates/department/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/templates/department/_form.html.twig` | Twig template: department/_form.html.twig | +| `sova-cabinet/templates/department/edit.html.twig` | Twig template: department/edit.html.twig | +| `sova-cabinet/templates/department/index.html.twig` | Twig template: department/index.html.twig | + + +## `sova-cabinet/templates/internal_api/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/templates/internal_api/swagger.html.twig` | Twig template: internal_api/swagger.html.twig | + + +## `sova-cabinet/templates/page/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/templates/page/_delete_form.html.twig` | Twig template: page/_delete_form.html.twig | +| `sova-cabinet/templates/page/_form.html.twig` | Twig template: page/_form.html.twig | +| `sova-cabinet/templates/page/edit.html.twig` | Twig template: page/edit.html.twig | +| `sova-cabinet/templates/page/index.html.twig` | Twig template: page/index.html.twig | +| `sova-cabinet/templates/page/new.html.twig` | Twig template: page/new.html.twig | +| `sova-cabinet/templates/page/show.html.twig` | Twig template: page/show.html.twig | + + +## `sova-cabinet/templates/report/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/templates/report/_form.html.twig` | Twig template: report/_form.html.twig | +| `sova-cabinet/templates/report/index.html.twig` | Twig template: report/index.html.twig | + + +## `sova-cabinet/templates/review_source/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/templates/review_source/_delete_form.html.twig` | Twig template: review_source/_delete_form.html.twig | +| `sova-cabinet/templates/review_source/_form.html.twig` | Twig template: review_source/_form.html.twig | +| `sova-cabinet/templates/review_source/edit.html.twig` | Twig template: review_source/edit.html.twig | +| `sova-cabinet/templates/review_source/index.html.twig` | Twig template: review_source/index.html.twig | +| `sova-cabinet/templates/review_source/new.html.twig` | Twig template: review_source/new.html.twig | + + +## `sova-cabinet/templates/security/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/templates/security/card.html.twig` | Twig template: security/card.html.twig | +| `sova-cabinet/templates/security/case_history.html.twig` | Twig template: security/case_history.html.twig | +| `sova-cabinet/templates/security/confirm.html.twig` | Twig template: security/confirm.html.twig | +| `sova-cabinet/templates/security/login.html.twig` | Twig template: security/login.html.twig | +| `sova-cabinet/templates/security/login_wmtmed.html.twig` | Twig template: security/login_wmtmed.html.twig | +| `sova-cabinet/templates/security/payment.html.twig` | Twig template: security/payment.html.twig | +| `sova-cabinet/templates/security/referrals.html.twig` | Twig template: security/referrals.html.twig | +| `sova-cabinet/templates/security/refund_blank.html.twig` | Twig template: security/refund_blank.html.twig | +| `sova-cabinet/templates/security/refund_form.html.twig` | Twig template: security/refund_form.html.twig | +| `sova-cabinet/templates/security/register.html.twig` | Twig template: security/register.html.twig | +| `sova-cabinet/templates/security/setting.html.twig` | Twig template: security/setting.html.twig | + + +## `sova-cabinet/templates/specialist/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/templates/specialist/_calendar.html.twig` | Twig template: specialist/_calendar.html.twig | +| `sova-cabinet/templates/specialist/_item.html.twig` | Twig template: specialist/_item.html.twig | +| `sova-cabinet/templates/specialist/_reviews.html.twig` | Twig template: specialist/_reviews.html.twig | +| `sova-cabinet/templates/specialist/_search_form.html.twig` | Twig template: specialist/_search_form.html.twig | +| `sova-cabinet/templates/specialist/index.html.twig` | Twig template: specialist/index.html.twig | +| `sova-cabinet/templates/specialist/show.html.twig` | Twig template: specialist/show.html.twig | + + +## `sova-cabinet/templates/specialist/admin/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/templates/specialist/admin/_form.html.twig` | Twig template: specialist/admin/_form.html.twig | +| `sova-cabinet/templates/specialist/admin/_toggle_form.html.twig` | Twig template: specialist/admin/_toggle_form.html.twig | +| `sova-cabinet/templates/specialist/admin/index.html.twig` | Twig template: specialist/admin/index.html.twig | + + +## `sova-cabinet/templates/widget/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/templates/widget/reference.html.twig` | Twig template: widget/reference.html.twig | +| `sova-cabinet/templates/widget/review_source.html.twig` | Twig template: widget/review_source.html.twig | + + +## `sova-cabinet/templates/widget_form/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/templates/widget_form/_delete_form.html.twig` | Twig template: widget_form/_delete_form.html.twig | +| `sova-cabinet/templates/widget_form/_form.html.twig` | Twig template: widget_form/_form.html.twig | +| `sova-cabinet/templates/widget_form/edit.html.twig` | Twig template: widget_form/edit.html.twig | +| `sova-cabinet/templates/widget_form/editor.html.twig` | Twig template: widget_form/editor.html.twig | +| `sova-cabinet/templates/widget_form/index.html.twig` | Twig template: widget_form/index.html.twig | +| `sova-cabinet/templates/widget_form/new.html.twig` | Twig template: widget_form/new.html.twig | +| `sova-cabinet/templates/widget_form/show.html.twig` | Twig template: widget_form/show.html.twig | + + +## `sova-cabinet/templates/widget_form_input/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/templates/widget_form_input/_delete_form.html.twig` | Twig template: widget_form_input/_delete_form.html.twig | +| `sova-cabinet/templates/widget_form_input/_form.html.twig` | Twig template: widget_form_input/_form.html.twig | +| `sova-cabinet/templates/widget_form_input/edit.html.twig` | Twig template: widget_form_input/edit.html.twig | +| `sova-cabinet/templates/widget_form_input/new.html.twig` | Twig template: widget_form_input/new.html.twig | + + +## `sova-cabinet/tests/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/tests/bootstrap.php` | PHP (Symfony) | + + +## `sova-cabinet/tests/Controller/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/tests/Controller/OnlineSpecialistsControllerTest.php` | Symfony controller: OnlineSpecialistsControllerTest | + + +## `sova-cabinet/tests/Unit/Support/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/tests/Unit/Support/OnlineModeTest.php` | PHP (Symfony) | + + +## `sova-cabinet/translations/` + + +| Файл | Назначение | +|------|------------| +| `sova-cabinet/translations/.gitignore` | Git ignore rules | +| `sova-cabinet/translations/KnpPaginatorBundle.ru.yaml` | YAML-конфиг / Helm / K8s | diff --git a/infrastructure/test-contour/k3s-test-reference/sova-deploy.md b/infrastructure/test-contour/k3s-test-reference/sova-deploy.md new file mode 100644 index 0000000..e46f108 --- /dev/null +++ b/infrastructure/test-contour/k3s-test-reference/sova-deploy.md @@ -0,0 +1,264 @@ +# sova-deploy: Helm и ArgoCD + +GitOps-репозиторий: Helm charts приложений, data layer, ArgoCD Applications и platform values. + +**Файлов:** 56 + + +## `sova-deploy/apps/adminpanel/` + + +| Файл | Назначение | +|------|------------| +| `sova-deploy/apps/adminpanel/Chart.yaml` | Helm chart metadata | +| `sova-deploy/apps/adminpanel/values-stage.yaml` | Overrides для stage-контура | +| `sova-deploy/apps/adminpanel/values-test.yaml` | Overrides для test-контура | +| `sova-deploy/apps/adminpanel/values.yaml` | Базовые Helm values | + + +## `sova-deploy/apps/adminpanel/templates/` + + +| Файл | Назначение | +|------|------------| +| `sova-deploy/apps/adminpanel/templates/all.yaml` | Combined Helm template (Deployment/Service/Ingress) | + + +## `sova-deploy/apps/backend/` + + +| Файл | Назначение | +|------|------------| +| `sova-deploy/apps/backend/Chart.yaml` | Helm chart metadata | +| `sova-deploy/apps/backend/values-stage.yaml` | Overrides для stage-контура | +| `sova-deploy/apps/backend/values-test.yaml` | Overrides для test-контура | +| `sova-deploy/apps/backend/values.yaml` | Базовые Helm values | + + +## `sova-deploy/apps/backend/jwt/` + + +| Файл | Назначение | +|------|------------| +| `sova-deploy/apps/backend/jwt/private.pem` | TLS/JWT ключ | +| `sova-deploy/apps/backend/jwt/public.pem` | TLS/JWT ключ | + + +## `sova-deploy/apps/backend/templates/` + + +| Файл | Назначение | +|------|------------| +| `sova-deploy/apps/backend/templates/_console.tpl` | Helm template partial | +| `sova-deploy/apps/backend/templates/all.yaml` | Combined Helm template (Deployment/Service/Ingress) | + + +## `sova-deploy/apps/cabinet/` + + +| Файл | Назначение | +|------|------------| +| `sova-deploy/apps/cabinet/Chart.yaml` | Helm chart metadata | +| `sova-deploy/apps/cabinet/values-stage.yaml` | Overrides для stage-контура | +| `sova-deploy/apps/cabinet/values-test.yaml` | Overrides для test-контура | +| `sova-deploy/apps/cabinet/values.yaml` | Базовые Helm values | + + +## `sova-deploy/apps/cabinet/templates/` + + +| Файл | Назначение | +|------|------------| +| `sova-deploy/apps/cabinet/templates/all.yaml` | Combined Helm template (Deployment/Service/Ingress) | + + +## `sova-deploy/apps/docs/` + + +| Файл | Назначение | +|------|------------| +| `sova-deploy/apps/docs/Chart.yaml` | Helm chart metadata | +| `sova-deploy/apps/docs/values-stage.yaml` | Overrides для stage-контура | +| `sova-deploy/apps/docs/values-test.yaml` | Overrides для test-контура | +| `sova-deploy/apps/docs/values.yaml` | Базовые Helm values | + + +## `sova-deploy/apps/docs/templates/` + + +| Файл | Назначение | +|------|------------| +| `sova-deploy/apps/docs/templates/all.yaml` | Combined Helm template (Deployment/Service/Ingress) | + + +## `sova-deploy/apps/redmine/` + + +| Файл | Назначение | +|------|------------| +| `sova-deploy/apps/redmine/Chart.lock` | Lockfile (Helm/composer/yarn) | +| `sova-deploy/apps/redmine/Chart.yaml` | Helm chart metadata | +| `sova-deploy/apps/redmine/values-test.yaml` | Overrides для test-контура | +| `sova-deploy/apps/redmine/values.yaml` | Базовые Helm values | + + +## `sova-deploy/apps/redmine/charts/` + + +| Файл | Назначение | +|------|------------| +| `sova-deploy/apps/redmine/charts/redmine-32.2.2.tgz` | Vendored Helm subchart | + + +## `sova-deploy/argocd/` + + +| Файл | Назначение | +|------|------------| +| `sova-deploy/argocd/app-of-apps.yaml` | ArgoCD root Application (sova-root) | + + +## `sova-deploy/argocd/apps/` + + +| Файл | Назначение | +|------|------------| +| `sova-deploy/argocd/apps/platform-tools.yaml` | ArgoCD: monitoring, Gitea Actions, Redmine | +| `sova-deploy/argocd/apps/sova-projects.yaml` | ArgoCD GitOps: AppProject definitions | +| `sova-deploy/argocd/apps/test-contour.yaml` | ArgoCD: приложения test-контура | + + +## `sova-deploy/argocd/projects/` + + +| Файл | Назначение | +|------|------------| +| `sova-deploy/argocd/projects/sova-project.yaml` | ArgoCD AppProject RBAC и namespaces | + + +## `sova-deploy/data/db-init/` + + +| Файл | Назначение | +|------|------------| +| `sova-deploy/data/db-init/Chart.yaml` | Helm chart metadata | +| `sova-deploy/data/db-init/values.yaml` | Базовые Helm values | + + +## `sova-deploy/data/db-init/templates/` + + +| Файл | Назначение | +|------|------------| +| `sova-deploy/data/db-init/templates/db-init-jobs.yaml` | K8s Jobs: schema → seed SQL | + + +## `sova-deploy/data/mysql-bitrix/init/` + + +| Файл | Назначение | +|------|------------| +| `sova-deploy/data/mysql-bitrix/init/01-bitrix-schema-and-seed.sql` | SQL (schema или seed) | + + +## `sova-deploy/data/mysql-simple/` + + +| Файл | Назначение | +|------|------------| +| `sova-deploy/data/mysql-simple/mysql.yaml` | YAML-конфиг / Helm / K8s | + + +## `sova-deploy/data/postgres/init/` + + +| Файл | Назначение | +|------|------------| +| `sova-deploy/data/postgres/init/01-create-databases.sql` | SQL (schema или seed) | +| `sova-deploy/data/postgres/init/02-backend-schema-and-seed.sql` | SQL (schema или seed) | +| `sova-deploy/data/postgres/init/03-cabinet-schema-and-seed.sql` | SQL (schema или seed) | + + +## `sova-deploy/data/test/` + + +| Файл | Назначение | +|------|------------| +| `sova-deploy/data/test/Chart.yaml` | Helm chart metadata | +| `sova-deploy/data/test/values.yaml` | Базовые Helm values | + + +## `sova-deploy/data/test/sql/mysql-bitrix/schema/` + + +| Файл | Назначение | +|------|------------| +| `sova-deploy/data/test/sql/mysql-bitrix/schema/01-bitrix-schema.sql` | SQL (schema или seed) | + + +## `sova-deploy/data/test/sql/mysql-bitrix/seed/` + + +| Файл | Назначение | +|------|------------| +| `sova-deploy/data/test/sql/mysql-bitrix/seed/01-bitrix-seed.sql` | SQL (schema или seed) | + + +## `sova-deploy/data/test/sql/postgres/schema/` + + +| Файл | Назначение | +|------|------------| +| `sova-deploy/data/test/sql/postgres/schema/01-create-databases.sql` | SQL (schema или seed) | +| `sova-deploy/data/test/sql/postgres/schema/02-backend-schema.sql` | SQL (schema или seed) | +| `sova-deploy/data/test/sql/postgres/schema/03-cabinet-schema.sql` | SQL (schema или seed) | + + +## `sova-deploy/data/test/sql/postgres/seed/` + + +| Файл | Назначение | +|------|------------| +| `sova-deploy/data/test/sql/postgres/seed/01-create-databases.seed.sql` | SQL (schema или seed) | +| `sova-deploy/data/test/sql/postgres/seed/02-backend-seed.sql` | SQL (schema или seed) | +| `sova-deploy/data/test/sql/postgres/seed/03-cabinet-seed.sql` | SQL (schema или seed) | + + +## `sova-deploy/data/test/templates/` + + +| Файл | Назначение | +|------|------------| +| `sova-deploy/data/test/templates/namespace.yaml` | YAML-конфиг / Helm / K8s | + + +## `sova-deploy/platform/argocd/` + + +| Файл | Назначение | +|------|------------| +| `sova-deploy/platform/argocd/values-test.yaml` | Overrides для test-контура | + + +## `sova-deploy/platform/gitea-actions/` + + +| Файл | Назначение | +|------|------------| +| `sova-deploy/platform/gitea-actions/values-test.yaml` | Overrides для test-контура | + + +## `sova-deploy/platform/monitoring/` + + +| Файл | Назначение | +|------|------------| +| `sova-deploy/platform/monitoring/loki-datasource.yaml` | YAML-конфиг / Helm / K8s | + + +## `sova-deploy/platform/sentry/charts/` + + +| Файл | Назначение | +|------|------------| +| `sova-deploy/platform/sentry/charts/sentry-31.7.0.tgz` | Vendored Helm subchart | diff --git a/infrastructure/test-contour/k3s-test-reference/sova-docs-repo.md b/infrastructure/test-contour/k3s-test-reference/sova-docs-repo.md new file mode 100644 index 0000000..5a53b36 --- /dev/null +++ b/infrastructure/test-contour/k3s-test-reference/sova-docs-repo.md @@ -0,0 +1,210 @@ +# sova-docs: сайт документации + +VitePress-сайт (монорепо docs + test-contour). Собирается в Docker и деплоится как docs-test. + +**Файлов:** 114 + + +## `sova-docs/` + + +| Файл | Назначение | +|------|------------| +| `sova-docs/.gitignore` | Git ignore rules | +| `sova-docs/Dockerfile` | Docker multistage build | +| `sova-docs/api-routes.md` | Документация Markdown | +| `sova-docs/architecture.md` | Документация Markdown | +| `sova-docs/data-model.md` | Документация Markdown | +| `sova-docs/docs-site.md` | Документация Markdown | +| `sova-docs/environment.md` | Документация Markdown | +| `sova-docs/flows.md` | Документация Markdown | +| `sova-docs/forms-screenshots.zip` | Архив | +| `sova-docs/index.md` | Документация Markdown | +| `sova-docs/nginx.conf` | nginx конфиг контейнера | +| `sova-docs/package-lock.json` | JSON-данные / конфиг | +| `sova-docs/package.json` | NPM/Yarn зависимости и scripts | +| `sova-docs/quick-start.md` | Документация Markdown | +| `sova-docs/testing.md` | Документация Markdown | + + +## `sova-docs/.gitea/workflows/` + + +| Файл | Назначение | +|------|------------| +| `sova-docs/.gitea/workflows/build.yml` | Gitea Actions CI pipeline | + + +## `sova-docs/.vitepress/` + + +| Файл | Назначение | +|------|------------| +| `sova-docs/.vitepress/config.mts` | VitePress: nav, sidebar, mermaid | + + +## `sova-docs/.vitepress/theme/` + + +| Файл | Назначение | +|------|------------| +| `sova-docs/.vitepress/theme/index.ts` | TypeScript | +| `sova-docs/.vitepress/theme/style.css` | CSS-стили | + + +## `sova-docs/apps/` + + +| Файл | Назначение | +|------|------------| +| `sova-docs/apps/admin-panel-content-crud.md` | Документация приложения: admin-panel-content-crud | +| `sova-docs/apps/admin-panel.md` | Документация приложения: admin-panel | +| `sova-docs/apps/backend-architecture.md` | Документация приложения: backend-architecture | +| `sova-docs/apps/backend-content-crud.md` | Документация приложения: backend-content-crud | +| `sova-docs/apps/backend-ddd.md` | Документация приложения: backend-ddd | +| `sova-docs/apps/backend.md` | Документация приложения: backend | +| `sova-docs/apps/cabinet-architecture.md` | Документация приложения: cabinet-architecture | +| `sova-docs/apps/cabinet.md` | Документация приложения: cabinet | +| `sova-docs/apps/doctor-schedule-sync.md` | Документация приложения: doctor-schedule-sync | +| `sova-docs/apps/online-consultation.md` | Документация приложения: online-consultation | + + +## `sova-docs/apps/backend-scenarios/` + + +| Файл | Назначение | +|------|------------| +| `sova-docs/apps/backend-scenarios/anonymous-reserve.md` | Сценарий backend: anonymous-reserve | +| `sova-docs/apps/backend-scenarios/auth-uid-pcode.md` | Сценарий backend: auth-uid-pcode | +| `sova-docs/apps/backend-scenarios/calltouch-lead.md` | Сценарий backend: calltouch-lead | +| `sova-docs/apps/backend-scenarios/change-region.md` | Сценарий backend: change-region | +| `sova-docs/apps/backend-scenarios/index.md` | Сценарий backend: index | +| `sova-docs/apps/backend-scenarios/kiosk-checkpass.md` | Сценарий backend: kiosk-checkpass | +| `sova-docs/apps/backend-scenarios/login-jwt.md` | Сценарий backend: login-jwt | +| `sova-docs/apps/backend-scenarios/schedule-cache.md` | Сценарий backend: schedule-cache | +| `sova-docs/apps/backend-scenarios/schedule-messenger.md` | Сценарий backend: schedule-messenger | +| `sova-docs/apps/backend-scenarios/sms-record.md` | Сценарий backend: sms-record | +| `sova-docs/apps/backend-scenarios/specialist-card-locations.md` | Сценарий backend: specialist-card-locations | +| `sova-docs/apps/backend-scenarios/sync-doctors-reviews.md` | Сценарий backend: sync-doctors-reviews | +| `sova-docs/apps/backend-scenarios/xml-yandex-feed.md` | Сценарий backend: xml-yandex-feed | + + +## `sova-docs/forms-screenshots/` + + +| Файл | Назначение | +|------|------------| +| `sova-docs/forms-screenshots/01-login-landing.png` | Скриншот формы cabinet: 01-login-landing.png | +| `sova-docs/forms-screenshots/02-login-modal.png` | Скриншот формы cabinet: 02-login-modal.png | +| `sova-docs/forms-screenshots/03-password-recovery.png` | Скриншот формы cabinet: 03-password-recovery.png | +| `sova-docs/forms-screenshots/04-registration.png` | Скриншот формы cabinet: 04-registration.png | +| `sova-docs/forms-screenshots/05-specialists-search.png` | Скриншот формы cabinet: 05-specialists-search.png | +| `sova-docs/forms-screenshots/06-price-search.png` | Скриншот формы cabinet: 06-price-search.png | +| `sova-docs/forms-screenshots/07-help-callback.png` | Скриншот формы cabinet: 07-help-callback.png | +| `sova-docs/forms-screenshots/08-info-reference-entry.png` | Скриншот формы cabinet: 08-info-reference-entry.png | +| `sova-docs/forms-screenshots/09-widget-form-2.png` | Скриншот формы cabinet: 09-widget-form-2.png | +| `sova-docs/forms-screenshots/10-widget-reference.png` | Скриншот формы cabinet: 10-widget-reference.png | +| `sova-docs/forms-screenshots/11-doctor-your-home-modal.png` | Скриншот формы cabinet: 11-doctor-your-home-modal.png | +| `sova-docs/forms-screenshots/12-booking-modal-offline.png` | Скриншот формы cabinet: 12-booking-modal-offline.png | +| `sova-docs/forms-screenshots/13-online-specialists.png` | Скриншот формы cabinet: 13-online-specialists.png | +| `sova-docs/forms-screenshots/14-case-history.png` | Скриншот формы cabinet: 14-case-history.png | +| `sova-docs/forms-screenshots/15-payment.png` | Скриншот формы cabinet: 15-payment.png | +| `sova-docs/forms-screenshots/16-settings.png` | Скриншот формы cabinet: 16-settings.png | +| `sova-docs/forms-screenshots/17-security-card.png` | Скриншот формы cabinet: 17-security-card.png | +| `sova-docs/forms-screenshots/18-refund-form.png` | Скриншот формы cabinet: 18-refund-form.png | +| `sova-docs/forms-screenshots/19-booking-modal-online.png` | Скриншот формы cabinet: 19-booking-modal-online.png | +| `sova-docs/forms-screenshots/README.md` | Главный README k3s-test | +| `sova-docs/forms-screenshots/manifest.json` | Метаданные скриншотов | + + +## `sova-docs/infrastructure/` + + +| Файл | Назначение | +|------|------------| +| `sova-docs/infrastructure/backend-external-services.md` | Инфра-документация: backend-external-services | +| `sova-docs/infrastructure/docker.md` | Инфра-документация: docker | +| `sova-docs/infrastructure/k8s-cicd-platform-plan.md` | Инфра-документация: k8s-cicd-platform-plan | + + +## `sova-docs/infrastructure/test-contour/` + + +| Файл | Назначение | +|------|------------| +| `sova-docs/infrastructure/test-contour/argocd-apps.md` | Инфра-документация: argocd-apps | +| `sova-docs/infrastructure/test-contour/git-flow.md` | Инфра-документация: git-flow | +| `sova-docs/infrastructure/test-contour/index.md` | Инфра-документация: index | +| `sova-docs/infrastructure/test-contour/tags.md` | Инфра-документация: tags | +| `sova-docs/infrastructure/test-contour/test-contour-article.md` | Инфра-документация: test-contour-article | + + +## `sova-docs/infrastructure/test-contour/guides/` + + +| Файл | Назначение | +|------|------------| +| `sova-docs/infrastructure/test-contour/guides/argocd.md` | Инфра-документация: argocd | +| `sova-docs/infrastructure/test-contour/guides/gitea-ci.md` | Инфра-документация: gitea-ci | +| `sova-docs/infrastructure/test-contour/guides/monitoring.md` | Инфра-документация: monitoring | +| `sova-docs/infrastructure/test-contour/guides/overview.md` | Инфра-документация: overview | +| `sova-docs/infrastructure/test-contour/guides/redmine.md` | Инфра-документация: redmine | + + +## `sova-docs/infrastructure/test-contour/k3s-test-reference/` + + +| Файл | Назначение | +|------|------------| +| `sova-docs/infrastructure/test-contour/k3s-test-reference/_generate.py` | Python-скрипт | +| `sova-docs/infrastructure/test-contour/k3s-test-reference/docs-pointers.md` | Инфра-документация: docs-pointers | +| `sova-docs/infrastructure/test-contour/k3s-test-reference/index.md` | Инфра-документация: index | +| `sova-docs/infrastructure/test-contour/k3s-test-reference/root-and-artifacts.md` | Инфра-документация: root-and-artifacts | +| `sova-docs/infrastructure/test-contour/k3s-test-reference/scripts.md` | Инфра-документация: scripts | +| `sova-docs/infrastructure/test-contour/k3s-test-reference/sova-adminpanel.md` | Инфра-документация: sova-adminpanel | +| `sova-docs/infrastructure/test-contour/k3s-test-reference/sova-backend.md` | Инфра-документация: sova-backend | +| `sova-docs/infrastructure/test-contour/k3s-test-reference/sova-cabinet.md` | Инфра-документация: sova-cabinet | +| `sova-docs/infrastructure/test-contour/k3s-test-reference/sova-deploy.md` | Инфра-документация: sova-deploy | +| `sova-docs/infrastructure/test-contour/k3s-test-reference/sova-docs-repo.md` | Инфра-документация: sova-docs-repo | +| `sova-docs/infrastructure/test-contour/k3s-test-reference/sova-mocks.md` | Инфра-документация: sova-mocks | +| `sova-docs/infrastructure/test-contour/k3s-test-reference/sova-platform.md` | Инфра-документация: sova-platform | +| `sova-docs/infrastructure/test-contour/k3s-test-reference/sova-redmine.md` | Инфра-документация: sova-redmine | + + +## `sova-docs/infrastructure/test-contour/screenshots/` + + +| Файл | Назначение | +|------|------------| +| `sova-docs/infrastructure/test-contour/screenshots/01-gitea-login.png` | Скриншот UI: 01-gitea-login.png | +| `sova-docs/infrastructure/test-contour/screenshots/02-gitea-org-sova.png` | Скриншот UI: 02-gitea-org-sova.png | +| `sova-docs/infrastructure/test-contour/screenshots/03-gitea-backend-actions.png` | Скриншот UI: 03-gitea-backend-actions.png | +| `sova-docs/infrastructure/test-contour/screenshots/04-gitea-action-run.png` | Скриншот UI: 04-gitea-action-run.png | +| `sova-docs/infrastructure/test-contour/screenshots/05-gitea-backend-tags.png` | Скриншот UI: 05-gitea-backend-tags.png | +| `sova-docs/infrastructure/test-contour/screenshots/06-gitea-backend-packages.png` | Скриншот UI: 06-gitea-backend-packages.png | +| `sova-docs/infrastructure/test-contour/screenshots/07-argocd-login.png` | Скриншот UI: 07-argocd-login.png | +| `sova-docs/infrastructure/test-contour/screenshots/08-argocd-applications.png` | Скриншот UI: 08-argocd-applications.png | +| `sova-docs/infrastructure/test-contour/screenshots/09-argocd-backend-test.png` | Скриншот UI: 09-argocd-backend-test.png | +| `sova-docs/infrastructure/test-contour/screenshots/10-argocd-sova-root.png` | Скриншот UI: 10-argocd-sova-root.png | +| `sova-docs/infrastructure/test-contour/screenshots/11-argocd-data-test.png` | Скриншот UI: 11-argocd-data-test.png | +| `sova-docs/infrastructure/test-contour/screenshots/12-grafana-login.png` | Скриншот UI: 12-grafana-login.png | +| `sova-docs/infrastructure/test-contour/screenshots/13-grafana-home.png` | Скриншот UI: 13-grafana-home.png | +| `sova-docs/infrastructure/test-contour/screenshots/14-grafana-loki-explore.png` | Скриншот UI: 14-grafana-loki-explore.png | +| `sova-docs/infrastructure/test-contour/screenshots/15-prometheus-graph.png` | Скриншот UI: 15-prometheus-graph.png | +| `sova-docs/infrastructure/test-contour/screenshots/16-prometheus-targets.png` | Скриншот UI: 16-prometheus-targets.png | +| `sova-docs/infrastructure/test-contour/screenshots/17-prometheus-up-query.png` | Скриншот UI: 17-prometheus-up-query.png | +| `sova-docs/infrastructure/test-contour/screenshots/18-sentry-login.png` | Скриншот UI: 18-sentry-login.png | +| `sova-docs/infrastructure/test-contour/screenshots/19-sentry-home.png` | Скриншот UI: 19-sentry-home.png | +| `sova-docs/infrastructure/test-contour/screenshots/20-sentry-issues.png` | Скриншот UI: 20-sentry-issues.png | +| `sova-docs/infrastructure/test-contour/screenshots/21-redmine-login.png` | Скриншот UI: 21-redmine-login.png | +| `sova-docs/infrastructure/test-contour/screenshots/22-redmine-home.png` | Скриншот UI: 22-redmine-home.png | +| `sova-docs/infrastructure/test-contour/screenshots/README.md` | Главный README k3s-test | +| `sova-docs/infrastructure/test-contour/screenshots/manifest.json` | Метаданные скриншотов | + + +## `sova-docs/operations/` + + +| Файл | Назначение | +|------|------------| +| `sova-docs/operations/maintenance.md` | Документация Markdown | diff --git a/infrastructure/test-contour/k3s-test-reference/sova-mocks.md b/infrastructure/test-contour/k3s-test-reference/sova-mocks.md new file mode 100644 index 0000000..edcb0aa --- /dev/null +++ b/infrastructure/test-contour/k3s-test-reference/sova-mocks.md @@ -0,0 +1,66 @@ +# sova-mocks: WireMock и Mailpit + +Моки внешних API (MIS, Calltouch, Captcha) и SMTP для test-контура. + +**Файлов:** 19 + + +## `sova-mocks/` + + +| Файл | Назначение | +|------|------------| +| `sova-mocks/docker-compose.yml` | Docker Compose (моки / cabinet dev) | + + +## `sova-mocks/charts/mocks/` + + +| Файл | Назначение | +|------|------------| +| `sova-mocks/charts/mocks/Chart.yaml` | Helm chart metadata | +| `sova-mocks/charts/mocks/values.yaml` | Базовые Helm values | + + +## `sova-mocks/charts/mocks/mappings/` + + +| Файл | Назначение | +|------|------------| +| `sova-mocks/charts/mocks/mappings/calltouch-lead-create.json` | WireMock stub: calltouch lead create | +| `sova-mocks/charts/mocks/mappings/captcha-validate.json` | WireMock stub: captcha validate | +| `sova-mocks/charts/mocks/mappings/mis-anonymous-reserve.json` | WireMock stub: mis anonymous reserve | +| `sova-mocks/charts/mocks/mappings/mis-filials-list.json` | WireMock stub: mis filials list | +| `sova-mocks/charts/mocks/mappings/mis-intervals.json` | WireMock stub: mis intervals | +| `sova-mocks/charts/mocks/mappings/mis-pricelist-departments.json` | WireMock stub: mis pricelist departments | +| `sova-mocks/charts/mocks/mappings/mis-pricelist-list.json` | WireMock stub: mis pricelist list | + + +## `sova-mocks/charts/mocks/templates/` + + +| Файл | Назначение | +|------|------------| +| `sova-mocks/charts/mocks/templates/all.yaml` | Combined Helm template (Deployment/Service/Ingress) | + + +## `sova-mocks/scripts/` + + +| Файл | Назначение | +|------|------------| +| `sova-mocks/scripts/smoke-local.sh` | Shell-скрипт | + + +## `sova-mocks/wiremock/mappings/` + + +| Файл | Назначение | +|------|------------| +| `sova-mocks/wiremock/mappings/calltouch-lead-create.json` | WireMock stub: calltouch lead create | +| `sova-mocks/wiremock/mappings/captcha-validate.json` | WireMock stub: captcha validate | +| `sova-mocks/wiremock/mappings/mis-anonymous-reserve.json` | WireMock stub: mis anonymous reserve | +| `sova-mocks/wiremock/mappings/mis-filials-list.json` | WireMock stub: mis filials list | +| `sova-mocks/wiremock/mappings/mis-intervals.json` | WireMock stub: mis intervals | +| `sova-mocks/wiremock/mappings/mis-pricelist-departments.json` | WireMock stub: mis pricelist departments | +| `sova-mocks/wiremock/mappings/mis-pricelist-list.json` | WireMock stub: mis pricelist list | diff --git a/infrastructure/test-contour/k3s-test-reference/sova-platform.md b/infrastructure/test-contour/k3s-test-reference/sova-platform.md new file mode 100644 index 0000000..61f2706 --- /dev/null +++ b/infrastructure/test-contour/k3s-test-reference/sova-platform.md @@ -0,0 +1,36 @@ +# sova-platform: Terraform + +Terraform для Multipass VM и установки k3s на single-node. + +**Файлов:** 10 + + +## `sova-platform/terraform/envs/local-test/` + + +| Файл | Назначение | +|------|------------| +| `sova-platform/terraform/envs/local-test/.terraform.lock.hcl` | Terraform lock | +| `sova-platform/terraform/envs/local-test/main.tf` | Terraform | +| `sova-platform/terraform/envs/local-test/terraform.tfvars` | Terraform переменные | +| `sova-platform/terraform/envs/local-test/terraform.tfvars.bak` | Файл проекта | +| `sova-platform/terraform/envs/local-test/terraform.tfvars.example` | Файл проекта | +| `sova-platform/terraform/envs/local-test/variables.tf` | Terraform | +| `sova-platform/terraform/envs/local-test/versions.tf` | Terraform | + + +## `sova-platform/terraform/modules/k3s-single-node/` + + +| Файл | Назначение | +|------|------------| +| `sova-platform/terraform/modules/k3s-single-node/main.tf` | Terraform | +| `sova-platform/terraform/modules/k3s-single-node/versions.tf` | Terraform | + + +## `sova-platform/terraform/modules/k3s-single-node/scripts/` + + +| Файл | Назначение | +|------|------------| +| `sova-platform/terraform/modules/k3s-single-node/scripts/install-k3s.sh` | Shell-скрипт | diff --git a/infrastructure/test-contour/k3s-test-reference/sova-redmine.md b/infrastructure/test-contour/k3s-test-reference/sova-redmine.md new file mode 100644 index 0000000..27dadfb --- /dev/null +++ b/infrastructure/test-contour/k3s-test-reference/sova-redmine.md @@ -0,0 +1,21 @@ +# sova-redmine: custom image + +Опциональный custom Docker-образ Redmine с plugin github_hook. + +**Файлов:** 2 + + +## `sova-redmine/` + + +| Файл | Назначение | +|------|------------| +| `sova-redmine/Dockerfile` | Docker multistage build | + + +## `sova-redmine/.gitea/workflows/` + + +| Файл | Назначение | +|------|------------| +| `sova-redmine/.gitea/workflows/build.yml` | Gitea Actions CI pipeline | diff --git a/infrastructure/test-contour/screenshots/21-redmine-login.png b/infrastructure/test-contour/screenshots/21-redmine-login.png new file mode 100644 index 0000000000000000000000000000000000000000..853951b5350cdf4ab59238aaf6ecb347d563c792 GIT binary patch literal 27226 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 literal 0 HcmV?d00001 diff --git a/infrastructure/test-contour/screenshots/22-redmine-home.png b/infrastructure/test-contour/screenshots/22-redmine-home.png new file mode 100644 index 0000000000000000000000000000000000000000..a3b5abfa2094f80dbdf011920ac370fbcdf8cb10 GIT binary patch literal 39372 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 C!e1@` literal 0 HcmV?d00001 diff --git a/infrastructure/test-contour/screenshots/README.md b/infrastructure/test-contour/screenshots/README.md index 6a2ca49..ef7af71 100644 --- a/infrastructure/test-contour/screenshots/README.md +++ b/infrastructure/test-contour/screenshots/README.md @@ -21,5 +21,9 @@ | 15-prometheus-graph.png | Prometheus Graph | | 16-prometheus-targets.png | Prometheus Targets | | 17-prometheus-up-query.png | PromQL up | +| 21-redmine-login.png | Redmine: вход | +| 22-redmine-home.png | Redmine: проекты | + +> Скриншоты 18–20 (Sentry) устарели — Sentry удалён из test-контура. Полный manifest: `manifest.json` diff --git a/infrastructure/test-contour/test-contour-article.md b/infrastructure/test-contour/test-contour-article.md index 20bff2a..0f53f57 100644 --- a/infrastructure/test-contour/test-contour-article.md +++ b/infrastructure/test-contour/test-contour-article.md @@ -598,6 +598,45 @@ imagePullSecrets: --- +## Redmine *(30.05.2026)* + +В test-контуре развёрнут **Redmine** — issue tracker для задач разработки и связи с Git-flow (`Refs #N` / `Fixes #N` в коммитах). + +| URL | Namespace | Назначение | +|-----|-----------|------------| +| http://redmine.sova.local | `redmine` | Задачи, проект `sova-platform`, пример [#27](http://redmine.sova.local/issues/27) | + +> **Sentry** был удалён из test-контура (≈10 GiB RAM). Ошибки приложений смотрите в [Grafana → Loki](./guides/monitoring.md). + +### Что сделано + +- **Redmine** — Bitnami chart, образ `bitnamilegacy/redmine:6.0.5-debian-12-r0`, БД `redmine_test` в `sova-data-test`. +- ArgoCD app `redmine-test` в `platform-tools.yaml`; namespace `redmine` в GitOps `sova-projects` / `sova-project.yaml`. +- Ingress `redmine.sova.local` в `deploy-platform-ingress.sh`. +- SMTP через Mailpit (письма в UI мока, не реальная почта). +- Скрипты: `deploy-redmine.sh`, `bootstrap-redmine.sh`, `setup-gitea-redmine-integration.sh`. +- Bootstrap: проект **Sova Platform**, задача **#27** (CRUD сущностей в API). +- Custom image `sova-redmine/` с plugin `redmine_github_hook` — опционально, для webhook из Gitea. + +### Деплой + +```bash +./scripts/deploy-redmine.sh +./scripts/deploy-redmine.sh --bootstrap # проект + задача #27 +./scripts/deploy-platform-ingress.sh +kubectl get application redmine-test -n argocd +kubectl get pods -n redmine +``` + +Подробный гайд со скриншотами: [Redmine](./guides/redmine.md). + +### Следующие шаги + +- [ ] Gitea external tracker + webhooks в Redmine (инструкции: `setup-gitea-redmine-integration.sh`) +- [ ] При необходимости — custom image `sova-redmine` с `redmine_github_hook` + +--- + ## Полезные команды ```bash @@ -621,7 +660,7 @@ helm template backend-test ./sova-deploy/apps/backend \ ## Итог -В `k3s-test/` собран **полноценный test-контур**: приложения, изолированные БД (schema → seed), моки внешних сервисов, GitOps и заготовка CI. Локально он крутится на Multipass + k3s и имитирует production-подобный стек без изменений монорепо. +В `k3s-test/` собран **полноценный test-контур**: приложения, изолированные БД (schema → seed), моки внешних сервисов, GitOps, **Redmine** и заготовка CI. Локально он крутится на Multipass + k3s и имитирует production-подобный стек без изменений монорепо. Перенос на удалённый сервер — это в основном замена **домена**, **TLS**, **registry образов** и **управления секретами**; скрипты и Helm charts из `k3s-test/` переиспользуются с минимальными правками `values-test.yaml`.