Free early-access launch: LAUNCH_MODE policy, CRO, pipeline hardening, AI-SEO, ops

- launch.ts policy: LAUNCH_MODE=free_early_access default; effective access =
  published && (free || early); intended tier (access) never rewritten
- Billing off server-side: /api/subscribe 503 honest copy; subscribe CTAs
  render disabled 'قريباً' from first paint; /subscription early-access panel
  + /api/notify (LaunchNotifications) with honest 503 when mail transport off
- Signup trust: verification email at signup (Users afterChange), no
  confirm-password, 429 message fidelity, typo suggestion, live password hint
- Agent pipeline: pickFields strips access/readingMinutes, sourceId dedup,
  secret-scan 422 (pattern names only), string-content rejected (was silently
  replaced), publish stays explicit opt-in
- lexical.ts: root unwrap fix — lexicalToText/countLexicalWords returned 0
  for real serialized trees (secret scan + readingMinutes were inert)
- llms-full.txt: fetchIndexDocs(true) — bodies were never selected
- Content honesty: contentType/authorName/sourceId fields + migration,
  readingMinutes computed at write (160 wpm) + backfill script, byline,
  'حُدّث' freshness
- SEO/AI-SEO: metadata rewrite (published-only, og:image 1200x630), Article +
  BreadcrumbList + FAQPage + Organization JSON-LD, isAccessibleForFree honest,
  table renderer, robots AI-crawler policy (10 named bots), llms.txt +
  llms-full.txt, /topics/* hubs + sitemap, noindex auth pages, www 301
- Ops: backup-db.sh (restore rehearsed on VPS), docs copies (launch
  readiness + marketing audit + owner-inputs for L-03), GLOSSARY.md entries

Verified: tsc --noEmit 0, npm run build 0, local smoke (ghost VIP read,
subscribe/notify/agent APIs, signup token, 429 on 6th, llms/topics/sitemap,
og:image/JSON-LD)
This commit is contained in:
AHMED
2026-10-10 18:03:45 +03:00
parent 82414e8a93
commit 0161924088
57 changed files with 4042 additions and 402 deletions
+31
View File
@@ -207,6 +207,8 @@ body { background: var(--ink); color: var(--mist); }
#site .membership-offer { border: 1px solid var(--seam); border-top: 2px solid var(--champagne); border-radius: var(--r-md); padding: 28px; background: var(--basalt); display: grid; gap: 18px; }
#site .membership-offer .price { font: 600 40px/1 var(--font-display); color: var(--mist); display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
#site .membership-offer .price span { font: 400 15px/1.5 var(--font-body); color: var(--stone); }
#site .membership-offer .price-early { color: var(--champagne); }
#site .membership-offer .early-line { color: var(--stone); font-size: 15.5px; margin: -8px 0 0; }
#site .membership-offer ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
#site .membership-offer li { display: flex; gap: 12px; align-items: baseline; color: var(--mist); font-size: 15.5px; }
#site .membership-offer li::before { content: ""; flex: none; width: 9px; height: 8px; background: var(--champagne); clip-path: polygon(50% 0, 100% 100%, 0 100%); transform: translateY(-1px); }
@@ -277,7 +279,22 @@ body { background: var(--ink); color: var(--mist); }
#site .art-body li + li { margin-top: .4em; }
#site .art-body li::marker { color: var(--champagne); }
#site .art-body blockquote { margin-inline: 0; padding: 4px 20px; border-inline-start: 2px solid var(--champagne); color: var(--mist); font-size: 19px; }
#site .topic-hero { padding-block: clamp(40px, 6vw, 72px) 8px; }
#site .topic-hero h1 { font-size: clamp(28px, 3vw, 40px); margin: 0 0 6px; }
#site .topic-hero .crumbs { display: flex; gap: 8px; color: var(--stone); font-size: 14px; margin: 0 0 18px; }
#site .topic-hero .crumbs a { color: var(--champagne); }
#site .topic-hint { color: var(--mist); margin: 0; }
#site .topic-list { padding-block: 32px 72px; }
#site .topic-other { margin-top: 40px; color: var(--stone); font-size: 15px; }
#site .topic-other a { color: var(--champagne); }
#site .topic-strip { display: flex; flex-wrap: wrap; gap: 10px; margin: 0 0 22px; }
#site .topic-strip a { display: inline-block; padding: 6px 16px; border: 1px solid var(--seam); border-radius: 999px; color: var(--mist); font-size: 14.5px; }
#site .topic-strip a:hover { border-color: var(--champagne); color: var(--champagne); }
#site .art-body pre { direction: ltr; text-align: left; background: var(--ink-2); border: 1px solid var(--seam); border-radius: var(--r-md); padding: 20px 22px; overflow-x: auto; font: 14.5px/1.75 ui-monospace, "SF Mono", Menlo, Consolas, monospace; }
#site .art-body .post-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }
#site .art-body .post-table table { width: 100%; border-collapse: collapse; font-size: 16px; line-height: 1.8; }
#site .art-body .post-table th, #site .art-body .post-table td { border: 1px solid var(--seam); padding: 10px 14px; text-align: start; vertical-align: top; }
#site .art-body .post-table th { background: var(--ink-2); font-weight: 600; color: var(--mist); }
#site .art-body pre code { background: none; padding: 0; white-space: pre; }
#site .art-body hr { border: 0; height: 1px; background: var(--seam); margin-block: 2.4em; }
#site .art-body .intro { font-size: 21px; line-height: 1.9; color: var(--mist); }
@@ -285,6 +302,11 @@ body { background: var(--ink); color: var(--mist); }
#site .paywall h2 { font-size: clamp(24px, 2.4vw, 30px); margin: 0 0 12px; }
#site .paywall p { color: var(--stone); font-size: 16.5px; }
#site .paywall-actions { display: flex; flex-wrap: wrap; gap: 12px; margin: 24px 0 14px; }
#site .paywall-preview ul { list-style: none; margin: 0 0 6px; padding: 0; display: grid; gap: 8px; }
#site .paywall-preview li { display: flex; gap: 10px; align-items: baseline; color: var(--mist); font-size: 15.5px; }
#site .paywall-preview li svg { flex: none; width: 14px; height: 14px; transform: translateY(2px); }
#site .early-notice { margin: 0 0 28px; padding: 14px 18px; border: 1px solid var(--seam); border-inline-start: 2px solid var(--champagne); border-radius: var(--r-md); background: var(--basalt); }
#site .early-notice p { color: var(--stone); font-size: 16.5px; margin: 0; }
#site .art-aside { position: sticky; top: 104px; display: grid; gap: 28px; }
#site .aside-title { font: 600 15px/1.6 var(--font-body); color: var(--mist); margin-bottom: 10px; }
#site .toc ol { list-style: none; margin: 0; padding: 0; border-inline-start: 1px solid var(--seam); }
@@ -324,6 +346,13 @@ body { background: var(--ink); color: var(--mist); }
MEMBERSHIP
================================================================== */
#site.v2-membership .mem-hero { padding-block: clamp(56px, 8vw, 104px); border-bottom: 1px solid var(--seam); }
#site.v2-membership .early-access { padding-top: clamp(32px, 5vw, 56px); }
#site.v2-membership .early-access .wrap > p { color: var(--stone); max-width: 70ch; }
#site.v2-membership .early-access h2 { font-size: clamp(22px, 2.4vw, 30px); margin-bottom: 10px; }
#site .notify-form { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 18px; align-items: center; }
#site .notify-form input { min-height: 48px; padding: 0 14px; border: 1px solid var(--seam); border-radius: var(--r-sm, 10px); background: var(--bg); color: var(--fg); font: inherit; min-width: min(320px, 100%); }
#site .notify-form .notify-error { color: var(--error, #b4443c); width: 100%; margin: 0; }
#site .notify-done { color: var(--success, var(--champagne)); font-weight: 600; margin-top: 18px; }
#site.v2-membership .mem-hero-grid { display: grid; grid-template-columns: minmax(0, 1.3fr) minmax(300px, 1fr); gap: clamp(32px, 6vw, 88px); align-items: start; }
#site.v2-membership .mem-hero h1 { font-size: clamp(36px, 4.6vw, 60px); max-width: 15ch; }
#site.v2-membership .mem-hero .lede { margin-top: 22px; }
@@ -341,6 +370,7 @@ body { background: var(--ink); color: var(--mist); }
#site .plan-cta .btn { width: 100%; }
#site .plan-soon { padding: 14px 16px; border: 1px dashed var(--seam-2); border-radius: var(--r-sm); color: var(--stone); font-size: 14.5px; }
#site .plan-soon a { color: var(--mist); text-decoration: underline; text-underline-offset: 4px; }
#site .plan-soon-wrap { display: grid; gap: 10px; justify-items: start; }
#site.v2-membership .mem-samples { padding-block: clamp(64px, 8vw, 104px); background: var(--ink-2); border-bottom: 1px solid var(--seam); }
#site .sample-grid { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 28px 24px; }
#site .sample { display: grid; gap: 8px; align-content: start; height: 100%; }
@@ -605,6 +635,7 @@ body, #site { background: var(--ink); color: var(--mist); }
#site.v2-article .art-head { background: var(--ink-2); }
#site .art-body pre { background: #0f172a; color: #e2e8f0; border-color: #0f172a; }
#site .paywall { background: #f2faf7; border-color: #cfe9e1; border-top-color: var(--champagne); }
#site .early-notice { background: #f2faf7; border-color: #cfe9e1; border-inline-start-color: var(--champagne); }
#site .comment, #site .comment-gate { background: #fff; }
#site .art-related { background: var(--ink-2); }
#site :is(.related-item, .sample) { background: #fff; }