From e3b255f2269e79dd6ac4d03688f587a126f7032c Mon Sep 17 00:00:00 2001 From: cesnimda Date: Sat, 18 Jul 2026 14:38:35 +0200 Subject: [PATCH] feat(career): theme polish, rich-text bullets, entry ordering, outline API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- JobTrackerApi.Tests/CvBuilderTests.cs | 40 +++++++++++++++++++ .../Controllers/CvVariantController.cs | 11 +++++ JobTrackerApi/Services/CvRenderModel.cs | 21 ++++++++++ JobTrackerApi/Services/CvVariantService.cs | 8 ++++ JobTrackerApi/Services/ThemedCvRenderer.cs | 28 ++++++++++++- Models/CvTheme.cs | 16 +++++--- Models/CvVariantSettings.cs | 4 ++ 7 files changed, 121 insertions(+), 7 deletions(-) diff --git a/JobTrackerApi.Tests/CvBuilderTests.cs b/JobTrackerApi.Tests/CvBuilderTests.cs index b696ad4..b7e6917 100644 --- a/JobTrackerApi.Tests/CvBuilderTests.cs +++ b/JobTrackerApi.Tests/CvBuilderTests.cs @@ -124,6 +124,46 @@ public sealed class CvBuilderTests Assert.DoesNotContain("class=\"sidebar\"", minimal.Html); } + [Fact] + public void Bullets_support_safe_inline_markdown_and_escape_everything_else() + { + var renderer = new ThemedCvRenderer(); + var profile = new StructuredCvProfile { Summary = { "**bold** and *italic* and __under__ and [site](https://x.io) " } }; + var model = CvVariantResolver.Build(profile, new CvVariantSettings(), "F", null); + var html = renderer.Render(model, CvThemeCatalog.Resolve("modern"), new CvVariantSettings { ThemeId = "modern" }).Html; + Assert.Contains("bold", html); + Assert.Contains("italic", html); + Assert.Contains("under", html); + Assert.Contains("site", html); + Assert.Contains("<script>", html); // the real tag is escaped, inert + Assert.DoesNotContain("