nessa: publish the Terms of Use the app links at /terms (FRE-194) #7

Open
agent-senior-engineer wants to merge 1 commits from freno-dev/FRE-194-nessa-terms-of-use into master
Collaborator

Summary

The document behind the Terms of Service row in the Nessa app. Nessa didn't own a terms page: the app linked another product's terms and nessa.freno.me/terms was a 404. Nessa sells an auto-renewing subscription, so App Review 3.1.2 expects the app to link terms of use as well as a privacy policy.

nessa.freno.me/terms
  └── src/routes/nessa/terms.tsx        (new)  served by the existing catch-all:
      vercel.json  source "/(.*)"  host=nessa.freno.me  →  "/nessa/$1"
 SITEMAP_ROUTES.nessa
   /          weekly   1.0
   /contact   monthly  0.6
   /privacy   yearly   0.4
+  /terms     yearly   0.4

Page follows the privacy.tsx house template exactly: EdgeCacheHeaders, site-aware PageHead (only the base title — the | Nessa suffix and canonical derive), SubdomainHeader, subdomain-relative internal links.

Sections: acceptance and eligibility · the service and its limits (incl. not a medical device) · accounts (Clerk) · community content and acceptable use (content licence, leaderboard integrity, moderation) · subscriptions (Apple billing, auto-renewal, 24-hour cancel window, managing in the App Store, trials, refunds, price changes, downgrade) · Apple third-party acknowledgements · IP · disclaimers and liability · termination · changes · contact.

Evidence

  • Before: curl -o /dev/null -w '%{http_code}' https://nessa.freno.me/terms → 404
    After: the route exists; serves once this branch is deployed to the Vercel project.

  • JSX transform of the new page (esbuild, solid-js automatic runtime, repo tsconfig): clean, 24 KB output.

  • Sitemap change executed, not just asserted — bundled SITEMAP_ROUTES.nessa + generateSitemap and ran it:

[ "https://nessa.freno.me/",
  "https://nessa.freno.me/contact",
  "https://nessa.freno.me/privacy",
  "https://nessa.freno.me/terms" ]
count: 4 · has /terms: true · no main-site leak: true

That is exactly the set sitemap-routes.test.ts now asserts (toContain(/terms), toBe(4)).

  • bun test is not runnable in this run — no bun binary in the runner. Recorded as not runnable, not as passed. The two touched assertions are covered by the execution above.

Merge Danger

Door: two-way technically, but this is a public legal document — once live, users are relying on it, and changes are versioned by the "Last Updated" date rather than rolled back.

Blast radius: one new route + one sitemap entry. No existing page, component, or nav file is modified, so nothing that renders today changes. NAV_CONFIG is deliberately untouched, so the per-site nav matrix tests still pass unmodified.

Needs Mike's read before merge — these are judgement calls I did not make for him:

  1. Legal wording. Section 5 (subscriptions) and 6 (Apple) follow the standard App Store auto-renewable clauses; the rest is drafted to Nessa's actual features. It is a draft for your approval, not settled text.
  2. No entity name and no governing-law clause. No Nessa page states either today — the privacy policy speaks only as "we" — so I kept that rather than inventing an entity or jurisdiction. Say the word and both go in.
  3. Nav. /terms is in the sitemap but not in the Nessa nav. Adding it is one line in NAV_CONFIG.nessa plus updating nav-config.test.ts's link-set matrix.

Companion app-side PR: Mike/Nessa branch Nessa/FRE-194-replace-non-nessa-legal-destinations-with-approved-nessa-documents (FRE-194). The app's Terms row points at this route, so this page should deploy with or before that one — otherwise the row resolves to a 404.

## Summary The document behind the `Terms of Service` row in the Nessa app. Nessa didn't own a terms page: the app linked another product's terms and `nessa.freno.me/terms` was a 404. Nessa sells an auto-renewing subscription, so App Review 3.1.2 expects the app to link terms of use as well as a privacy policy. ```text nessa.freno.me/terms └── src/routes/nessa/terms.tsx (new) served by the existing catch-all: vercel.json source "/(.*)" host=nessa.freno.me → "/nessa/$1" ``` ```diff SITEMAP_ROUTES.nessa / weekly 1.0 /contact monthly 0.6 /privacy yearly 0.4 + /terms yearly 0.4 ``` Page follows the `privacy.tsx` house template exactly: `EdgeCacheHeaders`, site-aware `PageHead` (only the base title — the ` | Nessa` suffix and canonical derive), `SubdomainHeader`, subdomain-relative internal links. Sections: acceptance and eligibility · the service and its limits (incl. **not a medical device**) · accounts (Clerk) · community content and acceptable use (content licence, leaderboard integrity, moderation) · **subscriptions** (Apple billing, auto-renewal, 24-hour cancel window, managing in the App Store, trials, refunds, price changes, downgrade) · **Apple third-party acknowledgements** · IP · disclaimers and liability · termination · changes · contact. ## Evidence - **Before:** `curl -o /dev/null -w '%{http_code}' https://nessa.freno.me/terms` → `404` **After:** the route exists; serves once this branch is deployed to the Vercel project. - JSX transform of the new page (esbuild, solid-js automatic runtime, repo tsconfig): **clean**, 24 KB output. - Sitemap change **executed**, not just asserted — bundled `SITEMAP_ROUTES.nessa` + `generateSitemap` and ran it: ```text [ "https://nessa.freno.me/", "https://nessa.freno.me/contact", "https://nessa.freno.me/privacy", "https://nessa.freno.me/terms" ] count: 4 · has /terms: true · no main-site leak: true ``` That is exactly the set `sitemap-routes.test.ts` now asserts (`toContain(/terms)`, `toBe(4)`). - `bun test` is **not runnable in this run** — no bun binary in the runner. Recorded as not runnable, not as passed. The two touched assertions are covered by the execution above. ## Merge Danger **Door:** two-way technically, but this is a **public legal document** — once live, users are relying on it, and changes are versioned by the "Last Updated" date rather than rolled back. **Blast radius:** one new route + one sitemap entry. No existing page, component, or nav file is modified, so nothing that renders today changes. `NAV_CONFIG` is deliberately untouched, so the per-site nav matrix tests still pass unmodified. **Needs Mike's read before merge — these are judgement calls I did not make for him:** 1. **Legal wording.** Section 5 (subscriptions) and 6 (Apple) follow the standard App Store auto-renewable clauses; the rest is drafted to Nessa's actual features. It is a draft for your approval, not settled text. 2. **No entity name and no governing-law clause.** No Nessa page states either today — the privacy policy speaks only as "we" — so I kept that rather than inventing an entity or jurisdiction. Say the word and both go in. 3. **Nav.** `/terms` is in the sitemap but not in the Nessa nav. Adding it is one line in `NAV_CONFIG.nessa` plus updating `nav-config.test.ts`'s link-set matrix. Companion app-side PR: [Mike/Nessa](https://git.freno.me/Mike/Nessa) branch `Nessa/FRE-194-replace-non-nessa-legal-destinations-with-approved-nessa-documents` (FRE-194). The app's Terms row points at this route, so this page should deploy with or before that one — otherwise the row resolves to a 404.
agent-senior-engineer added 1 commit 2026-11-07 16:38:08 -05:00
The Nessa app's Settings › Legal "Terms of Service" row had no Nessa-owned
document to resolve to: it linked another product's terms, and
nessa.freno.me/terms was a 404. Nessa sells an auto-renewing subscription, so
App Review 3.1.2 requires the app to link terms of use as well as a privacy
policy — the row has to land on a real document.

- src/routes/nessa/terms.tsx: the page, in the privacy.tsx house template
  (EdgeCacheHeaders, site-aware PageHead, SubdomainHeader, subdomain-relative
  internal links). Sections cover acceptance, the service and its limits,
  accounts, community content and acceptable use, auto-renewable
  subscriptions (payment, renewal, the 24-hour cancel window, managing it in
  the App Store, trials, refunds, price changes), the Apple third-party
  acknowledgements, IP, disclaimers and liability, termination, changes, and
  contact.
- src/lib/sitemap-routes.ts: add /terms to the Nessa set, and update the
  count assertion in sitemap-routes.test.ts to match.

Health and safety: Nessa is not a medical device, so section 2(c) says so
explicitly — the previous app-side link pointed at another product's terms,
which said nothing about Nessa's training features.

Deliberately left out, for Mike to decide rather than have me guess:
 - No legal entity name and no governing-law clause. No Nessa page states
   either today; the privacy policy speaks only as "we".
 - No NAV_CONFIG entry, so the nav link-set matrix tests are untouched. The
   route serves through the existing catch-all host rewrite in vercel.json;
   adding a nav item is a one-line change plus a matrix update if wanted.
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin freno-dev/FRE-194-nessa-terms-of-use:freno-dev/FRE-194-nessa-terms-of-use
git checkout freno-dev/FRE-194-nessa-terms-of-use
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Mike/freno-dev#7