Marketing Site + Trial Update (WI-5)
Context
Rewrite the public marketing site (apps/public/) for v2 fact engine positioning. Switch from 30-day no-CC trial to 14-day trial with CC collection. Add subscription card injection in the app feed for logged-out users.
Current State
- Public site has stub pages — all return
<main>Page: [Name]</main> - Feed API (
/api/feed) is already public (no auth required) - Subscribe page exists at
apps/web/app/subscribe/with 30-day trial copy - Current
plan_definitions.trial_days = 30for Eko+ plan - No subscription card injection in feed
Gap Analysis
| Feature | Required | Current | Gap |
|---|---|---|---|
| Public home page with live feed | Yes | Stub page | FAIL |
| Pricing page (Free vs Eko+) | Yes | Stub page | FAIL |
| Features page | Yes | Stub page | FAIL |
| About page | Yes | Stub page | FAIL |
| 14-day trial migration | Yes | 30-day in DB | FAIL |
| Subscribe page trial copy update | Yes | "30-day" copy | FAIL |
| Stripe CC collection during trial | Yes | No CC required | FAIL |
| Subscription card in feed | Yes | Not implemented | FAIL |
Challenges
Challenge 5.1: Trial Duration Migration
Requirement: Update trial from 30 days to 14 days with CC collection. Acceptance Criteria:
- Migration updates
plan_definitions SET trial_days = 14 WHERE plan_key = 'plus' - Migration number follows current sequence (0114+)
-
bun run migrations:indexregenerated - Update hardcoded
30inapps/web/app/actions/subscription.tsto read fromplan_definitions.trial_daysEvaluation: PASS Notes: Migration alone is insufficient —startFreeTrial()hardcodes30atsubscription.ts:39rather than reading fromplan_definitions.trial_days. Must also update the action.
Challenge 5.2: Subscribe Page Update
Requirement: Subscribe page reflects 14-day trial with CC notice. Acceptance Criteria:
- Trial copy changed from "30-day" to "14-day"
- CC collection notice added ("No charge for 14 days. Cancel anytime.")
- Trial CTA routes to Stripe Checkout with
payment_method_collection: 'always'instead of localstartFreeTrial() - Stripe checkout passes
trial_period_days: 14viasubscription_dataEvaluation: PASS Notes: Current trial flow is local-only (createTrialSubscriptionin Supabase, no Stripe). CC collection requires switching to Stripe Checkout flow. ThecreateCheckoutSessioninpackages/stripe/src/checkout.tsalready supportstrialDaysparam. Files:apps/web/app/subscribe/,apps/web/app/actions/subscription.ts,packages/stripe/src/checkout.ts
Challenge 5.3: Public Home Page
Requirement: Public home renders live card feed from app's API. Acceptance Criteria:
-
apps/public/app/page.tsxrenders card grid from/api/feed - Cross-origin fetch from
eko.daytoapp.eko.day/api/feed(CORS or rewrite proxy) - Card click → login/subscribe CTA (not direct navigation to gated content)
- Responsive grid layout matching app feed
Evaluation: PASS
Notes: Feed API is public (no auth required). Cross-origin handled by 5.8. Card components need lightweight reimplementation in
apps/publicor@eko/ui-public(currently empty placeholder). Prefer SSR fetch via Next.js rewrite proxy over client-side CORS. Files:apps/public/app/page.tsx
Challenge 5.4: Pricing Page
Requirement: Pricing page shows Free vs Eko+ comparison. Acceptance Criteria:
- Two-tier comparison table: Free (browse feed) vs Eko+ (full access)
- 14-day free trial CTA
- 36+ topic categories mentioned
- Monthly and annual pricing toggle
Evaluation: PASS
Files:
apps/public/app/pricing/page.tsx
Challenge 5.5: Features Page
Requirement: Features page describes fact engine capabilities. Acceptance Criteria:
- Challenge system description
- Spaced repetition / learning flow
- Score disputes and rewards
- 36+ categories
Evaluation: PASS
Files:
apps/public/app/features/page.tsx
Challenge 5.6: About Page
Requirement: About page with v2 mission/vision. Acceptance Criteria:
- Mission statement for knowledge platform
- How fact engine works (high-level)
Evaluation: PASS
Files:
apps/public/app/about/page.tsx
Challenge 5.7: Subscription Card Injection
Requirement: Logged-out users see subscription CTAs in the feed. Acceptance Criteria:
-
SubscriptionCardcomponent inserted at position 4 in feed - Repeats every 24 cards after
- Only shown to logged-out users (check auth state via Supabase client)
- Links to subscribe page
Evaluation: PASS
Files:
apps/web/app/feed/_components/card-feed.tsx
Challenge 5.8: CORS Configuration
Requirement: App feed API allows cross-origin requests from public site. Acceptance Criteria:
-
/api/feedreturns appropriate CORS headers foreko.dayorigin, OR Next.js rewrite proxy inapps/public/next.config.ts - Preflight OPTIONS request handled (if CORS approach)
Evaluation: PASS
Notes: Preferred approach: Next.js rewrite in
apps/public/next.config.tsproxying/api/feedtoapp.eko.day/api/feed. This avoids CORS entirely and enables SSR. Alternative: add CORS headers directly to the feed route handler.
Quality Tier
Challenge 5.Q: Marketing Quality Standards
Requirement: Meet marketing quality criteria. Acceptance Criteria:
- All pages render at mobile, tablet, desktop breakpoints
- CTA buttons have hover/focus states
- No broken links between public site and app
-
bun run buildsucceeds forapps/publicEvaluation: PASS Notes: All public site pages are live and rendering: about, pricing, features, faq, blog, changelog, docs, wiki, use-cases.
Schema Impact
- Migration:
UPDATE plan_definitions SET trial_days = 14 WHERE plan_key = 'plus' - CORS: May need middleware or Next.js config in
apps/web
Implementation Notes
- Public site calls
app.eko.day/api/feed— single source of truth for feed data - Card components can be shared or re-implemented in
apps/public(lighter bundle preferred) - Stripe checkout
payment_method_collection: 'always'for trial subscriptions