Skip to content

Redesign transactional emails (embedded navy-violet templates) + display name endpoint - #204

Merged
thomasluizon merged 1 commit into
mainfrom
feature/166-167-emails-display-name
Jun 12, 2026
Merged

Redesign transactional emails (embedded navy-violet templates) + display name endpoint#204
thomasluizon merged 1 commit into
mainfrom
feature/166-167-emails-display-name

Conversation

@thomasluizon

@thomasluizon thomasluizon commented Jun 12, 2026

Copy link
Copy Markdown
Owner

Summary

#166 — Transactional email redesign. All five emails (verification code, welcome, account deletion, agent step-up reuse, internal support) move out of interpolated C# strings into embedded-resource .html/.txt templates under src/Orbit.Infrastructure/Email/Templates/ with ONE shared layout. A single-pass {{token}} renderer (no templating library; values are never re-scanned, so user content cannot inject tokens) composes them. Restyled on the navy-violet orbital system, dark navy baked in: #020618 canvas, flattened #111526 cards, violet #7F46F7 pill CTA with glow, gradient header band on welcome with solid bgcolor Outlook fallback, Rubik/Inter/Roboto stacks with system fallbacks, hosted no-bg logo with styled alt-text wordmark fallback. Every user-facing email now ships a plain-text part and a preheader. Copy and subjects are byte-identical (the 13 pre-existing email tests pass unchanged). IEmailService and all callers untouched.

#167 (backend) — Editable display name. PUT /api/profile/nameSetNameCommandUser.SetName (trims, rejects empty/whitespace, max 50 chars via DomainConstants.MaxUserNameLength; no uniqueness, it is a display name). FluentValidation mirrors the domain rules. Action registered in the agent catalog under ProfilePreferencesWrite.

Refs thomasluizon/orbit-ui-mobile#166
Refs thomasluizon/orbit-ui-mobile#167
Paired frontend PR: thomasluizon/orbit-ui-mobile#171 — merge THIS PR first (API contract).

Manual render check (#166 acceptance — run before merge)

  • Gmail web: verification, welcome, deletion (navy canvas, violet code well, pill CTA, logo)
  • Gmail Android: same three
  • Outlook: welcome header degrades to solid violet-950 band; squared cards acceptable; CTA legible
  • Apple Mail: Rubik/Inter load via @import; gradient renders
  • Images blocked: styled "Orbit" alt wordmark shows in the header
  • Plain-text part present on all user-facing emails

Validation

  • dotnet build 0 errors; dotnet test 3,196/3,196 (Domain 358 / Infrastructure 1,020 / Application 1,818)
  • New tests: renderer (12, incl. token-injection guard + embedded-resource loading), service (11, incl. text part + preheader + encoding), SetName domain/handler/validator (18)

🤖 Generated with Claude Code

…dpoint

Extract all five transactional emails into embedded-resource HTML/text
templates with a shared layout and a single-pass {{token}} renderer (no
templating library), restyled on the navy-violet orbital system with
plain-text parts and preheaders; copy and subjects unchanged.

Add PUT /api/profile/name backed by SetNameCommand and User.SetName
(trimmed, 1-50 chars, no uniqueness).

Refs thomasluizon/orbit-ui-mobile#166
Refs thomasluizon/orbit-ui-mobile#167

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two well-scoped features land cleanly here.

Email redesign (#166): The move from C# string-interpolated HTML blobs to embedded-resource templates with a shared layout is a clear improvement in maintainability. The single-pass Regex.Replace renderer correctly prevents token-injection (substituted values are never re-scanned), user content is HTML-encoded for HTML templates and URL-encoded for URLs, and the ConcurrentDictionary cache is properly scoped to the assembly lifetime. All five templates ship plain-text parts and preheaders; the HTML/text copy split (htmlCopy encodes userName, textCopy stays raw) is handled correctly. Test coverage is thorough: renderer tests hit every template for leftover tokens, verify the no-rescan invariant, and cover missing-template/missing-token failure paths; service tests verify encoding, gradient header, text-part presence, and the token-injection guard end-to-end.

Display name endpoint (#167): PUT /api/profile/name inherits the class-level [Authorize], uses HttpContext.GetUserId() (no IDOR risk), and the domain guard in User.SetName trims then validates — matching the FluentValidation layer. The DomainConstants.MaxUserNameLength constant flows cleanly through to AppConstants for the validator and the agent catalog description update is accurate. Command, validator, and domain tests cover the boundary cases (exact max, trimmed max, whitespace, accented characters, user-not-found).

@sonarqubecloud

Copy link
Copy Markdown

@thomasluizon
thomasluizon merged commit eb4e83c into main Jun 12, 2026
6 checks passed
@thomasluizon
thomasluizon deleted the feature/166-167-emails-display-name branch June 12, 2026 20:02
thomasluizon added a commit that referenced this pull request Jul 1, 2026
AgentCatalogServiceTests.EveryControllerAction_IsMappedToTheCatalog requires
every controller action be registered; add ChallengesController.GetMine and
SetHabits to the Manage Social capability's controller-action registry.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
thomasluizon added a commit that referenced this pull request Jul 1, 2026
Adds ChallengeValidatorsTests for GetUserChallengesQueryValidator and
SetChallengeHabitsCommandValidator (previously 0% covered), lifting new-code
coverage above the 80% quality gate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
thomasluizon added a commit that referenced this pull request Jul 1, 2026
#276)

* feat(api): challenges list endpoint, invite push, participant set-habits (#204)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(api): map challenges list + set-habits to agent catalog (#204)

AgentCatalogServiceTests.EveryControllerAction_IsMappedToTheCatalog requires
every controller action be registered; add ChallengesController.GetMine and
SetHabits to the Manage Social capability's controller-action registry.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test(api): cover challenges list + set-habits validators (#204)

Adds ChallengeValidatorsTests for GetUserChallengesQueryValidator and
SetChallengeHabitsCommandValidator (previously 0% covered), lifting new-code
coverage above the 80% quality gate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant