Требования, SLO и архитектурная схема проекта
Зачем это на собесе
Сквозной проект показывает, что вы умеете связать требования, архитектуру, реализацию и эксплуатацию. Начинается всё с понятных требований и измеримых целей надёжности.
Цель
Описать учебный production-проект Clinic (запись пациентов на приём): что он делает, для кого, какие нефункциональные требования и SLO, как выглядит архитектура и какие решения приняты (ADR). Этот документ — основа для всех следующих шагов: контракты, реализация, CI/CD, наблюдаемость и game day.
Продукт и пользователи
| Роль | Задачи |
|---|---|
| Пациент | найти врача и свободное время, записаться, отменить/перенести запись, получить напоминание |
| Регистратор | управлять расписанием, записывать по телефону, подтверждать/отменять |
| Врач | видеть свои приёмы на день, отмечать статус (принят, не явился) |
| Администратор | справочники (врачи, специальности, кабинеты), отчёты, роли |
Основные сценарии (user journeys)
- Запись на приём: выбор специальности → врача → свободного слота → подтверждение → уведомление.
- Отмена/перенос записи с освобождением слота.
- Расписание врача на день/неделю.
- Вход через SSO (OIDC), разграничение ролей.
Функциональные требования (MVP)
- каталог врачей и специальностей (чтение, поиск, фильтры);
- слоты расписания: генерация по шаблону, бронирование без двойной записи (конкурентность!);
- CRUD записей с правилами (нельзя записаться в прошлое, лимиты на пациента, окна отмены);
- уведомления (email/SMS/Telegram) о записи и напоминания — асинхронно;
- роли и права (пациент видит только свои записи);
- аудит действий (кто и что изменил);
- административный интерфейс справочников.
Нефункциональные требования
| Область | Требование |
|---|---|
| Производительность | p95 API < 300 мс на чтении каталога, < 500 мс на записи; 200 RPS на пике (приём записей утром) |
| Доступность | 99.9% в месяц для API записи (≈ 43 мин простоя) |
| Надёжность данных | RPO ≤ 5 минут, RTO ≤ 1 час; запись не теряется и не дублируется |
| Безопасность | OIDC/PKCE, TLS везде, минимальные права, защита ПДн (152-ФЗ/GDPR): шифрование, маскирование в логах, аудит доступа |
| Масштабируемость | горизонтальное для API; БД — вертикально + реплика чтения |
| Наблюдаемость | метрики, структурированные логи, трассировки, дашборды, алерты по SLO |
| Сопровождаемость | контракты API, тесты, IaC, документация, ADR |
| Доступность интерфейса | WCAG AA, адаптивность (мобильные), i18n (ru/en) |
| Совместимость | последние 2 версии браузеров; мобильный Safari/Chrome |
SLI и SLO
| Сценарий | SLI | SLO (30 дней) |
|---|---|---|
| Доступность API | доля ответов без 5xx / все запросы | 99.9% |
| Латентность чтения | доля запросов < 300 мс | 95% |
| Латентность записи на приём | доля запросов < 500 мс | 95% |
| Корректность записи | доля записей без конфликтов/дублей | 100% (инвариант, а не SLO: ошибки — баги) |
| Уведомления | доля отправленных за 1 мин | 99% |
| Frontend | LCP < 2.5 с для 75% сессий; доля сессий без JS-ошибок | 99% crash-free |
Error budget API: 0.1% ≈ 43 минуты в месяц. Политика: при расходе > 50% — осторожные релизы, при исчерпании — заморозка фич и работа над надёжностью.
Архитектура
Браузер (Vue 3 + Quasar SPA)
│ HTTPS
▼
Nginx / Ingress (TLS, маршрутизация, rate limit)
├── / → web (статика SPA)
├── /api → Clinic API (ASP.NET Core)
└── /auth → Keycloak (OIDC)
Clinic API ──▶ PostgreSQL (основные данные)
│ ├─▶ Redis (кэш расписания, блокировки, rate limit)
│ └─▶ Outbox → брокер (RabbitMQ/Kafka) → Notification Worker → Email/SMS/Telegram
Телеметрия: OTel SDK → OTel Collector → Prometheus / Loki / Tempo (или ClickHouse) → GrafanaКомпоненты и границы
- Web (SPA): Vue 3, Quasar, Pinia, TanStack Query, Vue Router; OIDC (PKCE) через Keycloak; сгенерированный клиент API;
- API: ASP.NET Core (Minimal API/Controllers), слои Domain/Application/Infrastructure; FluentValidation; EF Core; Polly; OpenTelemetry; health checks;
- Worker: обработка outbox и рассылок; идемпотентные обработчики;
- PostgreSQL: схема
clinic, миграции (EF/Flyway), ограничения целостности, индексы; - Redis: кэш каталога/слотов (cache-aside), rate limiting;
- Keycloak: пользователи, роли, SSO;
- Инфраструктура: Docker, compose (dev), Kubernetes (prod) + Helm, GitLab CI, Terraform/Ansible.
Ключевые архитектурные решения (ADR)
| ADR | Решение | Альтернативы | Обоснование |
|---|---|---|---|
| 1 | Модульный монолит API + отдельный Worker | микросервисы | небольшая команда, единая БД, проще эксплуатация; границы модулей для будущего разделения |
| 2 | PostgreSQL | MongoDB | строгие ограничения и транзакции для расписания |
| 3 | Бронирование слота через уникальное ограничение + оптимистичная блокировка | распределённые блокировки | целостность на уровне БД, проще и надёжнее |
| 4 | Transactional Outbox для уведомлений | dual write | атомарность «запись + событие» |
| 5 | OIDC Keycloak, PKCE | свой JWT | стандарты, SSO, MFA |
| 6 | OpenAPI как контракт (API-first) + кодогенерация клиента | ручные типы | единый источник истины |
| 7 | OpenTelemetry + Prometheus/Grafana/Loki/Tempo | вендорный APM | стандарты, контроль стоимости |
| 8 | Kubernetes + Helm + GitOps | compose на VM | HA, rolling, автоскейл (на этапе роста) |
Формат ADR: контекст → варианты → решение → последствия. Храним в docs/adr/.
Модель данных (упрощённо)
doctors(id, full_name, specialty_id, room, active)
specialties(id, name)
slots(id, doctor_id, starts_at timestamptz, duration_min, status) -- free | booked | blocked
appointments(id, slot_id UNIQUE, patient_id, status, created_at, updated_at, version)
patients(id, user_sub, full_name, phone) -- user_sub = sub из Keycloak
outbox(id, type, payload jsonb, created_at, published_at)
audit_log(id, actor, action, entity, entity_id, at, details jsonb)Инвариант «один слот — одна активная запись»: UNIQUE (slot_id) WHERE status IN ('booked','confirmed') (частичный уникальный индекс).
Риски и допущения
- пиковая нагрузка утром (старт записи на новый период): кэш, очередь, rate limiting;
- ПДн: классификация данных, маскирование, права доступа, ретенция;
- зависимость от SMS/Email провайдера: ретраи, очередь, деградация;
- одиночный кластер → HA на уровне приложения и БД (реплика, бэкапы);
- допущения и ограничения фиксируются в документе.
Что делаем
- Описать роли, сценарии и MVP-границы (что не входит);
- Зафиксировать нефункциональные требования с числами;
- Определить SLI/SLO и error budget, политику при расходе;
- Нарисовать архитектурную схему (C4: контекст и контейнеры) и сценарий запроса;
- Оформить 6–8 ADR с альтернативами;
- Спроектировать модель данных и ключевые инварианты;
- Перечислить риски и план их снижения;
- Определить стратегию окружений (dev/staging/prod), тестирования и релизов.
Результат / артефакты
docs/requirements.md(функциональные и нефункциональные требования, SLO);docs/architecture.md+ диаграммы (C4 context/container, последовательность записи на приём);docs/adr/0001…0008-*.md;- схема БД (ER-диаграмма) и черновик миграций;
- реестр рисков; definition of done для MVP.
Что рассказать на собесе
- как из бизнес-сценариев получили измеримые требования и SLO, и как они повлияли на архитектуру (например, бронирование слота через ограничения БД, а не блокировки приложения);
- почему модульный монолит, а не микросервисы, и когда будете разделять;
- как обеспечен инвариант «нет двойной записи» при конкурентных запросах;
- какие компромиссы приняты (ADR) и что изменилось бы при росте нагрузки;
- как требования безопасности и ПДн отражены в дизайне.