Skip to content
AskFlorence
Main Navigation ArchitectureFlorence AIAgentsMembersAgent PlatformValidationInfrastructure

Appearance

Sidebar Navigation

Overview

Home

Glossary

System Architecture

Consumer & Agent Flow

Florence AI

Overview

Principles

Runtime

Tool surface

Adding a tool

Tool registry

Knowledge: SBC scenarios & CSR

Voice

Evals & observability

Provider risk & portability

Outage playbook

Roadmap

Build plan

Agents

Overview

Workflows & pain points

Members

Overview

Medicaid coverage gap

Carriers

Overview

Marketplaces

Overview

Agency

Overview

Regulations

Overview

Agent Platform

Overview

Auth Architecture

MongoDB Permissioning

Compliance Model

Data Models

Data Sources

Overview

CMS Marketplace API

CMS dependency map

PUF Data

State Subsidies

SBE Ingestion Playbook

SBE State Watchouts + Decisions

CA Phase C/D Playbook

NY Phase C/D Playbook

Validation

Overview

Methodology

APTC Formula

California 2026

New York 2026

CAPS Formula

Scenario Results

Infrastructure

Account Inventory

AWS Setup Runbook

AWS Organizations

CloudTrail

GuardDuty

Security Hub

Config

CloudFront + WAFv2

Data sources & ingest

Phase 4 DNS

Change Log

Vulnerability Management

MongoDB Setup

Access Control

Data Classification

Documentation Hosting

Post-deploy Smoke

Development

Preflight (local CI mirror)

Testing strategy

Compliance

Overview (auditor entry point)

SOC 2 Control Mapping

HIPAA Control Mapping

CMS EDE Appendix A Mapping

Risk Assessment

Encryption Policy

Data Retention Policy

Privacy Impact Assessment

Consent Capture & Versioning

Incident Response Plan

Access Control Policy

Marketing vs. Portal Analytics

Vendor / Subprocessor Register

Dependency Vulnerability Policy

BAA / Compliance Evidence

Compliance-Automation Integration

Compliance-Automation Vendor Evaluation

Penetration Test Reports

Architecture

Portal entry handoff

Mobile app strategy

Deferred architecture decisions

Session cookie architecture

Share flows

Decisions (ADRs)

Index

0001 — Atlas project isolation

0002 — Append-only audit log

0003 — Narrow-scoped Mongo users

0004 — Cross-cluster Atlas PrivateLink

0005 — Delayed-job architecture

0006 — Mongo user simplification

0007 — Terraform owns ECS task def

0008 — E2E testing strategy

0009 — Self-hosted analytics + observability (superseded)

0010 — PostHog HIPAA Cloud (supersedes 0009)

Runbooks

Security Incident Response

Break-Glass Root Login

Onboard Team Member

Offboard Team Member

Atlas user provisioning

Deploy via Terraform (ENG-277)

Rollback via Terraform (ENG-277)

S3 data bucket migration (planned Phase 11)

Access Reviews

2026-Q2 Review

Session log

Index

2026-04-23 — Phase 10 DNS cutover

2026-04-22 — Phase 8 prod AWS mirror

2026-04-22 — Phase 7 Atlas VPC peering

2026-04-22 — Phase 6 CloudFront + WAF

2026-04-21 — Phase 5 staging go-live

2026-04-17 — Atlas staging

Briefs

Index

Member portal plan (ENG-187)

2026-04-16/17 handoff

2026-04-17 Atlas handoff

System briefing (2026-04-17)

Creative AdBundance proposal brief

Creative AdBundance analytics brief

ElevenLabs RN integration research

Policies

Overview

On this page

Share flows (ENG-339) ​

Two distinct share user stories, shipped together on top of the ENG-322 session substrate. Source: ENG-339 (follow-on to ENG-322). Linear: ENG-339.

Why two flavors, not one ​

A single "share" button conflates two different intents:

  • Flavor A — Save & share my plans: full plan details with personal pricing context. The recipient (a partner — or the sharer later) sees exactly what the sharer saw, frozen.
  • Flavor B — Tell a friend about AskFlorence: marketing share, no personal data. The recipient lands on AskFlorence to find their own subsidized price.

Two buttons, two flows = clean UX.

Gating ​

Both buttons render in a page-level <ShareButtons enabled=…> row in the /plans + plan-detail context strips. enabled is the server-read SESSION_FLOW_ENABLED, prop-drilled by the /plans + /plans/p/* server pages (those surfaces use the server prop, not the calculator's SessionFlagAutoProvider context — that distinction matters; wiring it to the context would have made it permanently false there). Flavor A snapshots the server session, so the whole row is hidden when the session flow is off (legacy/staging — no af_session cookie, nothing to snapshot) and on saved-share views (you're viewing someone's snapshot, not creating one). No new flag — reuses ENG-322's SESSION_FLOW_ENABLED.

Flavor A — Save & share (backend) ​

POST /api/share/create (guarded, write-class cap 20 — doubles as ENG-321 anti-abuse on share creation):

  • Resolves the session id (cookie or Authorization: Bearer — native ready) and loads it server-side (household / aptc / csr / coverage / planIdMap are server truth).
  • The client sends the full PlanDisplay[] it rendered — the ENG-322 session deliberately stores only plan {id} stubs, so the snapshot takes the full list from the client (same "client computes, server persists" contract as ENG-322; the pricing pipeline is never touched).
  • Writes a marketing_shares row: a frozen snapshot + 30-day TTL. Returns { shareUrl: "/plans/saved/<shareId>", expiresAt }.

marketing_shares schema ​

_id: "share_<hex>"
createdAt, expiresAt (TTL index, +30 days — Mongo reaps, no cron)
snapshot: {
  zip, countyFips, countyName, state, household, people,
  aptc, csr, isMedicaid,
  selectedDrugs[], selectedDoctors[],   // server truth (session)
  plans: PlanDisplay[],                 // client-supplied (faithful)
  planIdMap: { opaque -> real },        // copied from session
}
label: string | null
createdFromSession: "af_sess_<id>"      // abuse tracing
visitorId: "af_v_<id>"

No new infra/secret — app_write already has DB-wide readWrite (ADR 0006); the TTL index is created by the existing deploy-time ensure-indexes ECS RunTask (flows through the ENG-325 bundle).

Saved-view pages ​

  • /plans/saved/<shareId> — server fetches the share (404-card with a "Find your price →" CTA if missing/expired), renders read-only from the snapshot via SavedShareView (reuses MarketplacePlanCard; no fetch, no filters/sort, no recompute — exactly what the sharer saw). Banner: Saved search · created … · expires … · Start your own search →. noindex.
  • /plans/saved/<shareId>/p/<opaqueId> — resolves the opaque token against the frozen snapshot.planIdMap, finds the plan in snapshot.plans, renders PlanDetail with presetPlan (skips the fetch entirely — faithful) and savedShareId (back-link returns to the saved list). Unresolvable / expired → back to the saved list.

Opaque tokens are still per-snapshot (copied from the session that minted them) — they do not replay across users or shares.

Flavor B — Tell a friend (pure frontend) ​

No backend state. TellFriendModal has an editable pre-filled message and:

  • Mobile: Web Share API (navigator.share) → native sheet.
  • Desktop: clipboard copy + mailto: / sms: intents.
  • Link is the bare https://askflorence.health (no ?ref in v1). The future referral program layers ?ref=user-<visitorId> on later (ENG-322 parking lot) — backward-compatible.

Analytics ​

trackEvent("share_created", { flavor: "save_share" | "tell_a_friend" }) fires from both flows via src/lib/analytics.ts — a deliberate no-op until the self-hosted first-party stack lands (OpenPanel + GlitchTip, ADR 0009 / ENG-347); that file is the single server-side callsite where the OpenPanel ingest plugs in. Keeping the callsites live now = zero retro-fit later (the server-side spine is tool-portable by design).

Rollback ​

Pure additive. The collection + TTL index are inert until a share is created; the buttons are enabled-gated off the existing SESSION_FLOW_ENABLED. Revert the PR (or flip the session flag off and the row disappears). No pipeline / no infra / no secret change.

Pager
Previous pageSession cookie architecture
Next pageIndex

AskFlorence Internal Documentation. Not for public distribution.

AskFlorence

Internal Documentation

Access restricted. Not for public distribution.