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:
53
src/routes/nessa/deletion-content.ts
Normal file
53
src/routes/nessa/deletion-content.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Pure content + metadata for the Nessa per-subdomain account-deletion page
|
||||
* (task 11).
|
||||
*
|
||||
* Mirrors the `lineage/deletion-content.ts` pattern: imports NOTHING from
|
||||
* solid-js / @solidjs/router / @solidjs/meta so the constants here can be
|
||||
* unit-tested in `bun:test` without spinning up the router / MetaProvider.
|
||||
*
|
||||
* Nessa deletion assessment (see task 11 spec, step 5):
|
||||
* - Nessa DOES store user data. `src/server/api/routers/nessa.ts` defines
|
||||
* per-user tables (`users`, `authProviders`, `workouts`, `workoutPlans`,
|
||||
* `planExercises`, `planSets`, `routePoints`, `exerciseLibrary`) backed
|
||||
* by a per-user Turso DB, and `nessa-community.ts` defines shared
|
||||
* community tables (`clubs`, `clubMemberships`, …) keyed by `userId` /
|
||||
* `ownerId`. Auth is Clerk. → A deletion flow IS needed.
|
||||
* - Implemented here as the SAME email-request pattern Lineage uses: the
|
||||
* requester submits their email via `DeletionForm`; the generalized
|
||||
* `misc.sendDeletionRequestEmail` mutation sends a Nessa-branded email
|
||||
* to michael@freno.me + the requester; Mike then manually drops the
|
||||
* Nessa `users` row (+ cascades), the per-user Turso DB, and the user's
|
||||
* community memberships within the 24h grace window. An authenticated
|
||||
* self-delete via `nessa.deleteUser` + the Clerk Users API remains a
|
||||
* follow-up (it requires Clerk backend secret wiring that is out of
|
||||
* scope for the subdomain-routing feature); the email-request flow gives
|
||||
* users a real, immediate deletion path today.
|
||||
*
|
||||
* Cross-task contracts:
|
||||
* - `DELETION_PRODUCT_KEY = "nessa"` selects Nessa branding + the
|
||||
* `nessaDeletionRequestSent` cooldown cookie (server-side
|
||||
* `deletionCookieName("nessa")`).
|
||||
* - `DELETION_COOKIE_NAME` MUST match `deletionCookieName("nessa")` so the
|
||||
* client countdown reads the cookie the server actually sets.
|
||||
*/
|
||||
import type { PageHeadProps } from "~/components/page-head-meta";
|
||||
|
||||
/** Product discriminator forwarded to `misc.sendDeletionRequestEmail`. */
|
||||
export const DELETION_PRODUCT_KEY = "nessa" as const;
|
||||
|
||||
/**
|
||||
* Cooldown cookie name — MUST match `deletionCookieName("nessa")` on the
|
||||
* server (`nessaDeletionRequestSent`).
|
||||
*/
|
||||
export const DELETION_COOKIE_NAME = "nessaDeletionRequestSent";
|
||||
|
||||
/** Human-readable grace-window copy interpolated into the page body. */
|
||||
export const DELETION_GRACE_PERIOD_LABEL = "24-hour";
|
||||
|
||||
/** Base page title (site suffix appended by PageHead). */
|
||||
export const PAGE_META: PageHeadProps = {
|
||||
title: "Account Deletion",
|
||||
description:
|
||||
"Request account deletion for Nessa. Your Nessa account, workout data, and community memberships are removed after a 24-hour grace period."
|
||||
};
|
||||
Reference in New Issue
Block a user