Reaktor DocsBestBudsProduct UI

BestBuds - Product UI

BestBuds UI Migration Plan

Plan for migrating the real BestBuds app in modules/app to the visual and interaction language of the current prototype and desktop website without changing the app graph, data flows, auth behavior, or chat contracts.

Use whenPlanning or reviewing the BestBuds design-system extraction and app restyle.
SourceCodex scan of appWeb, prototype, modules/design, modules/app, and tests.
Route/docs/bestbuds-ui-migration-plan

Overview

The migration should be test-led. First capture the current prototype and website behavior, then extract the design system into modules/design, then replace the existing Compose UI screen by screen.

Preserve

Keep the existing Reaktor graph topology, route bindings, repositories, auth flows, analytics hooks, and platform targets. UI migration should not rewrite product behavior.

Extract

Move prototype and desktop website styling into named tokens, atoms, molecules, and screen templates in modules/design. Avoid carrying inline React styling into the app.

Replace

Restyle real app screens with shared design components while leaving graph nodes and data orchestration inside modules/app.

Core rule: appWeb and the mobile prototype define the look and interaction feel; the real app defines the behavior contract.

Source Of Truth

Use this precedence order when code disagrees.

  1. targets/appWeb/src/website_main.tsx and targets/appWeb/src/App.css for desktop website theme, palette tokens, typography, sticky prototype presentation, waitlist UX, and palette persistence.
  2. prototype/*.jsx for full mobile prototype behavior, route inventory, screen-level interaction patterns, local state, stage language, cards, top bars, tab bars, campaign/chat/event/profile flows.
  3. modules/app/src/commonMain/kotlin/ai/bestbuds/app for real app graph topology, repositories, route bindings, analytics, auth, and native behavior.
  4. modules/design as the final shared implementation home.
Legacy frontend scan: targets/appWeb/frontend was an older CRA/Tailwind/shadcn landing page. The only notable reference content was old product copy around a 7-day friendship system, access/foster phases, AI icebreakers, and meeting IRL. It did not contain the current appWeb palette, prototype behavior, or reusable implementation worth preserving, so it was deleted.

Current State

appWeb

The active appWeb entry points are src/main.tsx, src/App.tsx, src/website_main.tsx, src/App.css, src/prototype-inline.jsx, and src/SurfaceBackground.tsx.

Desktop website

Scroll-snapped narrative landing page with fixed top bar, palette selector, waitlist form, WebGL surface background, and sticky phone iframe.

Canonical defaults

Terracotta palette, Fraunces display serif, Space Grotesk body sans, organic cards, radius scale 1.5, accent intensity 1.3, texture off, cool stage language.

Showcased routes

create, landing, campaigns, chat, picks, and events. The mobile website is lighter and should only get smoke coverage for now.

Prototype

The standalone mobile prototype is the richest app reference. It includes onboarding, lobby, campaign, chat, picks, friends, events, create, search, notifications, invite, profile, settings, and home routes.

LayerPrototype examplesMigration value
TokensBB_TOKENS, stage definitions, card radius, accent alpha, texture layerSource for Kotlin palette, stage, spacing, and radius models.
AtomsAvatar, Pill, LiveDot, DayRing, IconBtn, BBWordmarkFirst shared Compose component set.
MoleculesAvatarStack, StageBadge, StageTrack, TrustRing, UserChipReusable product UI vocabulary for campaigns, chat, events, and profile.
LayoutsPhone, AppTopBar, TabBarScreen scaffolding and navigation chrome references.
Product widgetsCampaignCard, BudbotCampaignPanel, EventCard, chat panels, inbox rowsScreen molecules and organisms for the real app.

modules/design

The current design module is being replaced by a scoped atomic design surface. Public screen code should use Theme.Components { Card(...) }, Text, Chip, SearchBar, Event, and TopBar. Legacy wrapper names are not part of the migration path.

modules/app

The real app is graph-driven and should remain that way. The root route is /, onboarding is /onboarding, home is /home, top-level tabs include Chat, Campaign, Discover, and optional Events, with overflow graphs for Friends, Profile, and Dev.

AreaCurrent filesPrototype target
Login/startui/StartScreen.ktentry.jsx, onboarding.jsx
Onboardingui/onboarding/*onboarding.jsx, flow-bridges.jsx
Chat inboxui/home/chats/ChatsScreen.kt, ChatViews.ktchats-inbox.jsx
Chat threadChatScreen.kt, ChatViews.kt, views/MessageView.ktchat.jsx, prompt/member moments
CampaignsCampaignScreen.kt, CampaignComponents.ktcampaigns.jsx, campaign-detail.jsx
DiscoverDiscoverScreen.ktdiscover.jsx, create.jsx
Eventsui/home/events/*events.jsx
Friends/profileFriendsScreen.kt, ProfileScreen.kt, profile detail screenspicks.jsx, profile.jsx, member rows

Discrepancies

DiscrepancyResolution
appWeb desktop theme differs from older prototype defaults such as deep red, Instrument Serif, and Inter.Make appWeb values canonical: Fraunces, Space Grotesk, cool stage language, radius scale 1.5, accent intensity 1.3, and the newer palette values.
appWeb only exercises a subset of prototype routes.Desktop tests cover website behavior; mobile prototype tests cover app-like route behavior.
targets/appWeb/frontend was a separate legacy frontend.It has been scanned and deleted. Do not rebuild from that stack.
modules/design is Material-ish and gradient-heavy.Replace the internals with warm editorial/product tokens and scoped atomic components. Do not preserve legacy wrapper APIs.
The real Compose app has behavior not present in the prototype.Use the prototype for look and interaction feel; keep real data and behavior in app code.
React/Kotlin portability is uneven.Put portable data and Compose components in commonMain, React DOM wrappers in jsMain, and keep WebGL/iframe host details in TypeScript until worth porting.

Testing Plan

Add richer tests under tests/bestbudsWeb before extraction and migration.

Desktop website

Cover landing render, wordmark, headline, waitlist form, sticky prototype, palette persistence, story section navigation, iframe route sync, waitlist success/failure mocks, desktop width sanity, and console/page error guards.

Mobile prototype

Use an iPhone-sized Playwright project around 390x844. Cover onboarding, campaigns, campaign detail, chats, chat, picks, friends, events, event detail, create event, utility routes, and palette postMessage sync.

Mobile website

Keep it light: hero copy, inline preview render, palette control behavior, lazy-loaded final prototype iframe, and no console/page errors.

Recommended test shape

tests/bestbudsWeb/playwright/
  landing-desktop.spec.ts
  prototype-mobile.spec.ts
  landing-mobile-smoke.spec.ts
  helpers/
    consoleErrors.ts
    localStorage.ts
    waitlistMocks.ts
    iframe.ts

Commands

npm run test:bestbudsWeb:playwright
npm run test:bestbudsWeb:maestro
npm run test:bestbudsWeb
Prefer semantic text plus existing data-route and data-local-action selectors. Add stable data-testid attributes in prototype source only where tests become brittle.

Atomic Design Extraction

Token layer

Create canonical token files in modules/design/src/commonMain/kotlin/ai/bestbuds/design/tokens.

BestBudsPalette.kt
BestBudsTypography.kt
BestBudsSpacing.kt
BestBudsRadii.kt
BestBudsStage.kt
BestBudsElevation.kt

Suggested model: BestBudsPaletteName, BestBudsPalette, BestBudsTokens, BestBudsStage, BestBudsStageStyle, and BestBudsThemeState. Include helpers for color alpha, readable-on color, card radius, and stage accent selection.

Current implementation status: BestBudsPalette, BestBudsTokens, ColorTokens, CampaignStage, and StageTokens now live in modules/design. The stage model covers Forming, Matched, Milestone, BestBuds, and Wrapped, with app screens deriving stage from campaign metadata until the backend exposes a first-class stage field.

Scoped component API

Use a CompositionLocal-backed component set rather than public BB* component names. Screens should enter the design scope and write product-generic component calls such as Card, Text, Chip, SearchBar, Event, and TopBar. The current bridge is Theme.Components { ... }, backed by LocalBestBudsComponentSet and BestBudsComponentSet.

themed {
  Components {
    Card {
      Text("Coffee crawl")
      Chip("Matched")
      PrimaryButton("Open Chat")
    }
  }
}

Do not keep previous public component APIs as migration adapters. New atoms, molecules, and templates can use BestBuds-prefixed file/class names when useful, but their screen-facing component functions should be scoped and unprefixed.

LevelComponents
AtomsWordmark, Text, IconButton, Button, Pill, LiveDot, Avatar, DayRing, TrustRing, StageBadge, SearchField, TextField, Card, Divider, ReactionChip.
MoleculesTopBar, TabBar, AvatarStack, StageTrack, CampaignCard, CampaignDetailHeader, BudbotPanel, ChatRow, ChatBubble, MessageInput, ReplyPreview, Event, EventInvite, MemberRow, ProfileHeader, FilterRow, SettingsSection.
TemplatesScreenScaffold, ScrollableScreen, HomeShell, DetailScaffold, FormScaffold, EmptyState, LoadingState, ErrorState.
Do not move app repositories, route bindings, graph nodes, analytics calls, or platform auth into modules/design.
Current component status: campaign cards now consume scoped Card, Text, Chip, PrimaryButton, JoinButton, StageBadge, StageTrack, and TrustRing. Internal implementation names may remain descriptive, but screen code should stay inside Components { ... } and avoid preserving old public APIs.

React And Karakum

Use commonMain for portable design data and Compose components. Use jsMain only for React-specific wrappers.

modules/design/src/commonMain/kotlin/ai/bestbuds/design/
  tokens/
  theme/
  components/atoms/
  components/molecules/
  components/templates/

modules/design/src/jsMain/kotlin/ai/bestbuds/design/react/
  BestBudsReactTokens.kt
  ReactAtoms.kt
  ReactPrototypeHost.kt

modules/design/ts/
  package.json
  tsconfig.json
  karakum.config.json
  index.ts
  karakum.ts
  src/

Follow the reaktor-graph convention: TypeScript package in ts/, build: tsc -b, postbuild: karakum --config karakum.config.json, generated externals into ts/import, and Dependeasy web {} includes ts/import in jsMain.

Keep TypeScript for SurfaceBackground.tsx, exact prototype iframe hosting during migration, and DOM-only route/palette sync logic. Do not block Compose app restyling on perfect React/Kotlin parity.

Migration Sequence

  1. Baseline tests: expand Playwright desktop and mobile coverage, add fixtures for console errors, localStorage reset, iframe access, and waitlist mocks.
  2. Token-first design rewrite: replace current design token base with appWeb/prototype tokens, remove legacy wrappers, and document native font fallback strategy.
  3. Shared primitives: build wordmark, avatar, avatar stack, pills, buttons, icon buttons, cards, stage badges/tracks, day/trust rings, top bar, tab bar, event cards, and campaign cards.
  4. React/web pieces: move reusable appWeb pieces into modules/design/jsMain and modules/design/ts where useful, including palette serialization and prototype host wrappers.
  5. Real app screens: restyle StartScreen, onboarding, campaigns, discover, chats, chat, events, friends, profile, and dev in that order.
  6. Clean up: remove old gradient tokens, delete unused duplicate UI, update READMEs, and refresh generated JS only intentionally.

Screen Notes

Screen areaKeepChange
Start and onboardingApple/Google login, impersonated test users, pending login resume, auth status/errors.Prototype-style welcome, wordmark, warm card, clear auth actions, avatar/chip impersonation, and onboarding controls.
Campaigns and discoverSocialRepository calls, analytics events, route shape.Stage-aware cards, StageBadge, StageTrack, DayRing, AvatarStack, and prototype filters/cards.
ChatReverse LazyColumn, pagination, websocket behavior, reply drag, action sheets, reactions, copy/forward, retry/discard, stickers, image fullscreen, mentions, BotUser, typing/presence subtitle.Warm card/ink/cream bubbles, prototype top bar language, rounded composer, Budbot panel message styling, and pill reaction chips.
EventsSearch analytics, save/unsave analytics, create-event form state, private/public tabs.Prototype event cards, RSVP/invite controls, create event segmented options, warm save CTA, and FAB styling.
Profile and friendsProfile repository calls, logout behavior, friend/group navigation, age calculation, hobbies parsing.Profile header, avatar, stat chips, interest pills, member rows, message CTA, and prototype text field/card style.

Acceptance And Risks

Definition of done: the migration is finished only when every BestBuds app surface has moved to the new scoped UI and the migrated app is validated by the maintained Maestro suites. The current stage/campaign work is an implementation slice, not migration completion.

Acceptance criteria

  • appWeb desktop tests and mobile prototype tests pass.
  • modules/design owns canonical BestBuds tokens and shared components.
  • appWeb no longer defines independent duplicate palette constants; any remaining web-only constants must be deleted or moved into the shared token layer.
  • All real app screens use modules/design components for core UI structure and no screen depends on previous public component APIs.
  • Graph routes, ports, repositories, analytics, auth, and chat behavior remain unchanged unless explicitly scoped.
  • Android, iOS, and Desktop targets remain buildable.
  • BestBuds Maestro validation passes with the migrated UI in place: npm run maestro:android, npm run maestro:ios, and npm run test:bestbudsWeb:maestro.

Risks

  • Native font strategy for Fraunces and Space Grotesk.
  • Chat gesture, reverse list, modal sheet, and IME regressions during restyle.
  • Brittle prototype selectors unless stable test IDs are added sparingly.
  • WebGL background should stay TypeScript until Kotlin/JS porting has clear value.
  • Dirty generated artifacts should not be refreshed accidentally.
  • Legacy targets/appWeb/frontend should not distract the migration.

Immediate Next Steps

  1. Finish replacing direct Material/profile helper usage in ProfileScreen, FriendProfileScreen, GroupProfileScreen, DevScreen, event scaffolds, chat views, and remaining home shells.
  2. Move generic loading, profile placeholder, editable field, info row, avatar, and empty/error states behind the scoped component API instead of public helper functions.
  3. Keep feature behavior stable while changing presentation: auth, graph routes, chat actions, analytics, work tasks, and profile navigation should keep the same Maestro-observable semantics.
  4. Run the final validation gate after app migration: npm run maestro:android, npm run maestro:ios, npm run test:bestbudsWeb, plus target builds for Android, Darwin, Desktop, and app web.