feat(career): theme polish, rich-text bullets, entry ordering, outline API
CI and Deploy / test (push) Failing after 1m55s
CI and Deploy / deploy (push) Has been skipped

Phase 4.5 backend enablers.
- Themes (priority 3): AtsFriendly flag on single-column themes (surfaced in
  GET /api/cv/themes), print-quality page-break rules (entries never split
  across a page; headings stay with content; widow/orphan control), darkened
  the creative sidebar for AA contrast.
- Rich text (priority 1): bullets/summary support **bold**, *italic*,
  __underline__, [text](url) via a safe inline pass — everything is HTML-escaped
  first, so no user tag can survive; only the whitelist emits markup.
- Entry ordering (priority 1): CvSectionSetting.ItemOrder reorders entries
  within a section by ItemKey, never touching the master profile.
- Outline API: GET /api/cv/outline returns the master profile as sections+entries
  with ItemKeys, so the Content tab can render editable per-item rows.
- 3 new tests (22 total in the builder suite).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
cesnimda
2026-07-18 14:38:35 +02:00
parent 585047da9e
commit e3b255f226
7 changed files with 121 additions and 7 deletions
@@ -50,11 +50,22 @@ public sealed class CvVariantController : ControllerBase
accent = t.Accent,
photoShape = t.PhotoShape,
supportsIcons = t.DefaultIcons,
atsFriendly = t.AtsFriendly,
swatches = new[] { t.Accent, t.SidebarBg, t.Paper },
});
return Ok(themes);
}
// The master profile as sections+entries (with ItemKeys) — the Content tab reads this to render
// editable rows without duplicating the profile shape on the client.
[HttpGet("outline")]
public async Task<ActionResult<CvRenderModel>> Outline(CancellationToken ct)
{
var user = await _users.GetUserAsync(User);
if (user is null) return Unauthorized();
return Ok(await _variants.OutlineAsync(user.Id, Person(user), ct));
}
[HttpGet("variants")]
public async Task<ActionResult<IEnumerable<CvVariantSummary>>> List(CancellationToken ct)
{