Minisites — QA Plan
Resolution
| Step | Expected |
|---|---|
Hit https://<orgsubdomain>.fitkit.fit/ | Astro fetches /minisites/resolve?host=<host> and renders publishedContent. |
| Hit a custom domain registered against an org | Same — resolves by custom_domain. |
| Hit a host that matches no row | API returns 404; Astro renders “Site not found”. |
Org row exists but is_published = false | Astro renders 404 — drafts must not leak. |
Org row exists, is_published = true, published_content = null | Astro renders 404. |
Section rendering
| Step | Expected |
|---|---|
Org has no programs, but classes section is enabled | Section is filtered out of visibleSections and does not render. |
| Org has no upcoming sessions | schedule section is hidden. |
Section’s isEnabled is false | Section is hidden regardless of data presence. |
Two sections share the same order | Stable order falls back to insertion sequence. |
Theme
| Step | Expected |
|---|---|
| Owner edits primary color in editor and publishes | New color appears on next request after the 120s SWR window. |
Owner sets a fontFamily not in the enum | Falls back to inter. |
| Owner uploads a favicon | <link rel="icon"> points at the uploaded URL. |
Localization
| Step | Expected |
|---|---|
Org locale = he | Page renders RTL with Hebrew strings. |
Org locale = en | LTR English. |
Org locale = ru | LTR Russian. |
| Locale is malformed | Falls back to he. |
Live data freshness
| Step | Expected |
|---|---|
| Add a class session in the dashboard | New session appears on the schedule within 2 min (cache TTL). |
| Pause a plan | Plan disappears from pricing within 2 min. |
| Force-refresh via Vercel cache purge | Updates visible immediately. |
Performance
| Check | Threshold |
|---|---|
| LCP on mobile (Lighthouse) | < 2.5s. |
| Total JS bytes | < 30KB gzipped (WhatsApp button + scroll observers only). |
| Hero image preload tag present | Yes when hero has backgroundImage. |
SEO
| Step | Expected |
|---|---|
<title> and <meta description> come from seoTitle / seoDescription | When set, override default. |
robots.txt served at /robots.txt | Returns a 200 with the org’s robots directives. |
Cache-Control header | public, s-maxage=120, stale-while-revalidate=300. |
Contact / lead capture
| Step | Expected |
|---|---|
| Submit the contact form | Lead lands in the org’s leads pipeline tagged as source: 'minisite'. |
| Submit with spam payload (honeypot triggered) | Server rejects; no lead created. |
Custom domain provisioning
| Step | Expected |
|---|---|
Owner adds custom_domain and points CNAME to cname.vercel-dns.com | Vercel auto-issues cert; requests resolve. |
| Owner adds domain but never updates CNAME | Requests return generic Vercel 404 (gap — see README). |
Negative tests
- Hit
/minisites/resolve?host=with an empty host → API returns 400. - Hit the resolve endpoint with a host that includes a port → API strips the port before lookup.
- Render with
content.sectionsempty → only the hero (always-on) renders.