{"ok":true,"meta":{"generatedAt":"2026-06-30T13:17:42.902Z"},"data":{"version":"tzv3-launch-checklist-v1","endpoint":"/api/infrastructure/launch-checklist","summary":{"stages":14,"blockingStages":14,"requiredEnvironment":["NEXT_PUBLIC_SITE_URL","NEXT_PUBLIC_SCHEDULE_URL","DATABASE_URL","ADMIN_API_TOKEN","ADMIN_SESSION_SECRET","TELEGRAM_WEBHOOK_SECRET","VIP_CLUB_WEBHOOK_URL","VIP_CLUB_WEBHOOK_TOKEN","NEXT_PUBLIC_MEDIA_CDN_URL","CLOUDFLARE_R2_BUCKET","CLOUDFLARE_R2_ACCESS_KEY_ID","CLOUDFLARE_R2_SECRET_ACCESS_KEY","ELASTICSEARCH_URL","ELASTICSEARCH_API_KEY","UPSTASH_REDIS_REST_URL","UPSTASH_REDIS_REST_TOKEN","WEB_VITALS_ENDPOINT_URL","LEGAL_CONTACT_EMAIL"],"optionalEnvironment":["NEXT_PUBLIC_SCHEDULE_EMBED_URL","NEXT_PUBLIC_SCHEDULE_WIDGET_URL","NEXT_PUBLIC_SCHEDULE_SITE","NEXT_PUBLIC_SCHEDULE_LANG","SCHEDULE_API_URL","SCHEDULE_API_TOKEN","SCHEDULE_AVAILABILITY_PATH","SCHEDULE_REQUEST_PATH","ELASTICSEARCH_INDEX","NEXT_PUBLIC_VAPID_PUBLIC_KEY","PWA_PUSH_PROVIDER_URL","PWA_PUSH_PROVIDER_TOKEN","WEB_VITALS_ENDPOINT_TOKEN","CLOUDFLARE_ACCOUNT_ID","CLOUDFLARE_ZONE_ID","CLOUDFLARE_API_TOKEN","MIRROR_DOMAINS","MIRROR_TELEGRAM_ALERT_URL"],"ownerInputCount":52},"stages":[{"id":"domain","order":1,"title":"Canonical production domain","ownerInputs":["Final domain name","DNS or Cloudflare access","Final brand spelling"],"implementationSteps":["Set NEXT_PUBLIC_SITE_URL to the real HTTPS domain.","Confirm the website source repository is GitHub parkourcafe/artesc, not the ready-made schedule project repository.","Run npm run source:audit and open /api/infrastructure/source-control before Vercel env writes.","Run npm run ci:audit and open /api/infrastructure/ci-policy so GitHub Actions quality gates are present before launch.","Run npm run github-ci:audit after the latest push to capture hosted GitHub Actions success before production promotion.","Run vercel link against the confirmed Artesc website project, not australia-wlkk.","Run npm run vercel:link:audit and confirm the linked project is the Artesc website project before env writes.","Point DNS to the selected Vercel or Netlify project.","Open /api/infrastructure/public-origin-policy and confirm canonical domain, schedule URL, media CDN URL, route proofs, and Vercel link guard.","Verify canonical URLs, robots.txt, sitemap.xml, OpenGraph, and security headers."],"environment":["NEXT_PUBLIC_SITE_URL"],"verification":["npm run source:audit","npm run ci:audit","npm run github-ci:audit","npm run vercel:link:audit","npm run origin:audit -- --require-production","curl -s https://your-domain.example/api/infrastructure/source-control","curl -s https://your-domain.example/api/infrastructure/ci-policy","curl -s https://your-domain.example/api/infrastructure/public-origin-policy","curl -s https://your-domain.example/api/infrastructure/vercel-link","curl -s https://your-domain.example/robots.txt","curl -s https://your-domain.example/sitemap.xml","TZV3_BASE_URL=https://your-domain.example npm run seo:audit"],"blocksProduction":true},{"id":"schedule","order":2,"title":"Ready-made schedule connector","ownerInputs":["Public schedule URL","Schedule iframe URL","Schedule widget script URL","Schedule admin/import access for provider creation","Real providers attached to schedule tenant site=artesc","Schedule API base URL only if server-side availability/request forwarding is required","Schedule API token only if the optional server API requires auth","Availability and request endpoint paths only if the optional server API differs from defaults","Profile slug mapping used by the schedule service"],"implementationSteps":["Set NEXT_PUBLIC_SCHEDULE_URL for all public CTA links.","Set NEXT_PUBLIC_SCHEDULE_EMBED_URL or use the default australia-wlkk embed URL for /schedule-preview.","Keep NEXT_PUBLIC_SCHEDULE_SITE=artesc in production; use site-next only for temporary visual checks.","Open /api/schedule/provider-handoff-policy and create/update provider records in the ready-made schedule tenant with matching profile slugs.","Open /api/schedule/provider-import-payload and copy providerImportPayload into the ready-made schedule admin/import.","Attach real providers to site=artesc in the ready-made schedule project.","Run /api/schedule/provider-reconciliation to verify every imported provider id is visible in public site=artesc.","Optionally set SCHEDULE_API_URL, SCHEDULE_API_TOKEN, SCHEDULE_AVAILABILITY_PATH, and SCHEDULE_REQUEST_PATH when the schedule provider exposes server-side endpoints.","Verify provider handoff, provider import payload, provider reconciliation, profile-aware CTA links, /schedule-preview, npm run schedule:links:audit, npm run schedule:audit, and /api/schedule/status."],"environment":["NEXT_PUBLIC_SCHEDULE_URL","NEXT_PUBLIC_SCHEDULE_EMBED_URL","NEXT_PUBLIC_SCHEDULE_WIDGET_URL","NEXT_PUBLIC_SCHEDULE_SITE","NEXT_PUBLIC_SCHEDULE_LANG","SCHEDULE_API_URL","SCHEDULE_API_TOKEN","SCHEDULE_AVAILABILITY_PATH","SCHEDULE_REQUEST_PATH"],"verification":["npm run schedule:provider-handoff","npm run schedule:provider-import-payload","npm run schedule:provider-reconciliation -- --require-production","npm run schedule:links:audit","npm run schedule:audit","curl -s https://your-domain.example/api/schedule/provider-handoff-policy","curl -s https://your-domain.example/api/schedule/provider-import-payload","curl -s https://your-domain.example/api/schedule/provider-reconciliation","curl -s https://your-domain.example/api/schedule/link-audit-policy","curl -I https://your-domain.example/schedule-preview?site=artesc&lang=en","curl -s https://your-domain.example/api/schedule/tenant-status","curl -s https://your-domain.example/api/schedule/status","curl -s 'https://your-domain.example/api/schedule/availability?profile=sofia'"],"blocksProduction":true},{"id":"database","order":3,"title":"Production PostgreSQL and seed import","ownerInputs":["Supabase, Neon, or PostgreSQL DATABASE_URL","Decision on production region"],"implementationSteps":["Record /api/database/audit-policy, /api/database/migration-manifest, /api/database/seed-manifest, and /api/database/seed-payload before touching production data.","Run npm run database:seed-payload and confirm the no-write payload counts and fullSeed hash before POST /api/admin/seed.","Apply drizzle/0001_initial_tzv3.sql, drizzle/0002_review_author_alias.sql, and drizzle/0003_programmatic_seo_pages.sql.","Set DATABASE_URL in the hosting provider.","Run POST /api/admin/seed with x-admin-token.","Verify profile, media, services, collections, links, and programmatic SEO counts."],"environment":["DATABASE_URL","ADMIN_API_TOKEN"],"verification":["npm run database:seed-payload","npm run database:audit","curl -s https://your-domain.example/api/database/bootstrap-policy","curl -s https://your-domain.example/api/database/audit-policy","curl -s https://your-domain.example/api/database/seed-payload","curl -s https://your-domain.example/api/health","curl -s https://your-domain.example/api/profiles"],"blocksProduction":true},{"id":"admin-security","order":4,"title":"Admin secrets and audit","ownerInputs":["Permission to generate secrets or supplied ADMIN_API_TOKEN and ADMIN_SESSION_SECRET","Admin actor naming convention"],"implementationSteps":["Run npm run secrets:rotation and confirm generated Artesc secrets, owner/provider credentials, public defaults, and post-rotation audits are separated before env writes.","Set ADMIN_API_TOKEN and ADMIN_SESSION_SECRET.","Verify /admin session cookie behavior and protected admin endpoints.","Verify /admin/profiles keeps the profile editor locked until a signed HttpOnly admin session is active.","Verify admin audit logs are written after profile, seed, and moderation operations."],"environment":["ADMIN_API_TOKEN","ADMIN_SESSION_SECRET"],"verification":["npm run admin:audit","npm run secrets:rotation","curl -s https://your-domain.example/api/infrastructure/secret-rotation","curl -s https://your-domain.example/api/admin/session","curl -s https://your-domain.example/api/admin/security-audit-policy","Open https://your-domain.example/admin/profiles and confirm the editor is locked before login, then unlocked after POST /api/admin/session.","curl -s https://your-domain.example/api/admin/audit/policy"],"blocksProduction":true},{"id":"telegram-status","order":5,"title":"Telegram live-status workflow","ownerInputs":["Telegram bot token","TELEGRAM_WEBHOOK_SECRET","Operator chat or workflow IDs"],"implementationSteps":["Run npm run telegram:handoff and review the no-secret BotFather/setWebhook handoff.","Set TELEGRAM_WEBHOOK_SECRET.","For direct Telegram delivery, run setWebhook with secret_token so Telegram sends x-telegram-bot-api-secret-token.","For a custom relay workflow, forward x-webhook-token to POST /api/webhooks/telegram/status.","Forward either JSON payloads or raw Telegram message updates with /status commands.","Send x-telegram-bot-api-secret-token or x-webhook-token with every webhook request.","Verify DB-first status updates and browser SSE badges."],"environment":["TELEGRAM_WEBHOOK_SECRET","DATABASE_URL"],"verification":["npm run telegram:handoff","npm run telegram:audit","curl -s https://your-domain.example/api/webhooks/telegram/setup-policy","curl -s https://your-domain.example/api/webhooks/telegram/status","curl -s https://your-domain.example/api/status","curl -N --max-time 2 https://your-domain.example/api/status/stream"],"blocksProduction":true},{"id":"vip-club","order":6,"title":"VIP Club verification workflow","ownerInputs":["VIP Club Telegram workflow URL","VIP Club webhook signing token","Operator verification procedure"],"implementationSteps":["Run npm run club:handoff and review the no-secret external receiver contract.","Set VIP_CLUB_WEBHOOK_URL and VIP_CLUB_WEBHOOK_TOKEN.","Connect the receiver used by /api/club/verify.","Verify the receiver checks x-artesc-signature, x-artesc-timestamp, and x-idempotency-key.","Keep subscriptions and payments disabled until legal/payment approval is complete."],"environment":["VIP_CLUB_WEBHOOK_URL","VIP_CLUB_WEBHOOK_TOKEN"],"verification":["npm run club:handoff","npm run club:audit","curl -s https://your-domain.example/api/club/policy","curl -s https://your-domain.example/api/club/handoff-policy","curl -s https://your-domain.example/api/club/audit-policy","curl -I https://your-domain.example/club"],"blocksProduction":true},{"id":"media-cdn","order":7,"title":"Media storage and CDN delivery","ownerInputs":["NEXT_PUBLIC_MEDIA_CDN_URL","Cloudflare R2 bucket","R2 access key","R2 secret","Approved media upload workflow"],"implementationSteps":["Open /api/media/asset-manifest and use its publicPath, r2Key, contentType, bytes, and sha256 values as the upload contract.","Open /api/media/public-url-policy and confirm external consumers will receive production HTTPS media URLs, not example or localhost origins.","Upload public catalog images and videos to the CDN path structure from the manifest.","Set NEXT_PUBLIC_MEDIA_CDN_URL for catalog images and video visits.","Set Cloudflare R2 storage env for production media operations.","Verify Next/Image remote patterns and public profile images."],"environment":["NEXT_PUBLIC_MEDIA_CDN_URL","CLOUDFLARE_R2_BUCKET","CLOUDFLARE_R2_ACCESS_KEY_ID","CLOUDFLARE_R2_SECRET_ACCESS_KEY"],"verification":["npm run media:public-urls","npm run media:audit","curl -s https://your-domain.example/api/media/public-url-policy","curl -s https://your-domain.example/api/media/video-policy","curl -s https://your-domain.example/api/media/enhancement-policy","curl -s https://your-domain.example/api/media/asset-manifest"],"blocksProduction":true},{"id":"search-cache","order":8,"title":"Elastic search and Redis cache","ownerInputs":["Elastic URL","Elastic API key","Elastic profile index name","Upstash Redis REST URL","Upstash Redis REST token"],"implementationSteps":["Open /api/search/index-manifest and use its settings, mappings, document payload, and hashes as the index import contract.","Open /api/search/bulk-payload and use createIndexRequest plus bulkNdjson as the copy-ready Elastic import packet.","Create or sync the profile index in Elastic from the manifest.","Set ELASTICSEARCH_URL, ELASTICSEARCH_API_KEY, and ELASTICSEARCH_INDEX.","Set UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN for repeated-result cache.","Verify /api/search reports source elastic or elastic-cache."],"environment":["ELASTICSEARCH_URL","ELASTICSEARCH_API_KEY","ELASTICSEARCH_INDEX","UPSTASH_REDIS_REST_URL","UPSTASH_REDIS_REST_TOKEN"],"verification":["npm run search:bulk-payload","npm run search:audit","curl -s https://your-domain.example/api/search/policy","curl -s https://your-domain.example/api/search/index-manifest","curl -s https://your-domain.example/api/search/bulk-payload","curl -s 'https://your-domain.example/api/search?q=vip%20english'"],"blocksProduction":true},{"id":"reviews-seo","order":9,"title":"Real reviews and Review JSON-LD","ownerInputs":["At least one real moderated review","Admin moderation procedure","Decision to expose Review/AggregateRating JSON-LD"],"implementationSteps":["Collect real review intake through /api/reviews after PostgreSQL is connected.","Moderate reviews through protected /api/admin/reviews.","Publish only verified reviews with authorAlias, rating, text, source, and isPublished=true.","Keep synthetic, paid, duplicate, or unverifiable reviews unpublished and out of JSON-LD."],"environment":["DATABASE_URL","ADMIN_API_TOKEN"],"verification":["npm run reviews:audit","curl -s https://your-domain.example/api/reviews/policy","curl -s https://your-domain.example/api/reviews/audit-policy","curl -s https://your-domain.example/api/seo/review-schema"],"blocksProduction":true},{"id":"pwa-push","order":10,"title":"PWA push provider and unsubscribe evidence","ownerInputs":["Approved PWA push provider endpoint","VAPID public key","PWA push provider bearer token","Provider-side delete/export evidence before notification sends"],"implementationSteps":["Set NEXT_PUBLIC_VAPID_PUBLIC_KEY, PWA_PUSH_PROVIDER_URL, and PWA_PUSH_PROVIDER_TOKEN.","Keep PWA push limited to explicit /favorites opt-in and favorite-status notifications.","Confirm the provider accepts x-artesc-push-event, x-artesc-signature, and x-idempotency-key.","Run the no-write PWA push audit before enabling notification sends."],"environment":["NEXT_PUBLIC_VAPID_PUBLIC_KEY","PWA_PUSH_PROVIDER_URL","PWA_PUSH_PROVIDER_TOKEN"],"verification":["npm run pwa-push:audit","curl -s https://your-domain.example/api/pwa/push/policy","curl -s https://your-domain.example/api/pwa/push/audit-policy"],"blocksProduction":true},{"id":"analytics","order":11,"title":"Web Vitals and analytics sink","ownerInputs":["Approved analytics provider or endpoint","WEB_VITALS_ENDPOINT_URL","WEB_VITALS_ENDPOINT_TOKEN if required"],"implementationSteps":["Set WEB_VITALS_ENDPOINT_URL and optional WEB_VITALS_ENDPOINT_TOKEN.","Confirm provider privacy review and retention.","Verify that forwarded payloads drop href, userAgent, query, and hash."],"environment":["WEB_VITALS_ENDPOINT_URL","WEB_VITALS_ENDPOINT_TOKEN"],"verification":["npm run vitals:audit","curl -s https://your-domain.example/api/performance/vitals"],"blocksProduction":true},{"id":"legal","order":12,"title":"Legal pages and takedown contact","ownerInputs":["LEGAL_CONTACT_EMAIL","Final legal wording","Counsel approval for retention and takedown flow"],"implementationSteps":["Set LEGAL_CONTACT_EMAIL.","Review /legal, /legal/privacy, /legal/data-retention, and /legal/takedown.","Confirm /api/legal/contact-policy shows the dedicated inbox, local no-storage mode, request fields, and service-level targets.","Confirm retention policy and deletion procedure."],"environment":["LEGAL_CONTACT_EMAIL"],"verification":["npm run legal:audit","curl -s https://your-domain.example/legal","curl -s https://your-domain.example/api/legal/retention-policy","curl -s https://your-domain.example/api/legal/contact-policy","curl -s https://your-domain.example/api/legal/audit-policy"],"blocksProduction":true},{"id":"cloudflare","order":13,"title":"Cloudflare DNS, WAF, and monitoring","ownerInputs":["Cloudflare account ID","Zone ID","API token","Mirror domains if used","Telegram alert webhook if used"],"implementationSteps":["Proxy the production domain through Cloudflare.","Configure WAF, bot/rate-limit rules, cache rules, and TLS.","Set mirror monitoring variables when mirror domains are used."],"environment":["CLOUDFLARE_ACCOUNT_ID","CLOUDFLARE_ZONE_ID","CLOUDFLARE_API_TOKEN","MIRROR_DOMAINS","MIRROR_TELEGRAM_ALERT_URL"],"verification":["npm run cloudflare:audit","curl -s https://your-domain.example/api/infrastructure/cloudflare/policy","curl -s https://your-domain.example/api/security/policy","curl -s https://your-domain.example/api/infrastructure/mirrors/check"],"blocksProduction":true},{"id":"final-qa","order":14,"title":"Final deployed-domain QA","ownerInputs":["Deployed URL","Approval to run read-only checks against production"],"implementationSteps":["Run production env check.","Open /api/infrastructure/production-evidence and confirm every blocking stage has a no-write evidence command.","Run readiness, SEO audit, and load smoke on the deployed domain.","Manually verify homepage, profile page, schedule CTA, admin noindex, legal pages, and status badges.","Do not mark production ready until all required gates pass."],"environment":["NEXT_PUBLIC_SITE_URL","NEXT_PUBLIC_SCHEDULE_URL","DATABASE_URL","ADMIN_API_TOKEN","ADMIN_SESSION_SECRET","TELEGRAM_WEBHOOK_SECRET","VIP_CLUB_WEBHOOK_URL","VIP_CLUB_WEBHOOK_TOKEN","LEGAL_CONTACT_EMAIL","ELASTICSEARCH_URL","ELASTICSEARCH_API_KEY","UPSTASH_REDIS_REST_URL","UPSTASH_REDIS_REST_TOKEN","NEXT_PUBLIC_MEDIA_CDN_URL","CLOUDFLARE_R2_BUCKET","CLOUDFLARE_R2_ACCESS_KEY_ID","CLOUDFLARE_R2_SECRET_ACCESS_KEY","WEB_VITALS_ENDPOINT_URL"],"verification":["TZV3_BASE_URL=https://your-domain.example npm run preflight:production","npm run github-ci:audit","npm run secrets:rotation -- --require-production","npm run env:check:production","npm run origin:audit -- --require-production","npm run evidence:audit -- --require-production","curl -s https://your-domain.example/api/infrastructure/production-evidence","npm run admin:audit","npm run database:seed-payload","npm run database:audit","npm run cloudflare:audit","npm run media:public-urls","npm run media:audit","npm run pwa-push:audit","npm run legal:audit","npm run reviews:audit","npm run schedule:provider-handoff","npm run schedule:provider-import-payload","npm run schedule:provider-reconciliation -- --require-production","npm run schedule:links:audit","npm run schedule:audit","npm run search:bulk-payload","npm run search:audit","npm run telegram:handoff","npm run telegram:audit","npm run club:handoff","npm run vitals:audit","TZV3_BASE_URL=https://your-domain.example npm run readiness","TZV3_BASE_URL=https://your-domain.example npm run seo:audit","TZV3_BASE_URL=https://your-domain.example npm run load:smoke"],"blocksProduction":true}],"ownerInputs":["Final domain name","DNS or Cloudflare access","Final brand spelling","Public schedule URL","Schedule iframe URL","Schedule widget script URL","Schedule admin/import access for provider creation","Real providers attached to schedule tenant site=artesc","Schedule API base URL only if server-side availability/request forwarding is required","Schedule API token only if the optional server API requires auth","Availability and request endpoint paths only if the optional server API differs from defaults","Profile slug mapping used by the schedule service","Supabase, Neon, or PostgreSQL DATABASE_URL","Decision on production region","Permission to generate secrets or supplied ADMIN_API_TOKEN and ADMIN_SESSION_SECRET","Admin actor naming convention","Telegram bot token","TELEGRAM_WEBHOOK_SECRET","Operator chat or workflow IDs","VIP Club Telegram workflow URL","VIP Club webhook signing token","Operator verification procedure","NEXT_PUBLIC_MEDIA_CDN_URL","Cloudflare R2 bucket","R2 access key","R2 secret","Approved media upload workflow","Elastic URL","Elastic API key","Elastic profile index name","Upstash Redis REST URL","Upstash Redis REST token","At least one real moderated review","Admin moderation procedure","Decision to expose Review/AggregateRating JSON-LD","Approved PWA push provider endpoint","VAPID public key","PWA push provider bearer token","Provider-side delete/export evidence before notification sends","Approved analytics provider or endpoint","WEB_VITALS_ENDPOINT_URL","WEB_VITALS_ENDPOINT_TOKEN if required","LEGAL_CONTACT_EMAIL","Final legal wording","Counsel approval for retention and takedown flow","Cloudflare account ID","Zone ID","API token","Mirror domains if used","Telegram alert webhook if used","Deployed URL","Approval to run read-only checks against production"],"completionRule":"Production can be treated as TZV3-ready only after every blocking stage has real env/evidence on the deployed domain."}}