- Fix chat components barrel to properly export all component modules
- Remove interceptor exports from API services barrel
- Regenerate store barrel files (auth, chat, sidebar, user) using barrelsby
Add a new /subscription route showing three VIP membership plans (Monthly,
Quarterly, Annual) with a pink→peach banner, per-plan gradient price bars,
a benefits card, a mock activate CTA, and an agreement checkbox.
- New reusable <Checkbox /> in src/app/_components/core for the legal
agreement toggle
- Hardcoded SUBSCRIPTION_PLANS constant in src/data/constants
- New SubscriptionScreen composed of 7 colocated components (back link,
user row, banner, plan card, benefits card, CTA button) with CSS
Modules matching the existing design-token system
- Route registered as protected and reached from /sidebar "Membership"
- Mock CTA: window.alert + router.push(/chat) — no payment calls
Co-Authored-By: Claude <noreply@anthropic.com>
- Remove unused `quotaWarningThreshold` and `warningThreshold` getter from `GuestChatQuota` DTO
- Apply get-or-init pattern in `ChatStorage.getGuestDailyChatQuota` and `getGuestTotalQuota`: when no existing value, initialize with DTO defaults (`threshold` = max per day, `totalQuotaDefault`) and return the seeded data
- Fall back to original `null` result if initialization write fails
- Consolidate logging strategy: drop per-actor trace logs in `chat-machine.ts`, keep business-decision logs in 3 assign actions, move all actor ENTRY/API/DONE chains to `chat-machine.actors.ts` and helper load logs to `chat-machine.helpers.ts`
Update implementation_plan.md with a detailed refactor plan that splits
`chatInitActor` into two independent actors (`loadQuotaActor` +
`loadHistoryActor`) and redesigns the history loading flow to follow
local → network → save semantics so the UI sees local data first,
then network data.
Key changes outlined in the plan:
- Add new events: `ChatQuotaLoaded`, `ChatHistoryLocalLoaded`,
`ChatHistoryNetworkLoaded`, `ChatHistorySyncDone`
- Remove dead-code `ChatInit` event
- Extend `ChatState` with `quotaLoaded` and `historyLoaded` flags
- Use an `always` barrier in `guestSession.initializing` and
`userSession.initializing` so both tasks must complete before
transitioning to `ready`
- Guest init runs `loadQuota` + `loadHistory` in parallel; non-guest
init runs `chatWebSocket` + `loadHistory` as independent tasks
Also adds `implementation_plan` to .gitignore.
Drop the QuotaDialog component invocation in chat-screen along with
its useState/useEffect wiring, and delete the component files. Update
JSDoc in chat-screen and routes to reflect the removed consumer.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Split `chatInitActor` into `loadQuotaActor` (guest quota fetch) and `loadHistoryActor` (local → network → save sync), and add `quotaLoaded` / `historyLoaded` state flags so the UI can display loading status during the new local-first history hydration flow. Also drop the now-unused `ChatInit` event and pipe Next.js stdout/stderr to a persistent log file in the post-receive hook for easier troubleshooting.
Comment out `src/router/index.ts` and `src/router/proxy.ts` to temporarily
disable the Next.js 16 proxy (auth-driven redirects) and router re-exports.
This effectively turns off the centralized route guard logic and stops the
proxy from intercepting requests until further iteration.
Move the file-local Helpers block (readGuestId) to auth-helpers.ts and the
Actors block (authRepo + 7 fromPromise actors) to auth-actors.ts. Public API
(authMachine, AuthEvent, AuthState, initialState, AuthMachine) is unchanged;
auth-context.tsx and the barrel index.ts need no edits.
Move the NextAuth v4 configuration from the route handler
(src/app/api/auth/[...nextauth]/route.ts) into a dedicated module
(src/lib/auth/auth.ts) to establish a single source of truth. The
route file now simply re-exports the handler from the shared
module, keeping provider setup, JWT/session callbacks, and
environment variable references in one reusable location.
- Inline NextAuth v4 handler directly in `[...nextauth]/route.ts`, removing
the `@/lib/auth/nextauth` abstraction layer
- Add Google/Facebook providers with JWT/session callbacks that expose
`idToken` and `accessToken` on the session for backend exchange
- Refactor `AuthPlatform` from constructor-based to static methods
(`googleSignIn()` / `facebookSignIn()`)
- Update `auth-machine.ts` and layout comment reference to match new structure
- Align with original Dart `nextauth-helpers.{googleLogin, facebookLogin}()`
naming and keep persistence concerns (unstorage, backend, custom cookies)
out of scope for this iteration
Add console.log instrumentation across the guest login pipeline (auth-machine, authRepository, authApi) to trace request lifecycle and surface Zod parsing failures with detailed issue info. Useful for diagnosing lastMessageAt schema mismatches.
- Move AiDisclosure and EmptyState logic into a new AiDisclosureBanner component
- Remove isGuest prop from ChatArea as it's no longer needed there
- Update styling with explicit color values for better visibility
- Remove redundant `loadingMoreHistory` and `ready` states from chat machine, consolidating history loading flow
- Add `align-self: flex-start` to chat row container for proper alignment
- Clean up commented-out margin rules in text bubble styles
- Update deploy script GIT_REMOTE from "server" to "test"
- Split chat state machine actors (chatInit, sendMessageHttp, loadMoreHistory, chatWebSocket) into a dedicated module
- Add comprehensive console logging across the chat state machine for full trace debugging
- Comment out margin on text bubble CSS for layout adjustment
- Add debug logging to chat input bar send handler
- Clean up redundant comments in auth-screen component
- Remove ChatScreenVisible and ChatScreenInvisible events from chat state machine
- Remove legacy ChatInit event handler
- Migrate state transitions to use absolute references (#chat.guestSession, #chat.userSession, #chat.idle)
- Adjust legal text wording for Cozsweet privacy agreement
Next.js Image scans only inline style for 'auto' to determine whether
sizing is fully delegated to CSS. The .logo class already sets
height: var(--auth-logo-height) and width: auto, but the inline auto
hint is required to suppress the width/height-modified warning.
Applies to both auth-facebook-panel and auth-email-panel where the same
login logo is rendered.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Update auth-legal-text copy to "I agree to the Cozsweet Privacy
Agreement and Terms of User", keeping the two external links.
- Center the Facebook icon and "Login with Facebook" label as a group
inside the main Facebook button (change .facebookLabel flex).
- Apply the same centering to the shared AuthSocialButton .label rule
so the Email and Facebook entries in the "Other Sign-in Options"
bottom sheet also render icon+text centered.
Co-Authored-By: Claude <noreply@anthropic.com>
- chat-screen no longer manages WebSocket directly; it now dispatches three
auth lifecycle events (ChatGuestLogin, ChatNonGuestLogin, ChatLogout)
derived from auth.loginStatus
- chat-machine internally owns the WebSocket long-lived actor via
fromCallback, completing the previously deferred migration scope
- removed ChatWebSocket import, getWsToken helper, and direct WS
effect from chat-screen; renamed dispatchInitialLoad to
dispatchAuthLifecycle to reflect the new responsibility
- decouples auth from chat machine via event-driven boundary: machine
stays unaware of loginStatus, guest semantics live at the dispatch
layer (guest → skip WS, non-guest → connect with token)
The screen-lifecycle events were dead code: the transitions in chat-machine
(idle <-> ready) had no caller behavior tied to them, and the dispatches
in chat-screen.tsx were the only senders. Drop the union members, both
state transitions, and the mount-effect dispatches.
The idle state remains declared as initial but is no longer reachable
at runtime; can be refactored in a follow-up.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Remove ChatAuthStatusChanged dispatch from auth login flow; chat screen now subscribes directly to auth state machine (loginStatus) to derive isGuest and drive WS lifecycle
- Gate quota-exceeded and warning dialogs to guests only (non-guests have no message limit)
- Dispatch ChatLoadMoreHistory for non-guest initial load vs ChatInit for guests
- Fix AppConstants import path from @/core/constants/app_constants to @/core/app_constants
- Add defensive isGuest checks in quota effects to prevent non-guest quota triggers
TextBubble now fills the available half-row width instead of being
capped at 75%. Add 16px margin on the avatar-side edge (margin-left
for AI, margin-right for user) so short messages still feel airy
and long messages are no longer artificially clipped.
Co-Authored-By: Claude <noreply@anthropic.com>
Move breakpoints, fonts, and app_constants into the core directory for better organization:
- Move src/lib/breakpoints.ts to src/core/breakpoints.ts
- Move src/lib/fonts.ts to src/core/fonts.ts
- Move src/core/constants/app_constants.ts to src/core/app_constants.ts and clean up outdated comments
Skip /auth/guest round-trip on splash Skip when localStorage already
holds a valid guestToken. Avoids redundant API call (and the
fingerprintjs deviceId probe) every time the user reopens splash.
Trade-off: a server-revoked token still resolves "guest" until the
first protected API call returns 401, which the HTTP layer handles.
Co-Authored-By: Claude <noreply@anthropic.com>
- Splash Skip button now dispatches `AuthGuestLoginSubmitted` instead of
direct routing, keeping guest auth under the state machine
- Update PWA install dialog copy ("Add to Home Screen") and drop favicon
entry from manifest icons
- Add debug logging and routing sequence docs to splash-button
Integrate the Logger into `Result.wrap` so that caught exceptions are
recorded with stack trace, error type, and a `component: "Result"`
tag before being wrapped into a `Result<T>`. Errors are first
normalized via `toError` to preserve `.stack`, `.code`, and `.status`
fields, then logged through the standard pipeline (dev console in
development, JSON pipeline in production). Callers continue to receive
a `Result<T>` — re-throwing remains opt-in via `Result.unwrap`.
Add pino v10.3.1 to project dependencies for structured logging support, along with its transitive dependencies (pino-abstract-transport, pino-std-serializers, quick-format-unescaped, atomic-sleep, etc.).
Add align-self: flex-end to .bubbleRowUser so the user message row
sizes to its content and pins to the right edge of the chat area.
Combined with the existing flex-end cross-axis alignment, this places
the user avatar at the right edge with the bubble to its left,
producing a proper left-to-right AI / right-to-left user mirror.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Match the Dart lib/ui/sidebar/sidebar_screen.dart + profile_view.dart
exactly:
- White inner shell with 24px padding
- Back button row (arrow icon + "Back" text, no "Profile" header)
- Single "Other" section with one "Log out" row
- Drop profile card, Account/Data/Session sections, and Sign-in CTA
Match Flutter row visuals in the shared SettingsSection:
- Gray (#f5f5f5) rounded row pill on a white card
- 20px chevron, 1px rgba(61,49,74,0.5) divider
- Destructive color #ff6b6b, 14px/600 black section title
Add tokens: --color-settings-card-background, --color-settings-row-background,
--color-settings-divider, --color-chevron-icon, --color-destructive.
Wire the BlocConsumer listener equivalent: on currentUser transitioning to
null, dispatch ChatAuthStatusChanged + AuthReset and router.replace("/chat").
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add AuthStatusChecker mounted in RootProviders to dispatch AuthStatusCheckSubmitted on mount. The new checkAuthStatusActor retrieves the device id, checks for an existing login or guest token, and falls back to a guest login API call when neither is present. Wires the new event/actor through the auth machine to enable automatic session restoration and guest-mode bootstrap.
Change flex-direction from column to row on .bubbleRowAi and
.bubbleRowUser so the avatar and message content render side-by-side
as the JSX and JSDoc already intend.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Wire the Google/Facebook OAuth callback flow end-to-end so the provider's id_token (Google) and access_token (Facebook) captured by NextAuth are forwarded to the backend in exchange for business tokens:
- Extend the NextAuth config with jwt/session callbacks that surface `account.id_token` / `account.access_token` to the client during first sign-in
- Add an `OAuthSessionSync` bridge mounted inside `RootProviders` that listens to `useSession()` and dispatches new `AuthGoogleSyncSubmitted` / `AuthFacebookSyncSubmitted` events
- Add corresponding actors in the auth XState machine that call `authRepository.googleLogin` / `facebookLogin`, persisting the backend's `LoginResponse` through the existing repository path
This keeps all authentication orchestrated by the auth state machine while preserving NextAuth's OAuth redirect UX.
Update the PWA install dialog styling and content to align with the
original Dart design, including a white background with large 40px
radius, 86x86 PNG icon, gradient primary button, and dynamic app title
sourced from AppConstants.
Move the `SidebarPage` and `BottomNavItem` enum definitions from
`sidebar-machine.ts` to `sidebar-state.ts` to avoid a circular
dependency between the two modules. Since both enums are tightly
coupled to the state shape (they define the value sets of
`currentPage` and `selectedBottomNavItem`), they now live alongside
the state itself.
- Move enum declarations and types from `sidebar-machine.ts` to
`sidebar-state.ts`
- Update `sidebar-events.ts` import path to reference `sidebar-state`
- Keep `sidebar-machine.ts` re-exporting `SidebarState` and
`initialState` to preserve its public API
Move new AuthPlatform(provider).signIn() out of UI components and into
the auth state machine. UI now dispatches AuthGoogle/FacebookLoginSubmitted
events; a new oauthSignIn actor inside the machine calls next-auth/react's
signIn(provider). Errors and the OAuth redirect window are exposed via
the existing state.isLoading / state.errorMessage surface, removing the
local busy / error state in auth-facebook-panel.
Co-Authored-By: Claude <noreply@anthropic.com>
- Move state management from `src/contexts` to `src/stores` (zustand-based)
- Update barrelsby config to include new stores directory
- Add bottom-sheet and auth-background components
- Auto-open browser on dev server ready in VS Code launch config
- Refresh generated barrel index files
Replace the separate FacebookLogin and GoogleLogin classes with a single
AuthPlatform class that takes a provider name ("facebook" | "google") as a
constructor argument. This consolidates duplicate OAuth sign-in logic behind
one entry point while preserving the existing NextAuth flow.
- Add new src/lib/auth/auth_platform.ts exporting AuthPlatform and
AuthProvider type
- Update auth-facebook-panel.tsx and splash-button.tsx to use the new API
- Rename initialContext → initialState in the auth machine for consistency
- Update inline docs and comments to reference AuthPlatform
No behavioral change for end users; both providers still route through
NextAuth's signIn() with the same callbacks and cookies.