using System;
using Ban.Sdaid.Notation.Documents;
using Ban.Sdaid.Icd;
namespace Ban.Sdaid.Icd.Arch.Tech.CSharp
{
/// <summary>
/// ADR-SRV-004: Конфигурация бэка по средам и CORS. Параметры среды — в appsettings
/// (подменяются деплоем), CORS-origins фронта — из конфига (allowlist по среде).
/// </summary>
public class ADR_SRV_004_AppConfigAndCors : IAdrDocument, IFolder<ArchCSharpFolder>
{
public string Name => "ADR-SRV-004. Конфигурация бэка и CORS";
public string Description =>
@"Бэк должен разворачиваться на стенде, где фронт и API — на разных origin. Фиксируем: параметры
среды берутся из appsettings (стандартный конфиг ASP.NET, подменяется деплоем), список разрешённых
origin фронта — из `Cors:AllowedOrigins` (allowlist по среде); в локальной разработке (список пуст) CORS
разрешает любой origin. Swagger UI — только вне прода.";
public string Version => "1.0";
public string Status => "accepted";
public string[] Comments => new[]
{
"2026-08-13. Принято перед разворачиванием на стенде (фронт и API на разных origin).",
};
public Type? Supersedes => null;
public static string S1_Context = """
## Контекст и постановка задачи
Сервис разворачивается на стендах (dev/stage/prod). Фронт и API там — на **разных origin**,
поэтому бэку нужен **CORS-allowlist**: браузер разрешит запрос со страницы фронта, только если
его origin в списке разрешённых. Список различается по среде, а артефакт сборки — один, значит
origin'ы нельзя «зашивать» в код.
Нужно зафиксировать: откуда бэк берёт параметры среды и как настраивается CORS, чтобы
разворачивание было предсказуемым, а локальная разработка не требовала ручной настройки.
""";
public static string S2_DecisionDrivers = """
## Драйверы решения
1. **Один билд на все среды** — параметры подменяются конфигом, не пересборкой.
2. **Безопасность CORS** — на стенде разрешаем только известные origin фронта, не «любой».
3. **Ноль трения локально** — `ng serve` на :4200 ходит на бэк без ручной настройки CORS.
4. **Стандартные механизмы ASP.NET** — `appsettings`, `IConfiguration`, без своих слоёв.
""";
public static string S3_ConsideredOptions = """
## Рассмотренные варианты
- **A (выбран).** Параметры среды — в `appsettings`; `Cors:AllowedOrigins` — allowlist из конфига;
пустой список = разрешить любой origin (локальная разработка).
- **B.** Всегда `AllowAnyOrigin`. Просто, но на стенде небезопасно.
- **C.** Origin'ы в переменных окружения/коде. Дробит конфиг, хуже читается, чем один `appsettings`.
""";
public static string S4_DecisionOutcome = """
## Решение
Выбран **Вариант A**.
### Параметры среды — в appsettings
`appsettings.json` — стандартный конфиг ASP.NET (`IConfiguration`). На стенде файл подменяется
деплоем (генерится `devops/configs-generator` вместе с рантайм-конфигом фронта). В репозитории —
значения для локальной разработки. Имя окружения задаётся `ASPNETCORE_ENVIRONMENT` при запуске.
### CORS — allowlist из конфига
```
"Cors": { "AllowedOrigins": ["https://sok.dev.example"] }
```
```csharp
var allowedOrigins = builder.Configuration.GetSection("Cors:AllowedOrigins").Get<string[]>() ?? [];
builder.Services.AddCors(o => o.AddPolicy(policy, p =>
{
if (allowedOrigins.Length > 0)
p.WithOrigins(allowedOrigins).AllowAnyHeader().AllowAnyMethod();
else
p.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod(); // локальная разработка
}));
app.UseCors(policy);
```
- **Список задан** (стенд) → разрешаем только эти origin.
- **Список пуст** (локальная разработка) → разрешаем любой origin, чтобы `ng serve` работал без
настройки.
### Swagger UI — только вне прода
Браузерная страница `/swagger` включается только при `ASPNETCORE_ENVIRONMENT=Development`
(на проде — выключена). Сам контракт `/openapi/v1.json` отдаётся всегда.
### Что не делаем
- Не зашиваем origin'ы в код.
- Не оставляем `AllowAnyOrigin` на стенде.
- Не заводим свой слой конфигурации поверх `IConfiguration`.
""";
public static string S5_PositiveConsequences = """
## Положительные следствия
- Один билд → все среды; CORS и параметры меняет только конфиг.
- На стенде CORS ограничен известными origin.
- Локальная разработка — без ручной настройки CORS.
""";
public static string S6_NegativeConsequences = """
## Отрицательные следствия и компромиссы
- Пустой список = «любой origin» удобен локально, но опасен, если случайно уедет на стенд —
поэтому на стендах список **обязателен** и проверяется при деплое.
""";
public static string S7_Validation = """
## Проверка
- С заданным `Cors:AllowedOrigins` запрос с чужого origin блокируется браузером, с разрешённого — проходит.
- С пустым списком локальный `ng serve` (:4200) ходит на бэк (:5080) без ошибок CORS.
- На проде `/swagger` недоступен; `/openapi/v1.json` доступен.
""";
public static string S8_OpenQuestions = """
## Открытые вопросы / отложено
- **Строки подключения к БД** — появятся в `appsettings` с введением персистентности (ADR-SRV-003).
- **Секреты** — не в коммитимом `appsettings`: локально — `appsettings.Local.json` (в `.gitignore`,
подключается в `Program.cs`, грузится в любой среде), на стендах — через devops-генератор /
переменные окружения (напр. `Orthocover:ApiKey`, ADR-SRV-005). Полноценная аутентификация — с auth-срезом.
- **Проверка непустого allowlist на не-Development** — можно добавить fail-fast при старте.
""";
public static string S99_Related = $"""
## Связанные артефакты
- {nameof(Ban.Sdaid.Icd.Arch.Tech.Angular.ADR_UI_014_RuntimeConfig)} — рантайм-конфиг фронта (`config.json`), парная схема.
- {nameof(Ban.Sdaid.Icd.Arch.Tech.CSharp.ADR_SRV_001_Cqrs)} — обёртка ответа и композиция хоста.
""";
}
}