Skip to content

feat(frontend,email): Archera Insurance CTA in modals + education pages + email mentions (closes #314)#336

Open
cristim wants to merge 3 commits into
feat/multicloud-web-frontendfrom
feat/issue-314-archera-modal-cta
Open

feat(frontend,email): Archera Insurance CTA in modals + education pages + email mentions (closes #314)#336
cristim wants to merge 3 commits into
feat/multicloud-web-frontendfrom
feat/issue-314-archera-modal-cta

Conversation

@cristim
Copy link
Copy Markdown
Member

@cristim cristim commented May 11, 2026

Summary

Fourth and final iteration of issue #314. Frontend + email-template scope, no IaC, no API/handler changes.

What this PR ships

Modal CTAs (soft, non-blocking, both link to the Archera education overlay):

  • Inside openPurchaseModal (frontend/src/recommendations.ts):

    Insure this commitment with Archera →

  • Inside openCreatePlanModal + openNewPlanModal (frontend/src/plans.ts):

    Insure this plan with Archera →

Both rendered as small secondary text-links — not buttons competing with the primary action. TODO(@cristim): final copy markers next to each.

Education pages (full-viewport overlay, hash-friendly):

  • Page A — "What is Archera Insurance?" opens with a "Why is CUDly telling me about this?" lead section that surfaces two transparency disclosures BEFORE getting into product detail:

    1. CUDly is fully functional regardless of whether you enroll in Archera Insurance. Nothing in CUDly is gated.
    2. Archera sponsors CUDly's development with a fraction of their insurance revenue. The honest reason CUDly surfaces this option.

    Then: plain-language explainer of commitment-overuse insurance, when it makes sense, and the 7-day post-purchase enrollment window.

  • Page B — "How the CUDly ↔ Archera integration works" carries a shorter "Disclosure" subheading near the top mirroring both facts in one sentence each, then the step-by-step integration flow (signup → Archera's own pre-filled IaC for AWS/GCP / OAuth consent for Azure → cost-data ingestion).

Both pages cross-link and carry https://archera.ai/signup?mode=cudly (target=_blank, rel="noopener noreferrer").

Email surfaces (new in this iteration):

  • internal/email/templates.gopurchaseApprovalRequestTemplate (plain text) + purchaseApprovalRequestHTMLTemplate (HTML): brief Archera Insurance mention near the bottom noting the buyer will have 7 days from each purchase to enroll. Links to the education page.
  • internal/email/templates.gopurchaseConfirmationTemplate: more prominent placement (7-day clock now active) with direct signup link.
  • template_renderers.go extended to populate ArcheraEducationURL on the relevant data structs.

Skipped (per #314's body): purchaseFailedTemplate, scheduledPurchaseTemplate, RI exchange templates.

Regression-guard tests:

  • Both education pages assert presence of both disclosure facts (no-gating + sponsorship-revenue) — so future copy edits can't silently remove them.
  • Email render tests assert "Archera" + "7 days" + signup-link string in both approval and confirmation templates.

Why the previous directions were abandoned

PR Direction Why closed
#310 Bundle Archera IAM trust policy into CUDly's federation IaC (a) External ID is derived from customer's Archera org ID which only exists post-signup; (b) Azure integration is OAuth consent, not RBAC role; (c) Archera ships pre-filled IaC themselves — duplicating creates drift surface
#315 Shared Terraform module + Settings → Federation Setup checkbox Same three problems + Settings is the wrong conversion moment
(cancelled) Settings checkbox + signup link Settings is the wrong UX moment — high-intent surfaces are at purchase time
#336 (this) Modal CTA + education pages + email mentions Right surfaces, no IAM duplication, transparency disclosures land where users will see them

Acceptance criteria

  • Purchase modal renders the simplified CTA; click opens Page A.
  • Plan-creation modal (both openCreatePlanModal and openNewPlanModal paths) renders the simplified CTA; same target.
  • Page A leads with the transparency disclosures (no-gating + sponsorship) before product detail.
  • Page B includes a "Disclosure" subheading mirroring both facts.
  • Both pages cross-link + carry signup link.
  • purchaseApprovalRequestTemplate + HTML variant mention Archera + 7-day window + education-page link.
  • purchaseConfirmationTemplate mentions Archera + 7-day window + direct signup link.
  • Frontend tests for CTAs + page navigation + signup-link attributes.
  • Regression-guard tests asserting both disclosure facts appear on both pages.
  • Email render tests asserting Archera mention + 7-day window + signup link.
  • Accessibility: CTAs are <button> elements with discernible names; overlay has role=region + aria-label; back button keyboard-reachable; heading hierarchy (h1 → h2) within overlay.
  • TODO(@cristim): final copy / TODO(@cristim): final disclosure copy markers left wherever wording is provisional.

Not in scope

  • Settings → Federation Setup checkbox (dropped from earlier iterations).
  • API / handler changes — none.
  • Bundle template changes — none (internal/iacfiles/templates/, iac/federation/, iac/modules/, terraform/environments/<cloud>/archera.tf, scripts/generate-federation-iac.go, scripts/check-archera-parity.sh — untouched).
  • Authentication / payment integration — none (signup happens on Archera's side).

TODO(@cristim) markers left for review

Location What needs review
Page A "Why is CUDly telling me about this?" Final disclosure copy (no-gating + sponsorship wording)
Page A intro paragraph Plain-language explainer wording
Page A "How it works" section Revenue model description
Page B "Disclosure" subheading Shorter disclosure wording
Page B step 1 Confirm exact onboarding URL/flow with Archera
Page B step 2 Confirm "Terraform/CloudFormation" for AWS and GCP
Page B "Disclaimers" Disclaimer language with legal/Archera
Both modal CTAs "Insure this commitment with Archera →" / "Insure this plan with Archera →" wording
Both email templates Final Archera section copy + 7-day window wording

Closes / Supersedes

Summary by CodeRabbit

  • New Features
    • Integrated Archera Insurance education overlay with pages, signup CTA, and deep-link handling; CTAs injected into purchase and plan modals
  • Email
    • Added conditional Archera content to purchase approval and confirmation emails (7-day enrollment info when present)
  • Style
    • New styles for modal CTAs and full-page education overlay
  • Tests
    • Expanded test coverage for overlay, deeplinks, CTA injection, and email template rendering

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 11, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f1c07bb8-732e-4947-b673-1625a3da5967

📥 Commits

Reviewing files that changed from the base of the PR and between 0de11a5 and 6c2b5c7.

📒 Files selected for processing (12)
  • frontend/src/__tests__/archera.test.ts
  • frontend/src/app.ts
  • frontend/src/archera.ts
  • frontend/src/index.html
  • frontend/src/plans.ts
  • frontend/src/recommendations.ts
  • frontend/src/styles/modals.css
  • internal/api/handler_purchases.go
  • internal/email/sender.go
  • internal/email/template_renderers_test.go
  • internal/email/templates.go
  • internal/purchase/execution.go
✅ Files skipped from review due to trivial changes (4)
  • internal/email/sender.go
  • internal/purchase/execution.go
  • frontend/src/recommendations.ts
  • frontend/src/styles/modals.css
🚧 Files skipped from review as they are similar to previous changes (5)
  • frontend/src/plans.ts
  • frontend/src/app.ts
  • frontend/src/tests/archera.test.ts
  • internal/email/template_renderers_test.go
  • frontend/src/archera.ts

📝 Walkthrough

Walkthrough

Added a complete Archera Insurance integration: a frontend module rendering CTAs and a two-page education overlay, injected into purchase and plan modals, wired into app deeplinks, with HTML/CSS, backend NotificationData/template additions, and frontend + backend tests.

Changes

Archera Insurance Education Overlay Integration

Layer / File(s) Summary
Module Exports and Type Definitions
frontend/src/archera.ts
Exports ARCHERA_SIGNUP_URL and page/path types; module-level focus state.
CTA Rendering
frontend/src/archera.ts
renderArcheraCTA() creates a paragraph CTA with a context-aware button that opens the overlay.
Overlay State Management
frontend/src/archera.ts
openArcheraPage(pageId) shows overlay and renders selected page; closeArcheraPage() hides/clears and restores focus.
Deeplink Handler & App Init
frontend/src/archera.ts, frontend/src/app.ts
handleArcheraDeeplink() matches trimmed window.location.pathname and opens Page A/B; app.init() calls the handler during startup.
Page A Content
frontend/src/archera.ts
Renders "What is Archera Insurance?" with disclosures, titled bullet sections, cross-link to Page B, and signup block.
Page B Content
frontend/src/archera.ts
Renders "How the CUDly ↔ Archera integration works" with short disclosure, ordered steps, disclaimers, cross-link to Page A, and signup block.
Shared Helpers
frontend/src/archera.ts
appendDisclosureSection(), buildBackButton(), appendSection(), buildSignupBlock() support page rendering/navigation.
HTML Container
frontend/src/index.html
Adds hidden #archera-page-container div to host overlay content.
Styling
frontend/src/styles/modals.css
Adds .archera-cta styles and full-viewport overlay styles, inner layout, steps, cross-links/back, and signup block/button styling.
Purchase Modal Integration
frontend/src/recommendations.ts
Imports renderArcheraCTA and appends CTA into purchase modal after approval-required note and before commitments table.
Plan Modal Integration
frontend/src/plans.ts
Imports renderArcheraCTA; injectPlanModalCTA() inserts CTA before .modal-buttons with #archera-plan-cta dedupe; wired into both plan modal openers.
Frontend Tests
frontend/src/__tests__/archera.test.ts
Jest tests: DOM teardown/setup, CTA element structure/click behavior, Page A/B content and navigation, disclosure content, deeplink gating, and modal CTA injection/deduplication.
Email Payload & Templates
internal/api/handler_purchases.go, internal/purchase/execution.go, internal/email/sender.go, internal/email/templates.go
Adds ArcheraEducationURL to NotificationData, normalizes dashboard base, populates Archera education URL, and conditionally renders Archera blocks in email templates.
Email Template Tests
internal/email/template_renderers_test.go
Go tests asserting presence/absence of Archera content, enrollment-window wording, and expected URLs when ArcheraEducationURL is set or empty.

Sequence Diagram

sequenceDiagram
  participant User
  participant Modal as Purchase/Plan Modal
  participant Archera as Archera Module
  participant Overlay as Archera Overlay

  User->>Modal: Open purchase or plan modal
  Modal->>Archera: renderArcheraCTA()
  Archera-->>Modal: CTA element appended to modal

  User->>Modal: Click CTA button
  Modal->>Archera: openArcheraPage('what-is-archera')
  Archera->>Overlay: Populate `#archera-page-container` with Page A
  Overlay-->>User: Show Page A content

  User->>Overlay: Click cross-link to "how-it-works"
  Overlay->>Archera: openArcheraPage('how-it-works')
  Archera->>Overlay: Clear & render Page B
  Overlay-->>User: Show Page B steps

  User->>Overlay: Click Back
  Overlay->>Archera: closeArcheraPage()
  Archera->>Overlay: Hide and clear container
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

Possibly related PRs

Poem

🐰 I stitched a little CTA to play,

Two pages hop to show the way,
Cross-links skip, a signup gleams,
Tests ensure the overlay beams,
Click, learn, and then bound away!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 76.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: adding Archera Insurance CTAs to modals, creating education pages, and updating email templates, with a reference to the closed issue #314.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/issue-314-archera-modal-cta

Comment @coderabbitai help to get the list of available commands and usage tips.

@cristim cristim added priority/p2 Backlog-worthy severity/medium Moderate harm urgency/this-quarter Within the quarter impact/many Affects most users effort/m Days type/feat New capability triaged Item has been triaged labels May 11, 2026
@cristim
Copy link
Copy Markdown
Member Author

cristim commented May 11, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 11, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontend/src/__tests__/archera.test.ts`:
- Around line 87-166: The tests append fixed-ID DOM nodes via
buildArcheraContainer, buildPurchaseModalDOM, and buildPlanModalDOM but never
remove them, causing stale-node collisions between tests; add a teardown to
clear those nodes between tests (e.g. an afterEach that removes elements with
IDs 'archera-page-container', 'purchase-modal', 'plan-modal' or simply resets
document.body.innerHTML = ''), ensuring each test starts with a clean DOM and
preventing selector bleed from previous runs.

In `@frontend/src/archera.ts`:
- Around line 70-100: When opening the overlay in openArcheraPage, capture and
save the currently focused element (e.g., const previouslyFocused =
document.activeElement as HTMLElement | null) onto the container (or a
module-scoped variable) before moving focus to the back button; then in
closeArcheraPage, after hiding/clearing the container, restore focus to that
saved element if it still exists in the document (and is focusable) and then
clear the saved reference. Update functions openArcheraPage and closeArcheraPage
to use the same storage location for the saved element and guard restoration
with a type check and document.contains to avoid errors.

In `@frontend/src/styles/modals.css`:
- Around line 238-244: The Archera overlay (`#archera-page-container`) currently
has z-index: 900 which is lower than modal layers (.modal / .modal-overlay at
1000); update `#archera-page-container` to use a z-index higher than the modal
layers (e.g., 1100) so the education page renders on top of open modals, keeping
position: fixed and overflow-y: auto intact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: efb411d6-fb2d-48a2-8297-1f385bdccb54

📥 Commits

Reviewing files that changed from the base of the PR and between c95a6ac and 5d3b205.

📒 Files selected for processing (6)
  • frontend/src/__tests__/archera.test.ts
  • frontend/src/archera.ts
  • frontend/src/index.html
  • frontend/src/plans.ts
  • frontend/src/recommendations.ts
  • frontend/src/styles/modals.css

Comment thread frontend/src/__tests__/archera.test.ts
Comment thread frontend/src/archera.ts
Comment thread frontend/src/styles/modals.css
@cristim cristim changed the title feat(frontend): Archera Insurance CTA in Purchase + Plan-creation modals + education pages (closes #314) feat(frontend,email): Archera Insurance CTA in modals + education pages + email mentions (closes #314) May 11, 2026
@cristim
Copy link
Copy Markdown
Member Author

cristim commented May 11, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 11, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/api/handler_purchases.go (1)

1266-1277: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Guard ArcheraEducationURL assignment when dashboard base is empty.

At Line 1277, dashboardBase + "/archera-insurance" is set unconditionally. If dashboardBase == "", emails still render the Archera block with a relative URL, which is usually invalid in email clients. Only set this field when dashboardBase is non-empty so templates can omit the block as intended.

💡 Suggested patch
   dashboardBase := h.resolveDashboardURL(req)
   data := email.NotificationData{
     DashboardURL:        dashboardBase,
     ApprovalToken:       execution.ApprovalToken,
     ExecutionID:         execution.ExecutionID,
     TotalSavings:        totalSavings,
     TotalUpfrontCost:    totalUpfront,
     Recommendations:     summaries,
     RecipientEmail:      to,
     CCEmails:            cc,
     AuthorizedApprovers: approvers,
-    ArcheraEducationURL: dashboardBase + "/archera-insurance",
   }
+  if dashboardBase != "" {
+    data.ArcheraEducationURL = dashboardBase + "/archera-insurance"
+  }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/api/handler_purchases.go` around lines 1266 - 1277, The
ArcheraEducationURL field on the email.NotificationData is unconditionally set
to dashboardBase + "/archera-insurance", which yields a relative URL when
dashboardBase is empty; update the construction of email.NotificationData so
ArcheraEducationURL is only populated when dashboardBase is non-empty (e.g.,
check the resolved dashboardBase from h.resolveDashboardURL(req) and set
ArcheraEducationURL to the concatenated string only if dashboardBase != ""
otherwise leave it empty or omit), locating this change around the
NotificationData literal that includes DashboardURL, ApprovalToken, ExecutionID,
etc., and ensure any template logic relies on an empty value to skip rendering
the Archera block.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontend/src/archera.ts`:
- Around line 93-96: The code currently overwrites _previouslyFocused on every
openArcheraPage(...) call; change openArcheraPage so it only captures
document.activeElement into _previouslyFocused when the overlay is transitioning
from hidden to visible (i.e., when there is no current _previouslyFocused or
when the overlay is not currently visible), rather than on every call. In
practice update openArcheraPage to check the overlay visibility/state (or
whether _previouslyFocused is null) before assigning _previouslyFocused =
document.activeElement instanceof HTMLElement ? document.activeElement : null,
and leave closeArcheraPage unchanged so it can restore the original opener
focus.

---

Outside diff comments:
In `@internal/api/handler_purchases.go`:
- Around line 1266-1277: The ArcheraEducationURL field on the
email.NotificationData is unconditionally set to dashboardBase +
"/archera-insurance", which yields a relative URL when dashboardBase is empty;
update the construction of email.NotificationData so ArcheraEducationURL is only
populated when dashboardBase is non-empty (e.g., check the resolved
dashboardBase from h.resolveDashboardURL(req) and set ArcheraEducationURL to the
concatenated string only if dashboardBase != "" otherwise leave it empty or
omit), locating this change around the NotificationData literal that includes
DashboardURL, ApprovalToken, ExecutionID, etc., and ensure any template logic
relies on an empty value to skip rendering the Archera block.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7bd02675-c0a6-4aee-9d44-016f2cab97f0

📥 Commits

Reviewing files that changed from the base of the PR and between 5d3b205 and 0de11a5.

📒 Files selected for processing (10)
  • frontend/src/__tests__/archera.test.ts
  • frontend/src/app.ts
  • frontend/src/archera.ts
  • frontend/src/plans.ts
  • frontend/src/styles/modals.css
  • internal/api/handler_purchases.go
  • internal/email/sender.go
  • internal/email/template_renderers_test.go
  • internal/email/templates.go
  • internal/purchase/execution.go
✅ Files skipped from review due to trivial changes (1)
  • internal/purchase/execution.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • frontend/src/plans.ts
  • frontend/src/styles/modals.css

Comment thread frontend/src/archera.ts Outdated
cristim added a commit that referenced this pull request May 11, 2026
PR #333 (closes #332) landed a botched merge of `unset_falls_through`
in TestNewSenderFromEnvironment_EmailEnabled — two overlapping copies
of the same sub-test ended up concatenated (one missing its closing
braces, one preceded by stray fragments), plus duplicate
`ctx :=` / `sender, err :=` lines. The result didn't parse:

  gofmt -l internal/email/factory_test.go
  internal/email/factory_test.go:309:2: missing ',' before newline ...
  internal/email/factory_test.go:312:6: expected '(', found TestNewSenderWithConfig_AWS

This trips `gofmt` and `go vet` in the pre-commit workflow on every
open PR against `feat/multicloud-web-frontend` (e.g. #326, #335, #336).

Keep the `prev/hadPrev` version of the sub-test (the one that actually
does `os.Unsetenv` first, which is the case the test name describes),
drop the orphaned `orig/hadOrig` fragment, and remove the duplicate
ctx/sender declarations.

Verified locally: gofmt clean, `go vet ./internal/email/...` clean,
`go test ./internal/email/...` 306 tests pass.
cristim added 3 commits May 11, 2026 23:07
…cation pages (closes #314)

Introduces the Archera Insurance CTA at the two high-intent moments
where a user is about to commit money, plus two education pages that
explain what Archera Insurance is and how the integration works.

**New module — frontend/src/archera.ts**
- `renderArcheraCTA()`: returns a small, muted <p> with an inline
  <button> that reads "Worried about committing? Archera Insurance
  underwrites commitment-overuse — learn how it works →". Placed
  below the approval note in the Purchase modal, and before the
  Save/Cancel row in Plan-creation modals.
- `openArcheraPage('what-is-archera' | 'how-it-works')`: renders a
  full-viewport overlay panel using DOM methods only (no innerHTML).
  Doesn't touch SPA routing state or the URL.
- `closeArcheraPage()`: hides + clears the overlay.
- `ARCHERA_SIGNUP_URL = 'https://archera.ai/signup?mode=cudly'` for
  attribution-tagged referral links.

**Page A — "What is Archera Insurance?"**
Plain-language explainer: commitment-overuse insurance, how Archera
earns (sharing-of-savings), when it makes sense, what CUDly's role is.
Cross-links to Page B. Signup link at bottom (target=_blank,
rel="noopener noreferrer").

**Page B — "How the CUDly ↔ Archera integration works"**
Step-by-step: sign up → Archera generates pre-filled IaC for AWS/GCP
(or OAuth consent for Azure) → Archera ingests cost data → purchase
commitments normally through CUDly. Disclaimers: Archera is
third-party, no credentials stored in CUDly. Cross-links to Page A.
Signup link at bottom.

TODO(@cristim) markers flag all copy that needs final review.

**Modal integration**
- `recommendations.ts / openPurchaseModal`: appends `renderArcheraCTA()`
  inside `#purchase-details`, below the approval note.
- `plans.ts / openCreatePlanModal + openNewPlanModal`: calls
  `injectPlanModalCTA()` (guarded against duplication with an id
  check) to insert the CTA before `.modal-buttons` in `#plan-form`.

**CSS (styles/modals.css)**: `.archera-cta`, `.archera-cta-link`,
`#archera-page-container`, `.archera-page-inner`, `.archera-page-back`,
`.archera-signup-block`, `.archera-signup-btn`, `.archera-signup-note`.

**HTML (index.html)**: adds `<div id="archera-page-container"
role="region" aria-label="Archera Insurance information">` (hidden
by default) before the modal stack.

**Tests (archera.test.ts)**: 26 assertions covering renderArcheraCTA
structure, page A/B content + crosslinks + signup link attributes,
closeArcheraPage, and CTA injection in both Purchase and Plan modals.

Nothing in backend/, cmd/, internal/, iac/, terraform/, or scripts/ is
touched. This is a frontend-only change. Supersedes PR #310 and PR #315
(closed without merging; earlier iterations bundled IAM/IaC which was
rejected by Archera-side review — see issue #314 for history).
Frontend (CR fixes):
- archera.ts: save/restore focus around overlay open/close (CR: focus
  restoration on closeArcheraPage)
- modals.css: raise #archera-page-container z-index from 900 to 1100
  so overlay sits above .modal layers (CR: z-index below modals)
- archera.test.ts: add global afterEach DOM teardown to prevent stale-
  node collisions between test suites (CR: missing teardown)

Frontend (scope additions from coordinator):
- archera.ts: update renderArcheraCTA copy to "Insure this commitment/
  plan with Archera →"; add transparency disclosure section (Page A:
  "Why is CUDly telling me about this?", Page B: "Disclosure") carrying
  two non-negotiable facts: CUDly fully functional without Archera +
  Archera sponsors CUDly; add handleArcheraDeeplink() for deep-link
  routing from email; export ARCHERA_PAGE_A/B_PATH constants
- app.ts: wire handleArcheraDeeplink() into init() after
  handlePurchaseDeeplink()
- plans.ts: pass 'plan' context to renderArcheraCTA in injectPlanModalCTA
- archera.test.ts: update CTA copy assertions; add disclosure tests (6);
  add handleArcheraDeeplink tests (3); total: 41 tests, all passing

Backend (email templates — scope addition):
- sender.go: add ArcheraEducationURL field to NotificationData; empty
  value silently omits the Archera block for backward compat
- templates.go: add conditional Archera 7-day enrollment block to
  purchaseApprovalRequestTemplate (plain-text), purchaseApprovalRequest-
  HTMLTemplate (HTML), and purchaseConfirmationTemplate
- handler_purchases.go, execution.go: populate ArcheraEducationURL as
  DashboardURL + "/archera-insurance" matching ARCHERA_PAGE_A_PATH
- template_renderers_test.go: add 4 Go tests asserting Archera content
  in all three modified templates + absence test when URL is empty
…aseApprovalEmail cyclomatic complexity

The if dashboardBase != "" guard added in the previous commit pushed
sendPurchaseApprovalEmail from complexity 10 to 11, exceeding the
gocyclo pre-commit threshold. Extracted the guard into a package-private
archeraEducationURL helper; sendPurchaseApprovalEmail calls it inline
without a branch, restoring complexity to 10.
@cristim cristim force-pushed the feat/issue-314-archera-modal-cta branch from d6e5130 to 6c2b5c7 Compare May 11, 2026 21:07
@cristim
Copy link
Copy Markdown
Member Author

cristim commented May 11, 2026

@coderabbitai review

PR was rebased onto base branch to pick up #337 (factory_test.go fix). Archera changes in this branch:

  • frontend modal CTAs (Insure this commitment with Archera → / Insure this plan with Archera →)
  • education pages with transparency disclosures (CUDly works without Archera + sponsorship fact)
  • regression-guard tests for both disclosures on both pages
  • email template Archera mentions with 7-day window (purchaseApprovalRequestTemplate + HTML + purchaseConfirmationTemplate)
  • archeraEducationURL helper in internal/api/handler_purchases.go to keep sendPurchaseApprovalEmail cyclomatic complexity ≤ 10
  • Archera overlay z-index raised to 1100 to render above modals

Previous round's findings should all be resolved.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 11, 2026

@cristim: Understood! Triggering a fresh review of PR #336 now, taking into account the rebase onto the base branch (picking up the #337 factory_test.go fix) and all the Archera changes you've listed:

  • Frontend modal CTAs for purchase and plan flows
  • Education overlay pages with transparency disclosures
  • Regression-guard tests for both disclosures on both pages
  • Email template Archera mentions with the 7-day enrollment window
  • archeraEducationURL helper to keep cyclomatic complexity ≤ 10
  • Archera overlay z-index raised to 1100

I'll check whether the previous round's findings are fully addressed.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim
Copy link
Copy Markdown
Member Author

cristim commented May 11, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 11, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/m Days impact/many Affects most users priority/p2 Backlog-worthy severity/medium Moderate harm triaged Item has been triaged type/feat New capability urgency/this-quarter Within the quarter

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant