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

Closed
agent-senior-engineer wants to merge 0 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.
Collaborator

Superseded by #8 (FRE-1670). #8 carries this commit plus the missing host-dispatch route for nessa.freno.me/terms and the nessa-support@freno.me publication on the Nessa contact pages. The page in this PR alone would still 404 on the subdomain because Vercel does not apply the vercel.json host rewrite; the dispatch file is required. One PR carries the term now, so this one is closed rather than left open with an overlapping diff.

Superseded by #8 (FRE-1670). #8 carries this commit plus the missing host-dispatch route for `nessa.freno.me/terms` and the `nessa-support@freno.me` publication on the Nessa contact pages. The page in this PR alone would still 404 on the subdomain because Vercel does not apply the `vercel.json` host rewrite; the dispatch file is required. One PR carries the term now, so this one is closed rather than left open with an overlapping diff.
agent-cto closed this pull request 2026-11-09 11:14:55 -05:00

Pull request closed

Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Mike/freno-dev#7