Почистить комментарии от упоминаний процесса

Удалены <remarks>, <summary> сжаты до короткой фразы, вырезаны
ссылки на Task/Ruling/этап/python/прототип; //-комментарии со ссылками
на процесс удалены; то же в .proto. Правила обновлены в
docs/spec/Код-стайл-Дейл.md. Строк комментариев 27210 -> ~19100.
This commit is contained in:
Rustam Khalimov
2026-09-11 13:39:39 +03:00
parent 5f5538d33b
commit b053d58335
902 changed files with 3902 additions and 12074 deletions
+2 -38
View File
@@ -14,21 +14,8 @@ using Deal.Modules.Tenants.Application.Models;
namespace Deal.Api.Endpoints;
/// <summary>
/// Эндпоинты карточек и поиска: GET /api/cards[?containerId=], /cards/counts, /cards/{id},
/// mark-all-seen/mark-col-seen, move/trash/restore/DELETE, clear-col, comments, reclassify (batch + {id}),
/// GET /api/search (этап 9, T6).
/// Эндпоинты карточек и поиска
/// </summary>
/// <remarks>
/// Единый контракт /api/cards (R5): старые ручки /api/leads, /api/projects, /api/boards и /api/columns
/// упразднены. GET /cards →
/// {items}; counts — плоская wire-форма {new, &lt;col&gt;: {count, new}, learning, ml, ai}; move → обновлённая
/// карточка; restore → {ok, col}; clear-col → {ok, cleared}; comments → {comments}; search →
/// {cards, messages: []}. 400 «Неизвестный контейнер» при несуществующем containerId; 404 «Карточка не
/// найдена» — null-результаты сервисов, 400-тексты — константы CardsService.
/// ⚠ Статические сегменты (counts, mark-all-seen, mark-col-seen, clear-col, reclassify) регистрируются ДО
/// /cards/{cardId}. Все эндпоинты требуют сессию: 401 {detail}; сервисы резолвятся из RequestServices
/// ПОСЛЕ проверки сессии.
/// </remarks>
public static class CardsEndpoints
{
// Префикс группы карточек.
@@ -40,26 +27,22 @@ public static class CardsEndpoints
// Путь поиска (GET).
private const string SearchPath = "/search";
// OpenAPI-тег группы (в прототипе роутер dashboard — dashboard_routes.py).
private const string OpenApiTag = "dashboard";
// 404: карточка не найдена (dashboard_routes.py _lead_or_404 L9296).
private const string CardNotFoundDetail = "Карточка не найдена";
// 400 GET /cards: containerId не существует.
private const string UnknownColumnDetail = "Неизвестный контейнер";
// Инициатор перехода при ручном переносе — действие пользователя (R4 этапа 9).
private const string UserActor = "user";
// SSE-тип события завершения переклассификации (этап 12, остаток 2; api.js слушает 'cards_reclassified').
private const string ReclassifiedEventType = "cards_reclassified";
// Контекст ручного перехода карточки: пользователь, обучение ML по цели переноса.
private static readonly TransitionContext UserMoveContext = new() { Actor = UserActor, Learn = true };
/// <summary>
/// Регистрирует группы /api/cards и /api (карточки + поиск). Статические сегменты — до /cards/{cardId}.
/// Регистрирует группы /api/cards и /api
/// </summary>
/// <param name="app">Построитель маршрутов приложения.</param>
/// <returns>Построитель маршрутов для цепочки вызовов.</returns>
@@ -112,7 +95,6 @@ public static class CardsEndpoints
return Results.Ok(new { items = cards });
}
// GET /api/cards/counts: плоская wire-форма счётчиков {new, &lt;col&gt;:{count,new}, learning, ml, ai} (L161163, §4.1 L257).
private static async Task<IResult> CountsAsync(HttpContext context, CancellationToken ct)
{
if (!context.HasUser())
@@ -123,7 +105,6 @@ public static class CardsEndpoints
CardsService cardsService = context.RequestServices.GetRequiredService<CardsService>();
CardCountsDto counts = await cardsService.CountsAsync(ct);
// Разворачивание CardCountsDto: колонки — корневые ключи (counts L268–279), служебные — фиксированные.
var wire = new Dictionary<string, object> { ["new"] = counts.New };
foreach ((string col, CardColumnCountDto column) in counts.Columns)
{
@@ -136,7 +117,6 @@ public static class CardsEndpoints
return Results.Ok(wire);
}
// GET /api/cards/{cardId}: одна карточка; 404 «Карточка не найдена» (L166–168).
private static async Task<IResult> GetCardAsync(
string cardId,
HttpContext context,
@@ -154,7 +134,6 @@ public static class CardsEndpoints
: Results.Ok(card);
}
// POST /api/cards/mark-all-seen: снять «новое» со всех карточек (L177–180); ответ {ok:true}.
private static async Task<IResult> MarkAllSeenAsync(HttpContext context, CancellationToken ct)
{
if (!context.HasUser())
@@ -167,7 +146,6 @@ public static class CardsEndpoints
return Results.Ok(new { ok = true });
}
// POST /api/cards/mark-col-seen: снять «новое» с колонки (L187–191); ответ {ok:true}.
private static async Task<IResult> MarkColSeenAsync(
MarkColBody body,
HttpContext context,
@@ -181,7 +159,6 @@ public static class CardsEndpoints
if (body.Col is null)
{
// Пустая/отсутствующая col попала бы в mark_seen как «не задана» и сняла бы «новое» со ВСЕХ
// карточек (truthiness python, L250256) — эндпоинт защищает от вызова с null (прототип: 422).
return EndpointResults.BadRequest(UnknownColumnDetail);
}
@@ -190,7 +167,6 @@ public static class CardsEndpoints
return Results.Ok(new { ok = true });
}
// POST /api/cards/{cardId}/move {to}: перенос карточки между контейнерами (этап 9, R4).
// Маршрутизацию цели (стадия «Выбранных» vs дашборд-контейнер) и побочные эффекты выполняет единый
// доменный механизм перехода ICardMover: стадия — запись истории и сброс напоминания
// (move_stage), дашборд-контейнер — журнал/обучение ML. Ответ — обновлённая карточка; 400 при
@@ -218,7 +194,6 @@ public static class CardsEndpoints
return EndpointResults.NotFound(CardNotFoundDetail);
}
// Аудит переноса карточки (этап 10, T1): цель — минимальный безопасный идентификатор.
await AuditAppender.AppendTenantAsync(context, AuditEvents.CardMoved, new { cardId, to = body.To }, ct);
CardsService cardsService = context.RequestServices.GetRequiredService<CardsService>();
@@ -228,7 +203,6 @@ public static class CardsEndpoints
: Results.Ok(unified);
}
// POST /api/cards/{cardId}/trash: в корзину + обучение ML spam (L203207); ответ {ok:true}; 404.
private static async Task<IResult> TrashAsync(
string cardId,
HttpContext context,
@@ -246,12 +220,10 @@ public static class CardsEndpoints
return EndpointResults.NotFound(CardNotFoundDetail);
}
// Аудит отправки карточки в корзину (этап 10, T1).
await AuditAppender.AppendTenantAsync(context, AuditEvents.CardTrashed, new { cardId }, ct);
return Results.Ok(new { ok = true });
}
// POST /api/cards/{cardId}/restore: возврат из архив/корзины на канбан (L210–214); ответ {ok, col}; 404.
private static async Task<IResult> RestoreAsync(
string cardId,
HttpContext context,
@@ -269,12 +241,10 @@ public static class CardsEndpoints
return EndpointResults.NotFound(CardNotFoundDetail);
}
// Аудит возврата карточки из корзины/архива (этап 10, T1).
await AuditAppender.AppendTenantAsync(context, AuditEvents.CardRestored, new { cardId, col }, ct);
return Results.Ok(new { ok = true, col });
}
// DELETE /api/cards/{cardId}: удалить навсегда (Cards + комментарии; L217221); ответ {ok:true}; 404.
private static async Task<IResult> DeleteAsync(
string cardId,
HttpContext context,
@@ -292,12 +262,10 @@ public static class CardsEndpoints
return EndpointResults.NotFound(CardNotFoundDetail);
}
// Аудит удаления карточки навсегда (этап 10, T1).
await AuditAppender.AppendTenantAsync(context, AuditEvents.CardDeleted, new { cardId }, ct);
return Results.Ok(new { ok = true });
}
// POST /api/cards/clear-col {col}: очистить корзину/архив (L228–235); ответ {ok, cleared}; 400.
private static async Task<IResult> ClearColAsync(
ClearColBody body,
HttpContext context,
@@ -315,7 +283,6 @@ public static class CardsEndpoints
: Results.Ok(new { ok = true, cleared = result.Cleared });
}
// POST /api/cards/{cardId}/comments {text}: добавить комментарий (L238–242); ответ {comments}; 400 «Пустой комментарий»; 404.
private static async Task<IResult> AddCommentAsync(
string cardId,
CommentBody body,
@@ -339,7 +306,6 @@ public static class CardsEndpoints
return EndpointResults.NotFound(CardNotFoundDetail);
}
// Аудит добавления комментария (этап 10, T1): текст комментария в детали не пишется.
await AuditAppender.AppendTenantAsync(context, AuditEvents.CardCommentAdded, new { cardId }, ct);
return Results.Ok(new { comments = result.Comments });
}
@@ -414,7 +380,6 @@ public static class CardsEndpoints
reason = result.Reason,
};
// Публикует SSE cards_reclassified после успешного прохода (Ruling 5: публикации — из Api).
// Публикуется только когда проход реально выполнен и что-то изменил (started и
// reclassified &gt; 0): пустой inbox/всё пропущено не меняют доску — событие не шлём. Нагрузка
// минимальная: сколько обработано и перемещено (фронт перечитывает доску). Без подписчиков — no-op.
@@ -455,7 +420,6 @@ public static class CardsEndpoints
ct);
}
// GET /api/search?q=: поиск карточек (FTS + LIKE, Ruling 6/Task 12; dashboard_routes L254256). Ответ {leads, messages: []}.
private static async Task<IResult> SearchAsync(
string? q,
HttpContext context,