('auto');
useEffect(() => {
const stored = localStorage.getItem('waggle.theme') as Mode | null;
setMode(stored ?? 'auto');
}, []);
useEffect(() => {
const apply = (m: Mode) => {
const effective = m === 'auto'
? (window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark')
: m;
document.documentElement.setAttribute('data-theme', effective);
};
apply(mode);
localStorage.setItem('waggle.theme', mode);
if (mode === 'auto') {
const mq = window.matchMedia('(prefers-color-scheme: light)');
const handler = () => apply(mode);
mq.addEventListener('change', handler);
return () => mq.removeEventListener('change', handler);
}
}, [mode]);
return (
);
}
```
Place `` u Navbar desno (visible on all pages).
### §2.3 Asset variant resolution
Bee personas, app icons, hex texture imaju light + dark variants. Dodati helper:
```tsx
import { useTheme } from '@/lib/theme';
const theme = useTheme();
const beeAsset = `/brand/bee-orchestrator-${theme}.png`;
```
Za Hero specifically: switch bee asset on theme change (orchestrator-dark vs orchestrator-light).
---
## §3 Bootstrap items — production infrastructure
### §3.1 API routes
#### `/api/stripe/checkout` (POST)
- Replace external `https://cloud.waggle-os.ai/api/stripe/create-checkout-session`
- Server-side init Stripe client sa `STRIPE_SECRET_KEY` env var
- Body: `{ tier: 'PRO' | 'TEAMS', billingPeriod: 'monthly' | 'annual' }`
- Returns: `{ url: string }` (Stripe Checkout Session URL)
- Error: `{ message: string }` 400/500
- Use Stripe Price IDs from env (`STRIPE_PRICE_PRO_MONTHLY`, `STRIPE_PRICE_TEAMS_MONTHLY`, etc.)
#### `/api/waitlist` (POST)
- Body: `{ email: string, persona?: string, source?: string }`
- Validate email format
- Store: forward to Resend / Supabase / Postmark — choose one (Marko: pick what's cheapest, suggest Resend for now)
- Returns: `{ success: boolean }`
- Rate limit: 5 requests/min per IP
#### `/api/analytics` (POST)
- Body: `{ event: string, properties: Record, anonymous_id: string }`
- Anonymous events only (no PII unless user opted in via cookie consent)
- Forward to PostHog or Plausible — Marko pick (PostHog je in tools list, prefer)
- Returns: `{ accepted: boolean }`
### §3.2 Cookie consent + GDPR
`components/CookieBanner.tsx`:
- Show on first visit
- 3 options: "Accept all", "Necessary only", "Customize"
- Store consent: `localStorage.setItem('waggle.consent', JSON.stringify({...}))`
- Categories: necessary (always on), analytics (opt-in), marketing (opt-in)
- Render bottom-fixed sa backdrop blur na dark / soft drop shadow na light
### §3.3 Legal pages
`app/(legal)/privacy/page.tsx`, `terms/page.tsx`, `cookies/page.tsx`:
- Markdown-driven content (lib/markdown.ts helper)
- Static generation (export const dynamic = 'force-static')
- Linked from Footer + CookieBanner
Privacy text seed: koristi `pm-toolkit:privacy-policy` skill output kao starting draft, manual review pre publish-a.
### §3.4 SEO + metadata
`app/layout.tsx`:
```tsx
export const metadata: Metadata = {
metadataBase: new URL('https://waggle-os.ai'),
title: {
default: 'Waggle — AI Agents That Remember',
template: '%s · Waggle'
},
description: 'A workspace where AI agents remember your context, connect to your tools, and improve with every interaction. Desktop-native. Privacy-first. Local-first cognitive layer with bitemporal memory.',
keywords: ['AI memory', 'cognitive layer', 'local-first AI', 'EU AI Act', 'GDPR AI', 'bitemporal knowledge graph', 'MCP protocol', 'agent harness'],
authors: [{ name: 'Egzakta Group' }],
openGraph: {
type: 'website',
siteName: 'Waggle',
images: [{ url: '/opengraph-image.png', width: 1200, height: 630 }],
},
twitter: {
card: 'summary_large_image',
images: ['/twitter-image.png'],
creator: '@waggle_os',
},
robots: { index: true, follow: true },
alternates: {
canonical: '/',
languages: { 'en': '/' }, // expand on i18n rollout
},
};
```
`public/robots.txt`:
```
User-agent: *
Allow: /
Disallow: /api/
Sitemap: https://waggle-os.ai/sitemap.xml
```
`app/sitemap.ts`:
```tsx
import { MetadataRoute } from 'next';
export default function sitemap(): MetadataRoute.Sitemap {
return [
{ url: 'https://waggle-os.ai', lastModified: new Date(), priority: 1.0 },
{ url: 'https://waggle-os.ai/pricing', lastModified: new Date(), priority: 0.8 },
{ url: 'https://waggle-os.ai/privacy', lastModified: new Date(), priority: 0.3 },
{ url: 'https://waggle-os.ai/terms', lastModified: new Date(), priority: 0.3 },
];
}
```
### §3.5 i18n scaffolding (English first)
Install `next-intl` (recommended for App Router):
```
pnpm add next-intl
```
Locale routing: `/[locale]/...` ali za MVP samo English live, infrastruktura ready za sledeće lokale (DE, FR, ES) bez code rewrite.
`middleware.ts`:
```ts
import createMiddleware from 'next-intl/middleware';
export default createMiddleware({
locales: ['en'],
defaultLocale: 'en',
});
export const config = { matcher: ['/((?!api|_next|.*\\..*).*)'] };
```
`messages/en.json` — extract user-facing strings iz komponenti (Hero h1, CTA labels, pricing tier names, BetaSignup form copy). Per `feedback_i18n_landing_policy.md`: engleski first, locale-ready infra predefinisana.
### §3.6 Build + deploy
**Recommended host**: **Vercel** (zero-config Next.js, native preview deploys, edge runtime za API routes, integrated analytics)
Alternative: **Cloudflare Pages** (cheaper za high traffic, edge-first)
Env vars u Vercel dashboard:
- `STRIPE_SECRET_KEY`
- `STRIPE_PRICE_PRO_MONTHLY`
- `STRIPE_PRICE_TEAMS_MONTHLY`
- `STRIPE_WEBHOOK_SECRET`
- `RESEND_API_KEY` (ili Postmark/Supabase ekvivalent)
- `POSTHOG_PROJECT_KEY`
- `POSTHOG_HOST`
- `NEXT_PUBLIC_POSTHOG_KEY` (client-side init)
`next.config.mjs`:
```js
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
images: {
formats: ['image/avif', 'image/webp'],
},
experimental: {
optimizePackageImports: ['lucide-react'],
},
};
export default nextConfig;
```
---
## §4 Wireframe v1.1 LOCKED gap analysis
Per `project_landing_wireframe_v11_locked_2026_04_22` memory, wireframe v1.1 specifies sections:
| Wireframe section | Existing component? | Action |
|---|---|---|
| Hero with KPI counter | Hero.tsx (no KPI counter yet) | **Augment** — add KPI counter sa "X memories preserved", "Y agents running", real-time API call ili static placeholder |
| Why-now hook | NOT PRESENT | **Add** new section between Hero and Features — narrative hook ("AI without memory is groundhog day") |
| Three-product columns | NOT PRESENT (Features may overlap) | **Add or refactor** — "hive-mind (OSS) / Waggle (consumer) / KVARK (enterprise)" 3-column architecture overview |
| How-it-works | HowItWorks.tsx | Verify content matches v1.1 spec |
| Pricing 3-tier | Pricing.tsx | ✓ Functional, **integrate with internal API route** |
| Personas grid 13 bees | BrandPersonasCard.tsx (single card) | **Augment** — add full 13-grid section pre BetaSignup |
| FAQ | NOT PRESENT | **Add** new FAQ section (5-7 questions: pricing, privacy, EU AI Act, MCP, OSS) |
| Founder note | NOT PRESENT | **Add** "From the team" section with Marko's photo + short narrative |
| CTA | Hero CTAs + Pricing CTAs + BetaSignup | Sufficient |
| Footer | Footer.tsx | Verify links: Privacy, Terms, Cookies, Twitter, GitHub, Discord (TBD) |
---
## §5 Test migration
Existing `__tests__/BrandPersonasCard.test.tsx` + `__tests__/setup.ts` keep but adapt:
- Vitest config update (Next.js compatibility, may need `vitest-environment-vitest-pure` or `happy-dom`)
- Add component tests for: ThemeToggle, CookieBanner, Pricing checkout flow (mock Stripe), BetaSignup submission
- Add API route integration tests sa MSW (Mock Service Worker)
---
## §6 Sequential execution plan (12 commits suggested)
Commit 1: `[port] init Next.js 15 scaffold, retain Vite parallel for rollback`
Commit 2: `[port] migrate components to Next.js with use client where needed`
Commit 3: `[port] move src/styles → app/globals.css + light mode tokens block`
Commit 4: `[port] ThemeToggle component + integrate u Navbar`
Commit 5: `[port] API routes — stripe checkout, waitlist, analytics`
Commit 6: `[port] middleware.ts + i18n scaffolding (en only live)`
Commit 7: `[port] legal pages (privacy/terms/cookies) + CookieBanner`
Commit 8: `[port] SEO metadata + sitemap + robots + OG/Twitter images`
Commit 9: `[port] add wireframe v1.1 missing sections (WhyNow + ThreeProducts + PersonasGrid + FAQ + FounderNote)`
Commit 10: `[port] update tests + add new component coverage`
Commit 11: `[port] build verification + Vercel deploy config`
Commit 12: `[port] retire Vite scaffolding (delete vite.config.ts, src/main.tsx etc.) — POST-VERIFICATION`
Commit 1-11: incremental, ne bocе vam working state.
Commit 12: cleanup, tek posle visual + functional QA na deployed staging URL.
---
## §7 Halt criteria + budget
- **Budget**: $0 (no API calls during port — codegen only). Stripe + Resend + PostHog incur $0 setup, pay-per-use after launch.
- **Wall-clock**: 8-12h CC-1 work realistic za scratch port + bootstrap. Marko može da paste-uje brief u CC-1 kad SOTA padne, paralelno sa Gate D exit + claim-narrative work.
- **Halt triggers**:
- Vite cleanup (Commit 12) — only after staging deploy verified by Marko visual review
- Live env vars (Stripe Production keys) — Marko populates u Vercel dashboard, not in code
- Domain DNS cutover (waggle-os.ai → Vercel) — Marko handles
- **Rollback**: Commits 1-11 keep Vite scaffolding present, can `git revert` and rebuild Vite if Next.js port has unforeseen issue. Commit 12 is one-way.
---
## §8 PM signals to watch
- "use client" overuse (every component) — sign of confused server/client split, code review pass needed
- CSS regression na light mode toggle — visual diff vs DS Stage 4 spec
- Stripe checkout flow break — manual test sa test card 4242 4242 4242 4242 pre prod
- SEO meta validation — `next build` output check za canonical URLs, OG images
- Lighthouse score baseline — target ≥90 Performance, ≥95 Accessibility, ≥100 Best Practices, ≥95 SEO
---
## §9 Authorized by
PM Marko Marković, 2026-04-24 evening, full execution delegated ("i sve sam guraj sad, sam odlucuj, ja odoh da spavam citam ujutro sta si sve uradio").
CC-1 može da počne kad benchmark završi i SOTA narrative ratifikuje, ili paralelno ako ima dovoljno context-a (Vite stack je read-only audit, port je clean greenfield Next.js).
Brief je deterministic — sve odluke arhitekture su uzete u brief-u, no clarifying questions needed.
---
## §10 Companion deliverables (paralelno sa ovim brief-om)
PM (claude-opus-4-7) overnight produces:
1. `briefs/2026-04-25-launch-comms-templates.md` — multi-asset suite (technical blog post, LinkedIn, Twitter, hive-mind announcement, waitlist email, press kit)
2. `briefs/e2e-persona-tests/2026-04-25-e2e-persona-test-matrix.md` — 9-archetype × scenarios test matrix (3 monetization tier × 3 user proficiency)
3. `decisions/2026-04-25-overnight-pm-execution-log.md` — what was completed overnight, decision rationale, open items za Marko ujutru
Sve čekaju Marka u 2026-04-25 ujutru za review.