feat: add product-aware deletion emails and subdomain deletion/downloads routes

- Extend DeletionForm with product discriminator and configurable cooldown cookie
- Extract env-free deletion email helpers into deletion-email.ts with Lineage/Nessa branding
- Make misc.sendDeletionRequestEmail mutation product-aware (subject, html content, cookie)
- Replace legacy /deletion/life-and-lineage page with 308 redirect to lineage subdomain
- Add Lineage and Nessa subdomain deletion route modules with shared content components
- Add Lineage downloads route modules with shared content
- Update privacy policy deletion link to lineage subdomain
This commit is contained in:
2026-07-23 12:32:14 -04:00
parent 5705c5add7
commit 59d129b46b
17 changed files with 1138 additions and 41 deletions

View File

@@ -0,0 +1,61 @@
/**
* Nessa per-subdomain account-deletion page — `nessa.freno.me/deletion`
* (task 11).
*
* Served at the public browser path `/deletion` (vercel.json host rewrites
* `nessa.freno.me/*` → the internal `/nessa/*` route prefix, leaving the
* browser URL clean — task 02 canonical rule).
*
* Nessa deletion assessment (see `./deletion-content.ts` for the full
* rationale): Nessa stores user data (`users`, `workouts`, `workoutPlans`,
* `exerciseLibrary`, community memberships) in a per-user Turso DB +
* shared community tables, authenticated via Clerk. → A deletion flow IS
* needed; this page provides it via the same email-request pattern Lineage
* uses, reusing the shared `DeletionForm` with `product="nessa"` so the
* generalized `misc.sendDeletionRequestEmail` mutation sends Nessa-branded
* email + writes a Nessa-specific cooldown cookie.
*
* Auth: NO freno.me web-auth — Nessa authenticates via Clerk; the deletion
* request is email-based (the requester may be locked out of their Clerk
* session), NOT an authenticated self-delete. The nav-config does NOT list
* a Nessa deletion link by default, so this page is reachable by direct URL
* + from the Nessa privacy policy (task-provided).
*
* Acceptance: `nessa.localhost:3000/deletion` renders the deletion form.
*/
import { PageHead } from "~/components/PageHead";
import DeletionForm from "~/components/DeletionForm";
import {
DELETION_PRODUCT_KEY,
DELETION_COOKIE_NAME,
DELETION_GRACE_PERIOD_LABEL,
PAGE_META
} from "~/routes/nessa/deletion-content";
export default function NessaDeletionPage() {
return (
<>
<PageHead title={PAGE_META.title} description={PAGE_META.description} />
<div class="pt-20">
<div class="mx-auto p-4 md:p-6 lg:p-12">
<div class="text-text w-full justify-center">
<div class="text-xl">
<em>What will happen</em>:
</div>
Once you send, if a match to the email provided is found in our
system, a {DELETION_GRACE_PERIOD_LABEL} grace period is started
where you can request a cancellation of the account deletion. Once
the grace period ends, your Nessa account entry, your workout and
plan data, and your community memberships will be completely
removed. No data related to the account is retained in any way.
</div>
<DeletionForm
product={DELETION_PRODUCT_KEY}
cookieName={DELETION_COOKIE_NAME}
/>
</div>
</div>
</>
);
}