Skip to content

[pro-web] feat: add image generation with gpt-image-1 and Nano Banana (Gemini) in Media Workspace tab#584

Merged
AndlerRL merged 22 commits intodevelopfrom
feat/media-tab-v1
Nov 21, 2025
Merged

[pro-web] feat: add image generation with gpt-image-1 and Nano Banana (Gemini) in Media Workspace tab#584
AndlerRL merged 22 commits intodevelopfrom
feat/media-tab-v1

Conversation

@derianrddev
Copy link
Contributor

@derianrddev derianrddev commented Nov 14, 2025

📖 Description

This pull request introduces a comprehensive set of improvements to the Media Tab functionality in the workspace, focusing on enhanced image generation, template selection, and context management. The changes add support for Gemini AI models in image generation, implement a new API route for fetching media templates, refactor the template and size selection UI for better usability and dark mode support, and integrate a new WorkspaceMediaProvider for media-specific state and actions. Additionally, the prompt form logic is updated to handle media generation workflows alongside chat.

✅ Changes Made

Media Tab & Image Generation Enhancements:

  • Added Gemini model support to the image generation API, enabling users to generate images using Google's Gemini models with proper prompt and image editing workflows. [1] [2] [3]
  • Implemented a new API route (apps/pro-web/app/api/media/templates/route.ts) to fetch available media templates from the filesystem, with error handling and Sentry logging.

UI/UX Improvements for Media Tab:

  • Refactored the Select Size and Select Template steps for the Media Tab wizard, improving layout, sticky headers, dark mode support, loading states, and template previews. [1] [2] [3] [4]
  • Updated the Media Tab wrapper and removed unused imports for cleaner code. [1] [2]

Context & Provider Integration:

  • Introduced and integrated WorkspaceMediaProvider into the application context, allowing media-specific actions and state to be accessed throughout the workspace. [1] [2] [3] [4]

Prompt Form Logic for Media Generation:

  • Updated the prompt form logic to handle media generation mode, including dynamic placeholders, media-specific prompt submission, and context-aware input handling. [1] [2] [3] [4] [5]

🖼️ Media (screenshots/videos)

https://www.loom.com/share/91794900acdb4aa9b3f27d68ab56fad5

Summary by Sourcery

Enable Google Gemini alongside OpenAI for image generation and editing in the Media Workspace; introduce a shared context for media state and prompt handling; refactor UI and workspace state for clearer feedback and tighter integration.

New Features:

  • Add support for Google Gemini (Nano Banana) models for image generation and edit workflows in the Media Tab API and UI
  • Introduce a WorkspaceMediaProvider context for sharing Media Tab state and handling prompt submissions across components

Enhancements:

  • Refactor MediaWorkspace UI to integrate image generation hook, display generated images, loading spinners, and error overlays
  • Automatically select appropriate model for new images (gpt-image-1) versus edits (gemini-2.5-flash-image) and unify activeTab state via workspace context
  • Integrate Media mode into the chat prompt form with context-aware placeholders and submission routing

Build:

  • Add @google/genai dependency for Google GenAI API support

Summary by Sourcery

Enable advanced image generation and editing in the Media Workspace by adding Google Gemini model support, sharing media state via a new context, and overhauling the UI and prompt flow for clearer feedback and tighter integration.

New Features:

  • Support Google Gemini (Nano Banana) models alongside OpenAI for new image generation and edit workflows.
  • Introduce WorkspaceMediaProvider context for sharing Media Tab state and prompt submission handlers across components.

Enhancements:

  • Refactor MediaWorkspace UI to leverage useImageGeneration hook and media context for model selection, prompt handling, and state management.
  • Enhance image generation feedback with loading spinners, error overlays, and integrated ImageDisplay component.
  • Integrate Media Tab mode into chat prompt form with context-aware placeholders and submission routing.
  • Unify activeTab state via workspace context and remove redundant local tab state.

Build:

  • Add @google/genai dependency for Google GenAI API support

Summary by CodeRabbit

Release Notes

  • New Features
    • Added Google Gemini image generation support alongside existing models.
    • Introduced media workspace with template selection and customizable frame sizes for image generation.
    • Added reference image support for editing and iterating on existing images.
    • Implemented version history tracking for generated images.
    • New sidebar navigation for templates, social media options, and brand kit management.

✏️ Tip: You can customize this high-level summary in your review settings.

@derianrddev derianrddev self-assigned this Nov 14, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 14, 2025

Walkthrough

This PR adds Google Gemini image generation support and introduces a new Media Workspace feature. It extends the image generation API to route Gemini models through a separate flow, updates provider composition to include WorkspaceMediaProvider, adds a complete media tab with template selection, frame sizing, reference images, and version history. The changes include new types for Google image models, helper utilities for template management, and multiple UI components for the media workspace.

Changes

Cohort / File(s) Summary
Gemini Image Generation Support
apps/pro-web/app/api/generate-images/route.ts, apps/pro-web/lib/hooks/use-image-generation.tsx, apps/pro-web/types/index.ts, apps/pro-web/package.json
Added Gemini/Google model support with new route branching for Gemini models, GoogleGenAI SDK integration, extended image generation hook to accept ImageModel union type and previousImageData for edit mode, introduced GoogleImageModel and ImageProviderType to support Google as a provider, added @google/genai dependency.
Provider & Context Integration
apps/pro-web/components/layout/providers.tsx, apps/pro-web/lib/hooks/use-workspace-media.tsx, apps/pro-web/lib/hooks/use-image-toggler.tsx
Wrapped WorkspaceChatProvider with new WorkspaceMediaProvider, added comprehensive media context hook managing image generation workflow, template/size selection, and UI state, added "use client" directive to image-toggler hook.
Prompt Form Media Integration
apps/pro-web/components/routes/chat/prompt-form/index.tsx
Replaced useWorkspaceChat with useWorkspaceMedia, added media mode detection via activeTab, introduced effectivePlaceholder for media-specific prompts, delegated media submission to handlePromptSubmit.
Workspace Content & Tab Menu
apps/pro-web/components/routes/workspace/workspace-content.tsx, apps/pro-web/components/routes/workspace/workspace-tab-menu.tsx
Added media actions (upload, media-sizes, media-library, media-version) to tab menu, integrated useWorkspaceMedia context, updated document menu structure with view-mode branching, replaced Gallery/Upload with Frame Sizes/Library/Version History for media tab.
Image Display & Generator UI
apps/pro-web/components/shared/image-display.tsx, apps/pro-web/components/shared/image-generator.tsx
Moved model info label from top-left to top-right in image display, replaced OpenAI-specific model typing with generic ImageModel, added provider field and Google model entry (gemini-2.5-flash-image), updated initial model selection, added Sparkles icon for Google models.
Media Workspace Core
apps/pro-web/components/routes/workspace/media-tab/media-workspace.tsx, apps/pro-web/components/routes/workspace/media-tab/media-tab-wrapper.tsx, apps/pro-web/components/routes/workspace/media-tab/index.ts
Introduced new MediaWorkspace component with template fetching, reference image management (4-slot limit), generated image and size/template reset logic, removed old media-workspace-ui and replaced with new streamlined implementation, updated import paths.
Media Canvas & Visualization
apps/pro-web/components/routes/workspace/media-tab/ui/canvas/media-canvas.tsx, apps/pro-web/components/routes/workspace/media-tab/ui/canvas/index.ts
Added MediaCanvas component rendering template/size selection UI, optional generated image display, loading/error overlays, and version history popup with navigation and version selection controls.
Media Sidebar & Reference Images
apps/pro-web/components/routes/workspace/media-tab/ui/sidebar/media-sidebar.tsx, apps/pro-web/components/routes/workspace/media-tab/ui/sidebar/index.ts, apps/pro-web/components/routes/workspace/media-tab/ui/reference-images/reference-images-panel.tsx, apps/pro-web/components/routes/workspace/media-tab/ui/reference-images/reference-upload-slot.tsx, apps/pro-web/components/routes/workspace/media-tab/ui/reference-images/index.ts
Added MediaSidebar with Templates/Social Media/Brand Kit buttons, ReferenceImagesPanel for 4-slot gallery management with add/remove operations, ReferenceUploadSlot with drag-and-drop and file validation (JPEG/PNG/WebP, 5MB limit).
Media Wizards & Steps
apps/pro-web/components/routes/workspace/media-tab/wizards/media-wizards.tsx, apps/pro-web/components/routes/workspace/media-tab/wizards/steps/select-size-step.tsx, apps/pro-web/components/routes/workspace/media-tab/wizards/steps/select-template-step.tsx, apps/pro-web/components/routes/workspace/media-tab/wizards/index.ts
Added MediaWizards orchestrating Size/Template/Library selection dialogs, SelectSizeStep with 2-column frame grid and aspect-based styling, SelectTemplateStep with loading/empty states and template cards with hover badges, auto-sizing logic via getFrameSizeFromTemplate.
Template API & Helpers
apps/pro-web/app/api/media/templates/route.ts, apps/pro-web/lib/helpers/workspace/media.ts
Introduced GET /api/media/templates route scanning public/templates and parsing filenames, added Template interface and utilities: imageUrlToBase64, parseTemplateFilename, filterTemplatesByFrame, filterTemplatesBySocialMedia, getUniqueSocialMedia, getUniqueFrames, getFrameSizeFromTemplate.
Wizard UI Refinement
apps/pro-web/components/ui/wizard/index.tsx
Made progress bar conditional rendering (only show when total steps > 1), removed pb-10 padding from DialogHeader.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant PromptForm as Prompt Form
    participant MediaContext as WorkspaceMedia<br/>Context
    participant ImageGen as useImageGeneration
    participant GeminiAPI as Google Gemini<br/>API
    participant OpenAI as OpenAI API
    
    User->>PromptForm: Submit prompt in media mode
    PromptForm->>MediaContext: handlePromptSubmit(prompt)
    MediaContext->>MediaContext: Validate template & size
    MediaContext->>MediaContext: Convert template to base64
    MediaContext->>ImageGen: generateImage(prompt,<br/>modelId, previousImage)
    alt Gemini Model (gemini-*)
        ImageGen->>GeminiAPI: Create content with<br/>prompt + optional image
        GeminiAPI-->>ImageGen: Generated image
    else Other Models
        ImageGen->>OpenAI: Generate image
        OpenAI-->>ImageGen: Image response
    end
    ImageGen-->>MediaContext: GeneratedImage
    MediaContext->>MediaContext: Update state &<br/>display canvas
    User->>User: View generated image
Loading
sequenceDiagram
    actor User
    participant Canvas as MediaCanvas
    participant Wizards as MediaWizards
    participant TemplateAPI as Templates API
    participant Context as WorkspaceMedia<br/>Context
    
    User->>Canvas: Click template area
    Canvas->>Wizards: Open template wizard
    Wizards->>TemplateAPI: GET /api/media/templates
    TemplateAPI-->>Wizards: Template list
    Wizards->>Wizards: Display templates
    User->>Wizards: Select template
    Wizards->>Context: onTemplateSelect(template)
    Context->>Context: Auto-determine size<br/>from template
    Context->>Wizards: Close dialog
    Wizards-->>Canvas: Return to canvas
    Canvas->>Canvas: Render template<br/>with new size
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Areas requiring extra attention:

  • Gemini API integration (apps/pro-web/app/api/generate-images/route.ts): Verify model detection logic, error handling for missing image data, and proper content part construction with optional previous images
  • WorkspaceMediaProvider state management (apps/pro-web/lib/hooks/use-workspace-media.tsx): Review state shape, action flows (especially handlePromptSubmit logic with base64 conversion), and model selection strategy (gemini-2.5-flash-image vs gpt-image-1)
  • Template parsing and API (apps/pro-web/app/api/media/templates/route.ts, apps/pro-web/lib/helpers/workspace/media.ts): Verify filename parsing logic, error handling/Sentry logging, and mapping logic between template frames and frame sizes
  • Provider nesting (apps/pro-web/components/layout/providers.tsx): Confirm correct ordering and that WorkspaceMediaProvider doesn't conflict with existing providers
  • Media wizard orchestration (apps/pro-web/components/routes/workspace/media-tab/wizards/media-wizards.tsx): Verify three-dialog coordination and callback chains, especially auto-sizing logic after template selection

Possibly related PRs

Suggested reviewers

  • AndlerRL

🐰 Whispers of templates and frames so fine,
Gemini models in a line,
Media workspace, crafted with care,
Images flowing through the air!
A studio born, where visions align,
✨ Let creation begin to shine! 🎨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main changes: adding image generation support with multiple AI models (gpt-image-1 and Gemini) in the Media Workspace tab, which aligns perfectly with the PR's comprehensive media generation functionality.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/media-tab-v1

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sourcery-ai
Copy link

sourcery-ai bot commented Nov 14, 2025

Reviewer's Guide

This PR extends the Media Workspace tab to support Google Gemini alongside OpenAI for image generation and editing, introduces a shared WorkspaceMediaProvider context to centralize Media Tab state and actions, and refactors hooks and UI components to streamline prompt handling, loading/error feedback, and workspace integration.

Sequence diagram for image generation with Gemini and OpenAI models

sequenceDiagram
    participant U as actor User
    participant MW as MediaWorkspace (UI)
    participant WM as WorkspaceMediaProvider
    participant IG as useImageGeneration (hook)
    participant API as generate-images API
    participant G as Google GenAI
    participant O as OpenAI

    U->>MW: Submit image prompt
    MW->>WM: handlePromptSubmit(prompt)
    WM->>IG: generateImage(prompt, modelId, previousImage?)
    IG->>API: POST /api/generate-images {prompt, modelId, previousImage, editMode}
    alt modelId startsWith 'gemini-'
        API->>G: googleAI.models.generateContent({model, contents})
        G-->>API: Image response (base64)
    else modelId is 'gpt-image-1'
        API->>O: openai.images.generate({prompt, ...})
        O-->>API: Image response (base64)
    end
    API-->>IG: {image: base64, warnings: []}
    IG-->>WM: Update generatedImage state
    WM-->>MW: Update UI with image/loading/error
Loading

Class diagram for updated image generation types and context

classDiagram
    class WorkspaceMediaProvider {
        +registerMediaHandlers(handlers)
    }
    class WorkspaceMediaContextType {
        +selectedTemplate: id string, name string or null
        +selectedSize: id string, name string or null
        +generatedImage: GeneratedImage or null
        +isGeneratingImage: boolean
        +imageError: ImageError or null
        +selectedModel: ImageModel
        +handlePromptSubmit(prompt: string): Promise<void>
        +registerMediaHandlers(handlers)
    }
    class GeneratedImage {
        +id: string
        +prompt: string
        +base64: string
        +modelId: ImageModel
        +timestamp: number
        +provider: ImageProviderType
    }
    class GenerateImageRequest {
        +prompt: string
        +modelId: ImageModel
        +previousImage: string
        +editMode: boolean
    }
    class UseImageGenerationReturn {
        +generatedImage: GeneratedImage or null
        +isGeneratingImage: boolean
        +imageError: ImageError or null
        +isEditMode: boolean
        +generateImage(prompt: string, modelId: ImageModel, previousImageData?): Promise<void>
        +resetState(): void
        +addImageToChat(mode?): void
    }
    WorkspaceMediaProvider --> WorkspaceMediaContextType
    WorkspaceMediaContextType --> GeneratedImage
    UseImageGenerationReturn --> GeneratedImage
    UseImageGenerationReturn --> GenerateImageRequest
    GeneratedImage --> ImageProviderType
    GeneratedImage --> ImageModel
    GenerateImageRequest --> ImageModel
    WorkspaceMediaContextType --> ImageModel
Loading

File-Level Changes

Change Details Files
Extend backend image-generation route to support Google Gemini models
  • Added isGeminiModel helper to detect Gemini model IDs
  • Integrated @google/genai SDK and GoogleGenAI client for Gemini content generations
  • Handled inlineData parts for edit-mode image chaining
apps/pro-web/app/api/generate-images/route.ts
apps/pro-web/package.json
Update types and minor UI adjustments
  • Unified ImageModel and ImageProviderType to include Google models
  • Enhanced ImageGenerator with provider-specific icons
  • Repositioned model info label in ImageDisplay
  • Added @google/genai dependency
apps/pro-web/types/index.ts
apps/pro-web/components/shared/image-generator.tsx
apps/pro-web/components/shared/image-display.tsx
apps/pro-web/package.json
Enhance useImageGeneration hook for multi-provider and edit chaining
  • Accepted optional previousImageData to enable chained edits
  • Auto-detected provider from modelId and consolidated logging
  • Unified isEdit logic for both explicit edit mode and previousImageData
apps/pro-web/lib/hooks/use-image-generation.tsx
Introduce WorkspaceMediaProvider context for shared Media Tab state/actions
  • Created useWorkspaceMedia hook and WorkspaceMediaProvider
  • Exposed registerMediaHandlers API for dynamic handler registration
  • Wrapped AppProviders with WorkspaceMediaProvider
apps/pro-web/components/layout/providers.tsx
apps/pro-web/lib/hooks/use-workspace-media.tsx
Refactor MediaWorkspace UI to leverage context-driven handlers
  • Replaced local hooks with registerMediaHandlers from context
  • Automated model selection (gpt-image-1 vs gemini) based on edit mode
  • Implemented handlePromptSubmit with precondition checks and reset logic
  • Added dynamic Canvas layout with spinner and error overlays
apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
Integrate Media Tab mode into chat PromptForm
  • Routed prompt submissions to media handlers when activeTab is 'media'
  • Computed dynamic placeholder text for generation vs edit
apps/pro-web/components/routes/chat/prompt-form/index.tsx
Switch workspace activeTab state to context
  • Added activeTab and setActiveTab to WorkspaceProvider and types
  • Replaced local activeTab state in WorkspaceContent with context
apps/pro-web/lib/hooks/use-workspace.tsx
apps/pro-web/components/routes/workspace/workspace-content.tsx

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@vercel
Copy link

vercel bot commented Nov 14, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
masterbots Ready Ready Preview Comment Nov 20, 2025 9:09pm
masterbots-pro Ready Ready Preview Comment Nov 20, 2025 9:09pm

@derianrddev derianrddev marked this pull request as ready for review November 14, 2025 16:06
Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes - here's some feedback:

  • Consider refactoring MediaWorkspace into smaller components (e.g., Canvas, Sidebar, Controls) to improve readability and maintainability.
  • The model/provider selection logic is duplicated across UI, hooks, and API layers; centralize it in a shared utility or strategy module to avoid drift.
  • Extract the Gemini-specific image generation code from the API route into its own service or module so the POST handler remains concise and focused.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Consider refactoring MediaWorkspace into smaller components (e.g., Canvas, Sidebar, Controls) to improve readability and maintainability.
- The model/provider selection logic is duplicated across UI, hooks, and API layers; centralize it in a shared utility or strategy module to avoid drift.
- Extract the Gemini-specific image generation code from the API route into its own service or module so the POST handler remains concise and focused.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/pro-web/components/routes/chat/prompt-form/index.tsx (1)

269-283: Media submission handoff is sound but relies on a registered handler

Delegating submit to mediaTab.handlePromptSubmit when activeTab === 'media' is a clean separation from the chat flow, and clearing input before delegation is safe since you pass the previous value as an argument.

Note that if WorkspaceMediaProvider is mounted but no media component has called registerMediaHandlers yet, this will call the default no-op handlePromptSubmit, effectively discarding the prompt. If that scenario is possible, consider either surfacing a user-visible warning or guarding on a flag that indicates handlers are registered.

🧹 Nitpick comments (6)
apps/pro-web/app/api/generate-images/route.ts (1)

114-124: Consider additional error handling for response parsing.

The response parsing assumes a specific structure from the Google GenAI API. While optional chaining provides some safety, consider adding validation for unexpected response formats to provide better error messages for debugging.

Example enhancement:

 if (response.candidates && response.candidates.length > 0) {
   const candidate = response.candidates[0]
   if (candidate.content?.parts) {
     for (const part of candidate.content.parts) {
       if (part.inlineData) {
         imageBase64 = part.inlineData.data
         break
       }
     }
   }
+} else {
+  console.warn('Unexpected Gemini response structure:', JSON.stringify(response))
 }
apps/pro-web/lib/hooks/use-workspace.tsx (1)

34-35: Workspace tab state integration is consistent with existing context design

  • Importing WorkspaceTabType and adding activeTab/setActiveTab to WorkspaceContextType matches the union type from thread.types and keeps the API explicit.
  • Initializing activeTab with 'documents' is valid for the declared union and aligns with existing workspace defaults.
  • Exposing setActiveTab via stableSetters and wiring activeTab into contextValue (and its dependency array) is correct; omitting setActiveTab from the deps is fine since React state setters are stable across renders (based on learnings).

If you later want tab choice to survive reloads, you can piggyback on the existing persistence mechanisms to store activeTab, but that’s optional.

Also applies to: 66-71, 140-141, 742-759, 775-802

apps/pro-web/lib/hooks/use-workspace-media.tsx (1)

1-84: WorkspaceMedia context API is well-structured; consider extracting a shared handlers type

The provider/context pattern here is solid: you centralize media state/handlers, provide a safe default handler, and enforce provider usage via the throwing useWorkspaceMedia hook.

To reduce duplication and keep the contract in sync, you might want to extract a WorkspaceMediaHandlers interface/type for the handler/state bundle and reuse it for:

  • WorkspaceMediaContextType fields
  • The internal handlers state
  • The registerMediaHandlers parameter

This keeps future additions to the media surface area less error‑prone.

apps/pro-web/lib/hooks/use-image-generation.tsx (1)

3-10: Provider-aware image generation and edit chaining are implemented correctly

  • Extending the signature to (prompt, modelId: ImageModel, previousImageData?: GeneratedImage) maintains backward compatibility while enabling edit chaining.
  • Provider inference via a gemini- prefix is reasonable for the current model set and is used consistently both for logging and the GeneratedImage.provider field.
  • The edit path correctly gates previousImage/editMode on isEdit || previousImageData, and uses the prior GeneratedImage’s base64 payload.
  • The useCallback dependency array includes isEditMode and previousImage, so you won’t get stale edit state.

If you expect more non‑Gemini Google image models in the future, consider centralizing model→provider mapping (e.g., a lookup table keyed by ImageModel) instead of relying solely on a string prefix.

Also applies to: 48-57, 67-75, 77-85, 87-89, 112-124

apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx (2)

47-62: Image generation hook integration and basic model selection are coherent

Reusing useImageGeneration here and computing a selectedModel for display/context based on isEditMode is a reasonable split between “generation engine” and workspace UI. The ImageModel typing keeps the model IDs aligned with your central types.

Given that the actual model chosen for generation is decided inside handlePromptSubmit, ensure selectedModel stays in sync with that choice so any observers of the media context don’t show stale provider/model info (see next comment).

Also applies to: 59-61


404-465: Reference image sidebar UX is coherent; inline handlers are fine but could be extracted

The right sidebar effectively manages up to four reference slots, supports opening the library dialog when empty, and provides an inline remove button with proper event stopping.

You do introduce several new inline arrow handlers (onClick={() => setDialogStep('library')}, onClick={() => handleCategorySelect(cat)}, etc.). Given the existing codebase already uses this pattern heavily, it’s acceptable, but if you find this sidebar becoming a hot render path, consider extracting these handlers into named functions to match your “no inline handlers” guideline.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 78ec016 and 5868095.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (13)
  • apps/pro-web/app/api/generate-images/route.ts (3 hunks)
  • apps/pro-web/components/layout/providers.tsx (2 hunks)
  • apps/pro-web/components/routes/chat/prompt-form/index.tsx (4 hunks)
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx (8 hunks)
  • apps/pro-web/components/routes/workspace/workspace-content.tsx (2 hunks)
  • apps/pro-web/components/shared/image-display.tsx (1 hunks)
  • apps/pro-web/components/shared/image-generator.tsx (3 hunks)
  • apps/pro-web/lib/hooks/use-image-generation.tsx (5 hunks)
  • apps/pro-web/lib/hooks/use-image-toggler.tsx (1 hunks)
  • apps/pro-web/lib/hooks/use-workspace-media.tsx (1 hunks)
  • apps/pro-web/lib/hooks/use-workspace.tsx (6 hunks)
  • apps/pro-web/package.json (1 hunks)
  • apps/pro-web/types/index.ts (3 hunks)
🧰 Additional context used
📓 Path-based instructions (14)
apps/{web,pro-web}/components/shared/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Place reusable UI under components/shared/

Place reusable UI elements under components/shared/

Files:

  • apps/pro-web/components/shared/image-generator.tsx
  • apps/pro-web/components/shared/image-display.tsx
apps/{web,pro-web}/**/*.tsx

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

apps/{web,pro-web}/**/*.tsx: Declare React components with the function keyword
Name React components using PascalCase
Order component files: imports → constants → component → styled components → types/interfaces
Use functional components and hooks; type props with a TypeScript interface
Use regular function references (not inline arrows) for React event handlers to avoid extra re-renders

apps/{web,pro-web}/**/*.tsx: Use regular function references for event handlers instead of inline arrow functions in JSX
Declare React components with the function keyword (function ComponentName() {})
Use PascalCase for React component names
Order React component files: imports, constants, component, styled components, types/interfaces
Style components with Tailwind CSS utility classes

Files:

  • apps/pro-web/components/shared/image-generator.tsx
  • apps/pro-web/lib/hooks/use-workspace.tsx
  • apps/pro-web/components/routes/workspace/workspace-content.tsx
  • apps/pro-web/lib/hooks/use-workspace-media.tsx
  • apps/pro-web/lib/hooks/use-image-toggler.tsx
  • apps/pro-web/components/layout/providers.tsx
  • apps/pro-web/components/shared/image-display.tsx
  • apps/pro-web/components/routes/chat/prompt-form/index.tsx
  • apps/pro-web/lib/hooks/use-image-generation.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Avoid default exports; prefer named exports
Use meaningful variable names; prefix booleans with is/has/does/should
Use interface for objects/classes; type for unions/tuples/aliases; enum for fixed sets; const for literals
Avoid any; prefer specific types
Leverage type inference where clear; annotate function params and return types
Prefer type assertions with 'as' over angle-bracket syntax
Use type guards to narrow types in conditionals

**/*.{ts,tsx}: Avoid default exports; prefer named exports
Use modern JavaScript features with TypeScript across the codebase
Use meaningful names; prefix booleans with is/has/does/should (e.g., isDisabled)
Receive an object and return an object (RORO) for functions interfacing with external services
Type definitions: use interface for objects/classes; type for unions/tuples/aliases; const for literals; enum for fixed sets
Avoid any; prefer specific types
Leverage type inference; omit explicit annotations when obvious
Add explicit type annotations for function parameters and return values
Prefer type assertions with as over angle-bracket syntax
Use type guards to narrow types within conditionals
Favor composition over inheritance in code structure

**/*.{ts,tsx}: Avoid default exports; prefer named exports
Prefer RORO (Receive an object, return an object) for function signatures, especially for external service interactions
Use interface for object shapes/classes; type for unions/tuples/aliases; const for literals; enum for fixed enumerations
Avoid using any; prefer precise types
Leverage type inference when clear; omit redundant annotations
Explicitly annotate function parameters and return types
Prefer type assertions with as over angle-bracket syntax
Use type guards to narrow types safely
Use meaningful variable names; prefix booleans with is/has/does/should
Favor composition over inheritance
Use lowercase dash-separated names for files and folders; use extensions like .config.ts, .test.ts, .context.tsx, .typ...

Files:

  • apps/pro-web/components/shared/image-generator.tsx
  • apps/pro-web/lib/hooks/use-workspace.tsx
  • apps/pro-web/components/routes/workspace/workspace-content.tsx
  • apps/pro-web/lib/hooks/use-workspace-media.tsx
  • apps/pro-web/lib/hooks/use-image-toggler.tsx
  • apps/pro-web/components/layout/providers.tsx
  • apps/pro-web/components/shared/image-display.tsx
  • apps/pro-web/types/index.ts
  • apps/pro-web/components/routes/chat/prompt-form/index.tsx
  • apps/pro-web/app/api/generate-images/route.ts
  • apps/pro-web/lib/hooks/use-image-generation.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
apps/{web,pro-web}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

apps/{web,pro-web}/**/*.{ts,tsx}: Use lowercase kebab-case for directories and filenames (components can omit extension)
Verify DOM operations and consider timing (RAF/delays) when manipulating the DOM in React
Use Tailwind CSS utility classes for styling React components

apps/{web,pro-web}/**/*.{ts,tsx}: Use TypeScript to define React props types (interfaces for props)
Use custom hooks (useMBChat, useThread, useSidebar, useModel) for domain-specific state and keep providers focused and composed hierarchically
Separate presentation from business logic and compose small components
Use hasura.service.ts for all GraphQL operations from UI layers

apps/{web,pro-web}/**/*.{ts,tsx}: Prefer Server Components; use the use client directive only when client-side features are required
Implement Nested Layouts using the App Router
Use Streaming and Suspense in Next.js 14/15 where appropriate
Follow Next.js file conventions as per documentation
Use IndexedDB for local caching to enable immediate UI updates

Files:

  • apps/pro-web/components/shared/image-generator.tsx
  • apps/pro-web/lib/hooks/use-workspace.tsx
  • apps/pro-web/components/routes/workspace/workspace-content.tsx
  • apps/pro-web/lib/hooks/use-workspace-media.tsx
  • apps/pro-web/lib/hooks/use-image-toggler.tsx
  • apps/pro-web/components/layout/providers.tsx
  • apps/pro-web/components/shared/image-display.tsx
  • apps/pro-web/types/index.ts
  • apps/pro-web/components/routes/chat/prompt-form/index.tsx
  • apps/pro-web/app/api/generate-images/route.ts
  • apps/pro-web/lib/hooks/use-image-generation.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
**/*

📄 CodeRabbit inference engine (CLAUDE.md)

**/*: Use lowercase with dash-separated directory and file names; use specific extensions: .config.ts, .test.ts, .context.tsx, .type.ts, .hook.ts; components may omit extension
Use Bun for package management and scripts instead of npm/yarn
Use Biome for formatting and linting via bun format-and-lint:fix; avoid Prettier/ESLint configs

Files:

  • apps/pro-web/components/shared/image-generator.tsx
  • apps/pro-web/package.json
  • apps/pro-web/lib/hooks/use-workspace.tsx
  • apps/pro-web/components/routes/workspace/workspace-content.tsx
  • apps/pro-web/lib/hooks/use-workspace-media.tsx
  • apps/pro-web/lib/hooks/use-image-toggler.tsx
  • apps/pro-web/components/layout/providers.tsx
  • apps/pro-web/components/shared/image-display.tsx
  • apps/pro-web/types/index.ts
  • apps/pro-web/components/routes/chat/prompt-form/index.tsx
  • apps/pro-web/app/api/generate-images/route.ts
  • apps/pro-web/lib/hooks/use-image-generation.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

**/*.tsx: Avoid inline arrow functions in JSX props; use stable function references for event handlers
Declare React components with the function keyword (functional components)
Use PascalCase for React component names
Use functional components and hooks instead of class components
Type component props with TypeScript interfaces

Files:

  • apps/pro-web/components/shared/image-generator.tsx
  • apps/pro-web/lib/hooks/use-workspace.tsx
  • apps/pro-web/components/routes/workspace/workspace-content.tsx
  • apps/pro-web/lib/hooks/use-workspace-media.tsx
  • apps/pro-web/lib/hooks/use-image-toggler.tsx
  • apps/pro-web/components/layout/providers.tsx
  • apps/pro-web/components/shared/image-display.tsx
  • apps/pro-web/components/routes/chat/prompt-form/index.tsx
  • apps/pro-web/lib/hooks/use-image-generation.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
apps/{web,pro-web}/components/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Order component files: imports → constants → component → styled components → types/interfaces

Files:

  • apps/pro-web/components/shared/image-generator.tsx
  • apps/pro-web/components/routes/workspace/workspace-content.tsx
  • apps/pro-web/components/layout/providers.tsx
  • apps/pro-web/components/shared/image-display.tsx
  • apps/pro-web/components/routes/chat/prompt-form/index.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
apps/{web,pro-web}/components/shared/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Store reusable UI elements in components/shared/

Files:

  • apps/pro-web/components/shared/image-generator.tsx
  • apps/pro-web/components/shared/image-display.tsx
apps/{web,pro-web}/lib/hooks/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

apps/{web,pro-web}/lib/hooks/**: Place custom React hooks under lib/hooks/
Encapsulate complex state in custom hooks and separate presentation from business logic

Store custom React hooks under lib/hooks/

Files:

  • apps/pro-web/lib/hooks/use-workspace.tsx
  • apps/pro-web/lib/hooks/use-workspace-media.tsx
  • apps/pro-web/lib/hooks/use-image-toggler.tsx
  • apps/pro-web/lib/hooks/use-image-generation.tsx
apps/{web,pro-web}/lib/hooks/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Place custom React hooks in lib/hooks/

Files:

  • apps/pro-web/lib/hooks/use-workspace.tsx
  • apps/pro-web/lib/hooks/use-workspace-media.tsx
  • apps/pro-web/lib/hooks/use-image-toggler.tsx
  • apps/pro-web/lib/hooks/use-image-generation.tsx
apps/{web,pro-web}/components/routes/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Place page-specific components under components/routes/[feature]/

Organize page-specific components under components/routes/

Files:

  • apps/pro-web/components/routes/workspace/workspace-content.tsx
  • apps/pro-web/components/routes/chat/prompt-form/index.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
apps/{web,pro-web}/types/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Place shared TypeScript definitions under types/

Keep TypeScript type definitions under types/

Files:

  • apps/pro-web/types/index.ts
apps/{web,pro-web}/types/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Place shared TypeScript types under types/

Files:

  • apps/pro-web/types/index.ts
apps/{web,pro-web}/app/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

apps/{web,pro-web}/app/**: Prefer Next.js Server Components; use 'use client' only when necessary
Leverage Streaming and Suspense for responsiveness in Next.js 15
Follow Next.js file conventions in the App Router

apps/{web,pro-web}/app/**: Leverage Server Components by default; use the use client directive only when client-side features are needed
Implement Nested Layouts using the App Router
Use Streaming and Suspense features in Next.js 14/15 where appropriate
Follow Next.js file conventions for routing and layout in the App Router
Optimize data fetching: fetch on the server, fetch where needed, and use preload patterns to avoid waterfalls

Files:

  • apps/pro-web/app/api/generate-images/route.ts
🧠 Learnings (36)
📓 Common learnings
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 504
File: apps/masterbots.ai/app/api/generate-images/route.ts:58-80
Timestamp: 2025-06-10T05:48:25.508Z
Learning: GPT-Image-1 is a legitimate and advanced OpenAI image generation model released in March 2025 as the successor to DALL·E 3. It's built on the multimodal GPT-4o architecture and supports enhanced capabilities including: up to 4096×4096 resolution, improved text rendering, image-to-image generation, inpainting/editing, multiple output formats (PNG, JPEG, WebP), transparent/opaque backgrounds, and both b64_json and URL response formats. It should be used with the OpenAI client directly rather than the experimental AI SDK for full feature support.
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 504
File: apps/masterbots.ai/app/api/generate-images/route.ts:58-80
Timestamp: 2025-06-10T05:48:25.508Z
Learning: In apps/masterbots.ai/app/api/generate-images/route.ts, the conditional check for modelId === 'gpt-image-1' is correct and uses the OpenAI client directly to handle this advanced model, while other models like 'dall-e-2' and 'dall-e-3' use the AI SDK. This implementation pattern is appropriate for handling different model capabilities.
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-09-04T21:31:18.830Z
Learning: Successfully created comprehensive GitHub issue #555 consolidating performance feedback and edge-case management for pro-web workspace features, including prioritized action items, testing requirements, and specific file references for implementation.
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 504
File: apps/masterbots.ai/app/api/generate-images/route.ts:58-80
Timestamp: 2025-06-10T05:48:25.508Z
Learning: The 'gpt-image-1' is a valid and new OpenAI image generation model that can be used with the OpenAI images.generate() API. It should be treated as a legitimate model ID alongside 'dall-e-2' and 'dall-e-3' in image generation applications.
📚 Learning: 2025-06-10T05:48:25.508Z
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 504
File: apps/masterbots.ai/app/api/generate-images/route.ts:58-80
Timestamp: 2025-06-10T05:48:25.508Z
Learning: In apps/masterbots.ai/app/api/generate-images/route.ts, the conditional check for modelId === 'gpt-image-1' is correct and uses the OpenAI client directly to handle this advanced model, while other models like 'dall-e-2' and 'dall-e-3' use the AI SDK. This implementation pattern is appropriate for handling different model capabilities.

Applied to files:

  • apps/pro-web/components/shared/image-generator.tsx
  • apps/pro-web/types/index.ts
  • apps/pro-web/app/api/generate-images/route.ts
  • apps/pro-web/lib/hooks/use-image-generation.tsx
📚 Learning: 2025-06-10T05:48:25.508Z
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 504
File: apps/masterbots.ai/app/api/generate-images/route.ts:58-80
Timestamp: 2025-06-10T05:48:25.508Z
Learning: The 'gpt-image-1' is a valid and new OpenAI image generation model that can be used with the OpenAI images.generate() API. It should be treated as a legitimate model ID alongside 'dall-e-2' and 'dall-e-3' in image generation applications.

Applied to files:

  • apps/pro-web/components/shared/image-generator.tsx
  • apps/pro-web/types/index.ts
  • apps/pro-web/app/api/generate-images/route.ts
  • apps/pro-web/lib/hooks/use-image-generation.tsx
📚 Learning: 2025-06-10T05:48:25.508Z
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 504
File: apps/masterbots.ai/app/api/generate-images/route.ts:58-80
Timestamp: 2025-06-10T05:48:25.508Z
Learning: GPT-Image-1 is a legitimate and advanced OpenAI image generation model released in March 2025 as the successor to DALL·E 3. It's built on the multimodal GPT-4o architecture and supports enhanced capabilities including: up to 4096×4096 resolution, improved text rendering, image-to-image generation, inpainting/editing, multiple output formats (PNG, JPEG, WebP), transparent/opaque backgrounds, and both b64_json and URL response formats. It should be used with the OpenAI client directly rather than the experimental AI SDK for full feature support.

Applied to files:

  • apps/pro-web/components/shared/image-generator.tsx
  • apps/pro-web/types/index.ts
  • apps/pro-web/app/api/generate-images/route.ts
  • apps/pro-web/lib/hooks/use-image-generation.tsx
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Use custom hooks (useMBChat, useThread, useSidebar, useModel) for domain-specific state and keep providers focused and composed hierarchically

Applied to files:

  • apps/pro-web/components/shared/image-generator.tsx
  • apps/pro-web/lib/hooks/use-workspace.tsx
  • apps/pro-web/components/routes/workspace/workspace-content.tsx
  • apps/pro-web/lib/hooks/use-workspace-media.tsx
  • apps/pro-web/lib/hooks/use-image-toggler.tsx
  • apps/pro-web/components/layout/providers.tsx
  • apps/pro-web/components/routes/chat/prompt-form/index.tsx
  • apps/pro-web/lib/hooks/use-image-generation.tsx
📚 Learning: 2024-10-23T07:33:36.041Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 287
File: apps/masterbots.ai/lib/hooks/use-thread-visibility.tsx:3-3
Timestamp: 2024-10-23T07:33:36.041Z
Learning: Always use explicit imports for React hooks to maintain consistency across the monorepo, and avoid using both named and default imports simultaneously.

Applied to files:

  • apps/pro-web/components/shared/image-generator.tsx
  • apps/pro-web/components/routes/workspace/workspace-content.tsx
  • apps/pro-web/lib/hooks/use-workspace-media.tsx
  • apps/pro-web/lib/hooks/use-image-toggler.tsx
  • apps/pro-web/components/layout/providers.tsx
  • apps/pro-web/components/routes/chat/prompt-form/index.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to apps/{web,pro-web}/**/*.tsx : Use functional components and hooks; type props with a TypeScript interface

Applied to files:

  • apps/pro-web/components/shared/image-generator.tsx
  • apps/pro-web/lib/hooks/use-workspace.tsx
  • apps/pro-web/components/routes/workspace/workspace-content.tsx
  • apps/pro-web/lib/hooks/use-workspace-media.tsx
  • apps/pro-web/lib/hooks/use-image-toggler.tsx
  • apps/pro-web/components/routes/chat/prompt-form/index.tsx
📚 Learning: 2025-01-28T19:42:19.327Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 337
File: packages/mb-genql/package.json:23-25
Timestamp: 2025-01-28T19:42:19.327Z
Learning: The genql dependencies (genql/cli, genql/runtime, genql) in packages/mb-genql/package.json are used primarily for TypeScript generation, and using "latest" versions is acceptable due to their stability and limited impact on the build process.

Applied to files:

  • apps/pro-web/package.json
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Pro workspace editors: controlled/uncontrolled patterns, Markdown utilities, section state sync, and timed DOM operations

Applied to files:

  • apps/pro-web/lib/hooks/use-workspace.tsx
  • apps/pro-web/components/routes/workspace/workspace-content.tsx
📚 Learning: 2025-09-04T21:31:18.830Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-09-04T21:31:18.830Z
Learning: The pro-web workspace features have complex performance considerations including markdown parsing optimization, AI streaming response handling, state persistence coordination, and selection range management that require careful monitoring and optimization.

Applied to files:

  • apps/pro-web/lib/hooks/use-workspace.tsx
📚 Learning: 2025-09-04T21:31:18.830Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-09-04T21:31:18.830Z
Learning: The pro-web workspace system has identified performance bottlenecks in markdown parsing, AI streaming response handling, selection range management, Base64 document processing, and multiple debounced state operations that require optimization and better coordination.

Applied to files:

  • apps/pro-web/lib/hooks/use-workspace.tsx
📚 Learning: 2025-09-04T21:31:18.830Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-09-04T21:31:18.830Z
Learning: Successfully created comprehensive GitHub issue #555 consolidating performance feedback and edge-case management for pro-web workspace features, including prioritized action items, testing requirements, and specific file references for implementation.

Applied to files:

  • apps/pro-web/lib/hooks/use-workspace.tsx
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Use TypeScript to define React props types (interfaces for props)

Applied to files:

  • apps/pro-web/lib/hooks/use-workspace.tsx
  • apps/pro-web/lib/hooks/use-workspace-media.tsx
📚 Learning: 2025-01-14T06:20:03.578Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 337
File: apps/masterbots.ai/components/routes/thread/user-thread-panel.tsx:195-205
Timestamp: 2025-01-14T06:20:03.578Z
Learning: React's useState setters (setState functions) maintain referential stability between renders and don't need to be included in useEffect dependency arrays. Include only the state values that the effect actually needs to track.

Applied to files:

  • apps/pro-web/lib/hooks/use-workspace.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to **/*.tsx : Use functional components and hooks instead of class components

Applied to files:

  • apps/pro-web/components/routes/workspace/workspace-content.tsx
  • apps/pro-web/lib/hooks/use-image-toggler.tsx
📚 Learning: 2025-10-24T20:40:56.510Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 573
File: apps/pro-web/components/routes/pro/pro.tsx:49-49
Timestamp: 2025-10-24T20:40:56.510Z
Learning: In apps/pro-web/lib/hooks/use-mb-chat.tsx, the useMBChat() hook returns a tuple [MBChatHookState, MBChatHookActions], not a direct object. Use array destructuring to access state (index 0) and actions (index 1), e.g., const [state, actions] = useMBChat() or const [{ isLoading }] = useMBChat().

Applied to files:

  • apps/pro-web/components/routes/workspace/workspace-content.tsx
  • apps/pro-web/lib/hooks/use-workspace-media.tsx
  • apps/pro-web/lib/hooks/use-image-toggler.tsx
  • apps/pro-web/components/layout/providers.tsx
  • apps/pro-web/components/routes/chat/prompt-form/index.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to apps/{web,pro-web}/lib/hooks/**/*.{ts,tsx} : Place custom React hooks in lib/hooks/

Applied to files:

  • apps/pro-web/components/routes/workspace/workspace-content.tsx
  • apps/pro-web/lib/hooks/use-workspace-media.tsx
  • apps/pro-web/lib/hooks/use-image-toggler.tsx
  • apps/pro-web/components/routes/chat/prompt-form/index.tsx
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to apps/{web,pro-web}/lib/hooks/** : Place custom React hooks under lib/hooks/

Applied to files:

  • apps/pro-web/lib/hooks/use-workspace-media.tsx
  • apps/pro-web/components/routes/chat/prompt-form/index.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Use Streaming and Suspense in Next.js 14/15 where appropriate

Applied to files:

  • apps/pro-web/lib/hooks/use-workspace-media.tsx
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/lib/hooks/** : Store custom React hooks under lib/hooks/

Applied to files:

  • apps/pro-web/lib/hooks/use-workspace-media.tsx
  • apps/pro-web/components/routes/chat/prompt-form/index.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Prefer Server Components; use the use client directive only when client-side features are required

Applied to files:

  • apps/pro-web/lib/hooks/use-image-toggler.tsx
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to apps/{web,pro-web}/app/** : Prefer Next.js Server Components; use 'use client' only when necessary

Applied to files:

  • apps/pro-web/lib/hooks/use-image-toggler.tsx
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/**/*.tsx : Declare React components with the function keyword (function ComponentName() {})

Applied to files:

  • apps/pro-web/lib/hooks/use-image-toggler.tsx
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to apps/{web,pro-web}/**/*.tsx : Declare React components with the function keyword

Applied to files:

  • apps/pro-web/lib/hooks/use-image-toggler.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-04-26T10:58:44.341Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 465
File: apps/masterbots.ai/components/routes/browse/browse-list.tsx:1-1
Timestamp: 2025-04-26T10:58:44.341Z
Learning: The browse-list.tsx component is redundant as thread-list.tsx has been developed to support all the same functionality including public pages. The codebase should be cleaned up to remove browse-list.tsx and related components in the browse directory, along with the BrowseProvider context.

Applied to files:

  • apps/pro-web/components/layout/providers.tsx
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to apps/{web,pro-web}/**/*.tsx : Order component files: imports → constants → component → styled components → types/interfaces

Applied to files:

  • apps/pro-web/components/layout/providers.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to apps/{web,pro-web}/components/**/*.tsx : Order component files: imports → constants → component → styled components → types/interfaces

Applied to files:

  • apps/pro-web/components/layout/providers.tsx
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to apps/{web,pro-web}/app/**/layout.tsx : Implement Nested Layouts via App Router layouts

Applied to files:

  • apps/pro-web/components/layout/providers.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Implement Nested Layouts using the App Router

Applied to files:

  • apps/pro-web/components/layout/providers.tsx
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Separate presentation from business logic and compose small components

Applied to files:

  • apps/pro-web/components/layout/providers.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to apps/{web,pro-web}/components/shared/**/*.{ts,tsx} : Store reusable UI elements in components/shared/

Applied to files:

  • apps/pro-web/components/layout/providers.tsx
  • apps/pro-web/components/shared/image-display.tsx
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/**/*.tsx : Order React component files: imports, constants, component, styled components, types/interfaces

Applied to files:

  • apps/pro-web/components/layout/providers.tsx
📚 Learning: 2025-04-26T10:58:44.341Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 465
File: apps/masterbots.ai/components/routes/browse/browse-list.tsx:1-1
Timestamp: 2025-04-26T10:58:44.341Z
Learning: The browse-list.tsx component and related components in the browse directory are redundant since thread-list.tsx has been developed to support all pages including public pages, and should be removed to simplify the codebase.

Applied to files:

  • apps/pro-web/components/layout/providers.tsx
📚 Learning: 2025-02-17T16:51:19.102Z
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 376
File: apps/masterbots.ai/components/routes/chat/chat.tsx:92-102
Timestamp: 2025-02-17T16:51:19.102Z
Learning: For the Chat component in apps/masterbots.ai/components/routes/chat/chat.tsx, the developer prefers to verify potential optimizations through local testing before accepting suggestions, particularly for performance-related changes like useCallback usage in debounce implementations.

Applied to files:

  • apps/pro-web/components/routes/chat/prompt-form/index.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to apps/{web,pro-web}/**/ai-main-call.actions.{ts,tsx} : Route AI API handling through ai-main-call.actions for unified processing

Applied to files:

  • apps/pro-web/app/api/generate-images/route.ts
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: For React/State: minimize useEffect deps, use refs for non-reactive values, separate state vs DOM manipulation

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
🧬 Code graph analysis (8)
apps/pro-web/components/shared/image-generator.tsx (1)
apps/pro-web/types/index.ts (1)
  • ImageModel (450-450)
apps/pro-web/lib/hooks/use-workspace.tsx (1)
apps/pro-web/types/thread.types.ts (1)
  • WorkspaceTabType (69-75)
apps/pro-web/components/routes/workspace/workspace-content.tsx (1)
apps/pro-web/lib/hooks/use-workspace.tsx (1)
  • useWorkspace (1388-1394)
apps/pro-web/lib/hooks/use-workspace-media.tsx (1)
apps/pro-web/types/index.ts (1)
  • ImageModel (450-450)
apps/pro-web/components/layout/providers.tsx (1)
apps/pro-web/lib/hooks/use-workspace-media.tsx (1)
  • WorkspaceMediaProvider (41-74)
apps/pro-web/components/routes/chat/prompt-form/index.tsx (2)
apps/pro-web/lib/hooks/use-workspace.tsx (1)
  • useWorkspace (1388-1394)
apps/pro-web/lib/hooks/use-workspace-media.tsx (1)
  • useWorkspaceMedia (76-84)
apps/pro-web/lib/hooks/use-image-generation.tsx (1)
apps/pro-web/types/index.ts (4)
  • ImageModel (450-450)
  • GeneratedImage (467-474)
  • ImageProviderType (441-441)
  • GenerateImageRequest (453-458)
apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx (4)
apps/pro-web/lib/hooks/use-image-generation.tsx (1)
  • useImageGeneration (18-175)
apps/pro-web/types/index.ts (1)
  • ImageModel (450-450)
apps/pro-web/lib/hooks/use-workspace-media.tsx (1)
  • useWorkspaceMedia (76-84)
apps/pro-web/components/shared/image-display.tsx (1)
  • ImageDisplay (22-188)
🔇 Additional comments (21)
apps/pro-web/package.json (1)

26-26: LGTM! Dependency addition aligns with Gemini integration.

The @google/genai dependency is correctly added to support the new Google Gemini image generation features introduced in this PR.

apps/pro-web/components/shared/image-display.tsx (1)

99-99: LGTM! Model info label repositioned.

The model info label has been moved from the top-left to the top-right corner, improving the layout for multi-provider image display.

apps/pro-web/components/shared/image-generator.tsx (4)

10-11: LGTM! Imports updated for multi-provider support.

The import changes correctly reflect the new ImageModel union type and add the Sparkles icon for Google provider differentiation.


16-25: LGTM! Model list extended with provider metadata.

The IMAGE_MODELS array correctly includes the new Gemini model with provider metadata, enabling multi-provider image generation workflows.


35-37: Verify default model change impact.

The default model has been changed from dall-e-3 to gemini-2.5-flash-image. While the implementation is correct, ensure this aligns with user expectations and any existing user preferences or settings are preserved.


147-151: LGTM! Provider-aware icon rendering.

The conditional icon rendering correctly differentiates between Google (Sparkles) and OpenAI (Camera) providers, improving visual clarity.

apps/pro-web/types/index.ts (6)

441-441: LGTM! Provider type extended correctly.

The ImageProviderType correctly includes both 'openai' and 'google' providers.


446-448: LGTM! Google model type defined.

The GoogleImageModel type is correctly defined with the initial Gemini model and follows the same pattern as OpenAIImageModel.


449-450: LGTM! Union type properly defined.

The ImageModel union type correctly combines both OpenAI and Google models, enabling type-safe multi-provider image generation.


455-455: LGTM! Request payload updated.

The GenerateImageRequest.modelId correctly uses the new ImageModel union type.


471-471: LGTM! Response payload updated.

The GeneratedImage.modelId correctly uses the new ImageModel union type.


621-625: LGTM! Hook signature updated for multi-provider support.

The generateImage signature correctly uses the ImageModel union type and adds previousImageData parameter for edit chaining.

apps/pro-web/components/routes/workspace/workspace-content.tsx (1)

3-3: LGTM! Workspace state centralized.

The refactoring correctly replaces local activeTab state with workspace context, eliminating state duplication and aligning with the centralized context architecture.

Also applies to: 30-31

apps/pro-web/lib/hooks/use-image-toggler.tsx (1)

1-2: LGTM! Client directive added appropriately.

The 'use client' directive is correctly added to support client-side hooks (useState, useContext) in Next.js 15.

apps/pro-web/components/layout/providers.tsx (1)

27-27: LGTM! WorkspaceMediaProvider integrated correctly.

The WorkspaceMediaProvider is properly integrated into the provider composition, maintaining the existing provider hierarchy while enabling media context throughout the application.

Also applies to: 74-92

apps/pro-web/app/api/generate-images/route.ts (3)

3-3: LGTM! Google GenAI SDK imported.

The GoogleGenAI import is correctly added from the new @google/genai dependency.


23-28: LGTM! Model detection helper added.

The isGeminiModel helper correctly identifies Gemini models using prefix matching.


136-136: LGTM! Control flow documentation improved.

The comment clarifies the OpenAI handling path, improving code maintainability.

apps/pro-web/components/routes/chat/prompt-form/index.tsx (1)

65-66: Media mode wiring and dynamic placeholder look correct; verify provider wrapping

  • Using useWorkspace()/useWorkspaceMedia() to derive isMediaMode and then computing effectivePlaceholder from mediaTab.generatedImage is coherent, and the useMemo dependencies cover all referenced values.
  • Binding the textarea’s placeholder to effectivePlaceholder correctly switches UX between chat and media modes.

Please confirm that any place PromptForm is rendered is wrapped in both WorkspaceProvider and WorkspaceMediaProvider; otherwise these hooks will throw at runtime.

Also applies to: 136-150, 345-359

apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx (2)

176-181: Resetting image generation on template/size change is reasonable

The effect that calls resetImageGeneration() when selectedTemplate?.id or selectedSize?.id changes correctly clears prior results when the canvas configuration changes. Omitting generatedImage and the reset function from the dependency array is intentional here and safe, since you only want the reset to run on template/size changes (the referenced values come from the same render that changed those keys).


214-305: Canvas overlays (image, loading, error) are layered correctly

  • Wrapping the template card with relative overflow-hidden and then layering:
    • the template/size label (z-10),
    • the rendered image via ImageDisplay (absolute inset, full size),
    • the loading overlay (z-30),
    • and the error overlay (z-20)
      provides a clear stacking order.
  • Gating ImageDisplay on generatedImage && !isGeneratingImage avoids showing stale content during an in‑flight generation.
  • Error overlay includes a straightforward “Try Again” button that reuses resetImageGeneration.

This structure should behave well across loading, success, and failure states.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx (1)

212-212: Avoid inline arrow functions in JSX event handlers.

Multiple inline arrow functions are used in JSX (Lines 212, 417-421, 434-440), which violates the coding guidelines and can cause unnecessary re-renders. The guidelines explicitly state to use stable function references for event handlers.

As per coding guidelines.

For handlers that need parameters from map iterations, consider using data attributes or wrapping with useCallback:

Example for line 212:

+	const handleCategoryClick = useCallback((category: MediaCategory) => {
+		setSelectedCategory(category)
+		setDialogStep('size')
+	}, [])

 	{categories.map((cat) => (
 		<Button
 			...
-			onClick={() => handleCategorySelect(cat)}
+			onClick={() => handleCategoryClick(cat)}
 		>

Or use a data attribute approach:

+	function handleCategoryClick(e: React.MouseEvent<HTMLButtonElement>) {
+		const categoryId = e.currentTarget.dataset.categoryId
+		const category = categories.find(c => c.id === categoryId)
+		if (category) {
+			setSelectedCategory(category)
+			setDialogStep('size')
+		}
+	}

 	{categories.map((cat) => (
 		<Button
 			...
-			onClick={() => handleCategorySelect(cat)}
+			onClick={handleCategoryClick}
+			data-category-id={cat.id}
 		>

Similar patterns should be applied to lines 417-421 and 434-440.

Also applies to: 417-421, 434-440

🧹 Nitpick comments (4)
apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx (1)

60-62: Move resolveImageModel outside the component.

This helper function is pure (doesn't close over any props or state) and is recreated on every render. Moving it outside MediaWorkspace avoids unnecessary function allocations.

Apply this diff:

+function resolveImageModel(hasImage: boolean): ImageModel {
+	return hasImage ? 'gemini-2.5-flash-image' : 'gpt-image-1'
+}
+
 export function MediaWorkspace() {
 	const [selectedCategory, setSelectedCategory] =
 		useState<MediaCategory | null>(null)
 	...
-	// Temporarily auto-enable edit behavior based on generatedImage.
-	// This avoids adding an explicit "Edit mode" toggle on the canvas for now.
-	// TODO: When media tools (erase/replace/add text) are ready, use isEditMode instead.
-	function resolveImageModel(hasImage: boolean): ImageModel {
-		return hasImage ? 'gemini-2.5-flash-image' : 'gpt-image-1'
-	}
-
 	// Model for Media Tab: Nano Banana (gemini) for edit mode, gpt-image-1 for generate
 	const selectedModel: ImageModel = resolveImageModel(!!generatedImage)
apps/pro-web/app/api/generate-images/route.ts (3)

23-28: Consider validating against a list of supported Gemini models.

The prefix check is simple but doesn't validate whether the specific model is supported. Consider maintaining a list of known Gemini model IDs to catch typos or unsupported models early.

Example:

-const isGeminiModel = (modelId: string): boolean => {
-	return modelId.startsWith('gemini-')
-}
+const SUPPORTED_GEMINI_MODELS = ['gemini-2.0-flash-exp', 'gemini-exp-1206'] as const
+
+const isGeminiModel = (modelId: string): boolean => {
+	return SUPPORTED_GEMINI_MODELS.some(model => modelId === model)
+}

86-89: Consider extracting contentParts type definition.

The inline type for contentParts could be extracted to improve reusability and reduce clutter, especially if this structure is used elsewhere in Gemini-related code.

+type GeminiContentPart = {
+	text?: string
+	inlineData?: { mimeType: string; data: string }
+}
+
-const contentParts: Array<{
-	text?: string
-	inlineData?: { mimeType: string; data: string }
-}> = []
+const contentParts: GeminiContentPart[] = []

118-132: Simplify response parsing with optional chaining.

The nested conditionals can be flattened for better readability.

-// Access the candidates array from the response
-if (response.candidates && response.candidates.length > 0) {
-	const candidate = response.candidates[0]
-	if (candidate.content?.parts) {
-		for (const part of candidate.content.parts) {
-			if (part.inlineData) {
-				imageBase64 = part.inlineData.data
-				break
-			}
-		}
-	}
-}
+// Extract image from first candidate
+const imageData = response.candidates?.[0]?.content?.parts?.find(
+	part => part.inlineData
+)?.inlineData?.data

-if (!imageBase64) {
+if (!imageData) {
 	throw new Error('No image data returned from Gemini')
 }

 return {
-	image: imageBase64,
+	image: imageData,
 	warnings: [],
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5868095 and a5c4da4.

📒 Files selected for processing (3)
  • apps/pro-web/app/api/generate-images/route.ts (3 hunks)
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx (8 hunks)
  • apps/pro-web/lib/hooks/use-workspace-media.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/pro-web/lib/hooks/use-workspace-media.tsx
🧰 Additional context used
📓 Path-based instructions (8)
apps/{web,pro-web}/components/routes/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Place page-specific components under components/routes/[feature]/

Organize page-specific components under components/routes/

Files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
apps/{web,pro-web}/**/*.tsx

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

apps/{web,pro-web}/**/*.tsx: Declare React components with the function keyword
Name React components using PascalCase
Order component files: imports → constants → component → styled components → types/interfaces
Use functional components and hooks; type props with a TypeScript interface
Use regular function references (not inline arrows) for React event handlers to avoid extra re-renders

apps/{web,pro-web}/**/*.tsx: Use regular function references for event handlers instead of inline arrow functions in JSX
Declare React components with the function keyword (function ComponentName() {})
Use PascalCase for React component names
Order React component files: imports, constants, component, styled components, types/interfaces
Style components with Tailwind CSS utility classes

Files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Avoid default exports; prefer named exports
Use meaningful variable names; prefix booleans with is/has/does/should
Use interface for objects/classes; type for unions/tuples/aliases; enum for fixed sets; const for literals
Avoid any; prefer specific types
Leverage type inference where clear; annotate function params and return types
Prefer type assertions with 'as' over angle-bracket syntax
Use type guards to narrow types in conditionals

**/*.{ts,tsx}: Avoid default exports; prefer named exports
Use modern JavaScript features with TypeScript across the codebase
Use meaningful names; prefix booleans with is/has/does/should (e.g., isDisabled)
Receive an object and return an object (RORO) for functions interfacing with external services
Type definitions: use interface for objects/classes; type for unions/tuples/aliases; const for literals; enum for fixed sets
Avoid any; prefer specific types
Leverage type inference; omit explicit annotations when obvious
Add explicit type annotations for function parameters and return values
Prefer type assertions with as over angle-bracket syntax
Use type guards to narrow types within conditionals
Favor composition over inheritance in code structure

**/*.{ts,tsx}: Avoid default exports; prefer named exports
Prefer RORO (Receive an object, return an object) for function signatures, especially for external service interactions
Use interface for object shapes/classes; type for unions/tuples/aliases; const for literals; enum for fixed enumerations
Avoid using any; prefer precise types
Leverage type inference when clear; omit redundant annotations
Explicitly annotate function parameters and return types
Prefer type assertions with as over angle-bracket syntax
Use type guards to narrow types safely
Use meaningful variable names; prefix booleans with is/has/does/should
Favor composition over inheritance
Use lowercase dash-separated names for files and folders; use extensions like .config.ts, .test.ts, .context.tsx, .typ...

Files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
  • apps/pro-web/app/api/generate-images/route.ts
apps/{web,pro-web}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

apps/{web,pro-web}/**/*.{ts,tsx}: Use lowercase kebab-case for directories and filenames (components can omit extension)
Verify DOM operations and consider timing (RAF/delays) when manipulating the DOM in React
Use Tailwind CSS utility classes for styling React components

apps/{web,pro-web}/**/*.{ts,tsx}: Use TypeScript to define React props types (interfaces for props)
Use custom hooks (useMBChat, useThread, useSidebar, useModel) for domain-specific state and keep providers focused and composed hierarchically
Separate presentation from business logic and compose small components
Use hasura.service.ts for all GraphQL operations from UI layers

apps/{web,pro-web}/**/*.{ts,tsx}: Prefer Server Components; use the use client directive only when client-side features are required
Implement Nested Layouts using the App Router
Use Streaming and Suspense in Next.js 14/15 where appropriate
Follow Next.js file conventions as per documentation
Use IndexedDB for local caching to enable immediate UI updates

Files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
  • apps/pro-web/app/api/generate-images/route.ts
**/*

📄 CodeRabbit inference engine (CLAUDE.md)

**/*: Use lowercase with dash-separated directory and file names; use specific extensions: .config.ts, .test.ts, .context.tsx, .type.ts, .hook.ts; components may omit extension
Use Bun for package management and scripts instead of npm/yarn
Use Biome for formatting and linting via bun format-and-lint:fix; avoid Prettier/ESLint configs

Files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
  • apps/pro-web/app/api/generate-images/route.ts
**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

**/*.tsx: Avoid inline arrow functions in JSX props; use stable function references for event handlers
Declare React components with the function keyword (functional components)
Use PascalCase for React component names
Use functional components and hooks instead of class components
Type component props with TypeScript interfaces

Files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
apps/{web,pro-web}/components/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Order component files: imports → constants → component → styled components → types/interfaces

Files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
apps/{web,pro-web}/app/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

apps/{web,pro-web}/app/**: Prefer Next.js Server Components; use 'use client' only when necessary
Leverage Streaming and Suspense for responsiveness in Next.js 15
Follow Next.js file conventions in the App Router

apps/{web,pro-web}/app/**: Leverage Server Components by default; use the use client directive only when client-side features are needed
Implement Nested Layouts using the App Router
Use Streaming and Suspense features in Next.js 14/15 where appropriate
Follow Next.js file conventions for routing and layout in the App Router
Optimize data fetching: fetch on the server, fetch where needed, and use preload patterns to avoid waterfalls

Files:

  • apps/pro-web/app/api/generate-images/route.ts
🧠 Learnings (17)
📓 Common learnings
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-09-04T21:31:18.830Z
Learning: Successfully created comprehensive GitHub issue #555 consolidating performance feedback and edge-case management for pro-web workspace features, including prioritized action items, testing requirements, and specific file references for implementation.
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 504
File: apps/masterbots.ai/app/api/generate-images/route.ts:58-80
Timestamp: 2025-06-10T05:48:25.508Z
Learning: GPT-Image-1 is a legitimate and advanced OpenAI image generation model released in March 2025 as the successor to DALL·E 3. It's built on the multimodal GPT-4o architecture and supports enhanced capabilities including: up to 4096×4096 resolution, improved text rendering, image-to-image generation, inpainting/editing, multiple output formats (PNG, JPEG, WebP), transparent/opaque backgrounds, and both b64_json and URL response formats. It should be used with the OpenAI client directly rather than the experimental AI SDK for full feature support.
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 504
File: apps/masterbots.ai/app/api/generate-images/route.ts:58-80
Timestamp: 2025-06-10T05:48:25.508Z
Learning: In apps/masterbots.ai/app/api/generate-images/route.ts, the conditional check for modelId === 'gpt-image-1' is correct and uses the OpenAI client directly to handle this advanced model, while other models like 'dall-e-2' and 'dall-e-3' use the AI SDK. This implementation pattern is appropriate for handling different model capabilities.
📚 Learning: 2025-06-10T05:48:25.508Z
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 504
File: apps/masterbots.ai/app/api/generate-images/route.ts:58-80
Timestamp: 2025-06-10T05:48:25.508Z
Learning: In apps/masterbots.ai/app/api/generate-images/route.ts, the conditional check for modelId === 'gpt-image-1' is correct and uses the OpenAI client directly to handle this advanced model, while other models like 'dall-e-2' and 'dall-e-3' use the AI SDK. This implementation pattern is appropriate for handling different model capabilities.

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
  • apps/pro-web/app/api/generate-images/route.ts
📚 Learning: 2025-06-13T08:55:45.217Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 508
File: apps/masterbots.ai/lib/helpers/ai-helpers.ts:280-283
Timestamp: 2025-06-13T08:55:45.217Z
Learning: In `apps/masterbots.ai/lib/helpers/ai-helpers.ts` the `verifyDuplicateMessage` function should:
• Use `message.content` as the sole de-duplication key so provisional (no-slug) and persisted (slugged) messages merge properly.
• Return the full `message` object (not just a string key) for the continuation prompts (`CONTINUE_GENERATION_PROMPT`, `CONTINUE_GENERATION_PROMPT_2`) because their content repeats and they must remain distinct.
• No explicit `!message.content` guard is needed; `return message.content` already yields `undefined` when content is missing.

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to **/*.tsx : Avoid inline arrow functions in JSX props; use stable function references for event handlers

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-02-17T16:51:19.102Z
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 376
File: apps/masterbots.ai/components/routes/chat/chat.tsx:92-102
Timestamp: 2025-02-17T16:51:19.102Z
Learning: For the Chat component in apps/masterbots.ai/components/routes/chat/chat.tsx, the developer prefers to verify potential optimizations through local testing before accepting suggestions, particularly for performance-related changes like useCallback usage in debounce implementations.

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to apps/{web,pro-web}/**/*.tsx : Use regular function references (not inline arrows) for React event handlers to avoid extra re-renders

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Verify DOM operations and consider timing (RAF/delays) when manipulating the DOM in React

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2024-11-20T04:00:45.413Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 300
File: apps/masterbots.ai/components/routes/thread/user-thread-panel.tsx:120-123
Timestamp: 2024-11-20T04:00:45.413Z
Learning: In React code, when reviewing `useEffect` dependencies, it's not always necessary to add functions like `handleThreadsChange` to the dependency array, as this may lead to unnecessary re-renders and performance issues. Only include dependencies that are essential and may change.

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/**/*.tsx : Use regular function references for event handlers instead of inline arrow functions in JSX

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2024-10-23T07:33:36.041Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 287
File: apps/masterbots.ai/lib/hooks/use-thread-visibility.tsx:3-3
Timestamp: 2024-10-23T07:33:36.041Z
Learning: Always use explicit imports for React hooks to maintain consistency across the monorepo, and avoid using both named and default imports simultaneously.

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: For React/State: minimize useEffect deps, use refs for non-reactive values, separate state vs DOM manipulation

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to apps/{web,pro-web}/**/*.tsx : Declare React components with the function keyword

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-01-14T06:20:03.578Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 337
File: apps/masterbots.ai/components/routes/thread/user-thread-panel.tsx:195-205
Timestamp: 2025-01-14T06:20:03.578Z
Learning: React's useState setters (setState functions) maintain referential stability between renders and don't need to be included in useEffect dependency arrays. Include only the state values that the effect actually needs to track.

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Embrace React’s declarative style; avoid imperative DOM manipulation

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to apps/{web,pro-web}/**/ai-main-call.actions.{ts,tsx} : Route AI API handling through ai-main-call.actions for unified processing

Applied to files:

  • apps/pro-web/app/api/generate-images/route.ts
📚 Learning: 2025-06-10T05:48:25.508Z
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 504
File: apps/masterbots.ai/app/api/generate-images/route.ts:58-80
Timestamp: 2025-06-10T05:48:25.508Z
Learning: GPT-Image-1 is a legitimate and advanced OpenAI image generation model released in March 2025 as the successor to DALL·E 3. It's built on the multimodal GPT-4o architecture and supports enhanced capabilities including: up to 4096×4096 resolution, improved text rendering, image-to-image generation, inpainting/editing, multiple output formats (PNG, JPEG, WebP), transparent/opaque backgrounds, and both b64_json and URL response formats. It should be used with the OpenAI client directly rather than the experimental AI SDK for full feature support.

Applied to files:

  • apps/pro-web/app/api/generate-images/route.ts
📚 Learning: 2025-06-10T05:48:25.508Z
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 504
File: apps/masterbots.ai/app/api/generate-images/route.ts:58-80
Timestamp: 2025-06-10T05:48:25.508Z
Learning: The 'gpt-image-1' is a valid and new OpenAI image generation model that can be used with the OpenAI images.generate() API. It should be treated as a legitimate model ID alongside 'dall-e-2' and 'dall-e-3' in image generation applications.

Applied to files:

  • apps/pro-web/app/api/generate-images/route.ts
🧬 Code graph analysis (1)
apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx (4)
apps/pro-web/lib/hooks/use-image-generation.tsx (1)
  • useImageGeneration (18-175)
apps/pro-web/types/index.ts (1)
  • ImageModel (450-450)
apps/pro-web/lib/hooks/use-workspace-media.tsx (1)
  • useWorkspaceMedia (74-82)
apps/pro-web/components/shared/image-display.tsx (1)
  • ImageDisplay (22-188)
🔇 Additional comments (3)
apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx (1)

73-86: Good fix for the TDZ issue and handler stability.

The previous critical issue with Temporal Dead Zone (referencing handlePromptSubmit before declaration) has been properly resolved by defining it with useCallback before the useEffect. The handler is now stable and correctly included in the effect's dependency array.

Also applies to: 89-108

apps/pro-web/app/api/generate-images/route.ts (2)

3-3: LGTM!

The import is clean and necessary for the new Gemini functionality.


77-82: LGTM!

The API key validation has been properly addressed from the previous review. Clear error message and early validation before instantiation.

Comment on lines +86 to +107
const contentParts: Array<{
text?: string
inlineData?: { mimeType: string; data: string }
}> = []

// Add prompt
contentParts.push({ text: prompt })

// Add previous image if in edit mode
if (editMode && previousImage) {
// Remove data URL prefix if present
const base64Data = previousImage.includes('base64,')
? previousImage.split('base64,')[1]
: previousImage

contentParts.push({
inlineData: {
mimeType: 'image/png',
data: base64Data,
},
})
}
Copy link
Contributor

@coderabbitai coderabbitai bot Nov 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix hardcoded MIME type assumption for previous images.

Line 103 hardcodes mimeType: 'image/png', but the previous image could be JPEG, WebP, or other formats. This mismatch may cause the Gemini API to reject or misinterpret the image data.

Detect the MIME type from the data URL prefix:

 if (editMode && previousImage) {
-	// Remove data URL prefix if present
-	const base64Data = previousImage.includes('base64,')
-		? previousImage.split('base64,')[1]
-		: previousImage
+	let mimeType = 'image/png' // default
+	let base64Data = previousImage
+	
+	// Extract MIME type and base64 data from data URL
+	if (previousImage.startsWith('data:')) {
+		const match = previousImage.match(/^data:(image\/[^;]+);base64,(.+)$/)
+		if (match) {
+			mimeType = match[1]
+			base64Data = match[2]
+		}
+	}

 	contentParts.push({
 		inlineData: {
-			mimeType: 'image/png',
+			mimeType,
 			data: base64Data,
 		},
 	})
 }
🤖 Prompt for AI Agents
In apps/pro-web/app/api/generate-images/route.ts around lines 86 to 107, the
code hardcodes mimeType: 'image/png' for previousImage which can be
JPEG/WebP/etc; instead, detect the MIME type from the data URL prefix (e.g.
data:<mimeType>;base64,...) before stripping the base64 payload: if
previousImage starts with 'data:' extract the substring between 'data:' and
';base64' and use that as inlineData.mimeType, then remove the 'data:*;base64,'
prefix to get base64Data; if no data URL prefix is present fall back to a safe
default like 'application/octet-stream' (or a configurable default) and set
inlineData.data to the remaining string. Ensure the extracted mimeType is used
rather than the hardcoded 'image/png'.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@coderabbitai I think by default the LLMs returns a PNG file hence, various file forms won't happen—UNLESS we activate the "library" feature, there if we need to add reference files, we must pass the base64 string to the request. Also happens with the templates if user starts from one.

⚠️ It is highly suggested that ref images executes in a server action, a major limitation in the NextJS API routes is that we cannot send more than 2.5/3mb per request and some files may weight more than that. It is easier server actions to execute these or use these server actions to create a cache with a checksum (computeChecksum fn) to then request this temp cache to the API request and send it to the googleAI client.

cc - @derianrddev

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AndlerRL, thank you for the clarification! You're absolutely right—since the generated images are PNG by default in the current scope, the hardcoded MIME type is appropriate for now.

I appreciate the heads-up about the upcoming library/template features. Your suggestion to use server actions with checksum-based caching is a solid architectural choice, especially given the 2.5-3MB limitation in Next.js API routes. That approach will handle larger reference images much more efficiently:

User uploads ref image → Server action with computeChecksum → Cache with checksum key → API route fetches from cache → GoogleAI client

This keeps the API route lightweight while supporting larger files through the cache layer.

Would you like me to create a tracking issue for the library/template feature implementation so the MIME type detection and server action refactoring are captured for the future work? Or is this already being tracked elsewhere?


✏️ Learnings added
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 584
File: apps/pro-web/app/api/generate-images/route.ts:86-107
Timestamp: 2025-11-14T19:14:07.226Z
Learning: In apps/pro-web/app/api/generate-images/route.ts, the hardcoded 'image/png' MIME type for Gemini previousImage is intentional—LLM-generated images are PNG by default. When the library/template features are added (allowing user-uploaded reference images), the architecture should use Next.js server actions with checksum-based caching (computeChecksum fn) to handle files larger than the 2.5-3MB API route limit, rather than detecting MIME types in the API route directly.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 504
File: apps/masterbots.ai/app/api/generate-images/route.ts:58-80
Timestamp: 2025-06-10T05:48:25.508Z
Learning: In apps/masterbots.ai/app/api/generate-images/route.ts, the conditional check for modelId === 'gpt-image-1' is correct and uses the OpenAI client directly to handle this advanced model, while other models like 'dall-e-2' and 'dall-e-3' use the AI SDK. This implementation pattern is appropriate for handling different model capabilities.

Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to apps/{web,pro-web}/public/**/*.{png,jpg,jpeg} : Prefer WebP for raster images; avoid adding non-WebP raster images when possible

Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 504
File: apps/masterbots.ai/app/api/generate-images/route.ts:58-80
Timestamp: 2025-06-10T05:48:25.508Z
Learning: GPT-Image-1 is a legitimate and advanced OpenAI image generation model released in March 2025 as the successor to DALL·E 3. It's built on the multimodal GPT-4o architecture and supports enhanced capabilities including: up to 4096×4096 resolution, improved text rendering, image-to-image generation, inpainting/editing, multiple output formats (PNG, JPEG, WebP), transparent/opaque backgrounds, and both b64_json and URL response formats. It should be used with the OpenAI client directly rather than the experimental AI SDK for full feature support.

Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 542
File: apps/web/components/layout/profile/layout.tsx:67-68
Timestamp: 2025-08-29T20:34:24.433Z
Learning: AndlerRL prefers skeleton loading states over conditional rendering for better UX when components are waiting for data to load. Components should show loading indicators rather than blank spaces.

Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-09-04T21:31:18.830Z
Learning: Successfully created comprehensive GitHub issue #555 consolidating performance feedback and edge-case management for pro-web workspace features, including prioritized action items, testing requirements, and specific file references for implementation.

Comment on lines +109 to +112
const response = await googleAI.models.generateContent({
model: modelId,
contents: contentParts,
})
Copy link
Contributor

@coderabbitai coderabbitai bot Nov 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

Verify Gemini API support for image size parameters.

The OpenAI path specifies DEFAULT_IMAGE_SIZE, but the Gemini path doesn't include any size specification. Confirm whether the Gemini API supports size parameters and, if so, add them for consistency.


🌐 Web query:

Does Google Gemini generateContent API support image size parameters for image generation?

💡 Result:

Yes. The Gemini/Imagen image-generation API accepts image-size parameters. For Imagen 4 models the parameter is named imageSize (or sample_image_size in Vertex AI) with supported values "1K" and "2K;” older Imagen models accept numeric sizes (e.g. 64, 256, 512, 1024, 2048, 4096). See the Gemini/Imagen docs and Vertex AI image-generation reference. [1][2][3]

Sources:

  • Gemini/Imagen docs (imageSize, aspectRatio, numberOfImages). [1]
  • Vertex AI / Imagen image-generation reference (sample_image_size: "1K" or "2K" for Imagen 4; numeric sizes for earlier models). [2]
  • Vertex AI parameter reference (sample_image_size field and supported values). [3]

🏁 Script executed:

#!/bin/bash
# Get full context of the generateContent call and surrounding code
cat apps/pro-web/app/api/generate-images/route.ts

Length of output: 5495


🏁 Script executed:

#!/bin/bash
# Search for DEFAULT_IMAGE_SIZE usage to understand OpenAI path
rg -n "DEFAULT_IMAGE_SIZE" apps/pro-web/

Length of output: 248


🏁 Script executed:

#!/bin/bash
# Search for other generateContent or image generation context
rg -n -A5 -B5 "generateContent" apps/pro-web/app/api/generate-images/

Length of output: 752


Add image size parameter to Gemini API call for consistency with OpenAI paths.

The Gemini path (lines 109-112) is missing size specification while both OpenAI paths include size: DEFAULT_IMAGE_SIZE. Web search confirms that the Gemini/Imagen API supports the imageSize parameter. Add imageSize to the generateContent() call to maintain consistent image dimensions across all model providers.

🤖 Prompt for AI Agents
In apps/pro-web/app/api/generate-images/route.ts around lines 109 to 112, the
Google/Gemini generateContent call is missing the image size parameter; add the
supported imageSize property (set to the same DEFAULT_IMAGE_SIZE constant used
for OpenAI paths) to the options passed to googleAI.models.generateContent so
Gemini/Imagen outputs match the OpenAI image dimensions.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to pass the frame to create the closest framing of the chosen template.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check the template and size structure in media-workspace-ui.tsx
echo "=== Template/Size in media-workspace-ui.tsx ==="
rg -n -A3 -B3 "selectedTemplate|selectedSize" apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx | head -50

echo -e "\n=== GenerateImageRequest type definition ==="
rg -n -A10 "type GenerateImageRequest|interface GenerateImageRequest" apps/pro-web/types/

echo -e "\n=== How generateImage is called (check for size params) ==="
rg -n -A5 "generateImage\(" apps/pro-web/lib/hooks/use-image-generation.tsx | head -40

echo -e "\n=== Template and size types/constants ==="
rg -n "TEMPLATES|IMAGE_SIZES|MediaTemplate|templateSize" apps/pro-web/components/routes/workspace/media-tab/

Length of output: 2532


🏁 Script executed:

#!/bin/bash
# Find Template and FrameSize type definitions
echo "=== Template and FrameSize type definitions ==="
rg -n -A10 "type Template|interface Template" apps/pro-web/types/
rg -n -A10 "type FrameSize|interface FrameSize" apps/pro-web/types/

echo -e "\n=== Check how generateImage constructs the API request ==="
cat apps/pro-web/lib/hooks/use-image-generation.tsx

echo -e "\n=== Check template data/constants ==="
fd -e ts -e tsx template apps/pro-web/components/routes/workspace/media-tab/ --exec cat {}

Length of output: 6314


🏁 Script executed:

#!/bin/bash
# Find FrameSize definition and size constants
echo "=== FrameSize type and size constants ==="
cat apps/pro-web/components/routes/workspace/media-tab/select-size-step.tsx

echo -e "\n=== Check if there are any existing size mappings ==="
rg -n "aspectRatio|imageSize|dimensions" apps/pro-web/components/routes/workspace/media-tab/

Length of output: 200


🏁 Script executed:

#!/bin/bash
# Find all files in media-tab directory
echo "=== All files in media-tab directory ==="
fd . apps/pro-web/components/routes/workspace/media-tab/ -t f

echo -e "\n=== Search for FrameSize definition ==="
rg -n "export.*FrameSize" apps/pro-web/

echo -e "\n=== Look for size-related code in media workspace ==="
rg -n -B5 -A10 "FrameSize" apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx

Length of output: 1986


🏁 Script executed:

#!/bin/bash
# Get the FrameSize definition and all frame sizes
echo "=== FrameSize definition and sizes ==="
cat apps/pro-web/components/routes/workspace/media-tab/steps/select-size-step.tsx

echo -e "\n=== Get all frameSizes from media-workspace-ui.tsx ==="
rg -n -A50 "const frameSizes" apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx

Length of output: 3628


@AndlerRL Perfect! I can see the frame/size system you have in place. To pass the template frame information to the Gemini API for proper aspect ratio handling, you'll need to make changes across three layers:

Required Changes

1. Extend the GenerateImageRequest type (apps/pro-web/types/index.ts)

export interface GenerateImageRequest {
	prompt: string
	modelId: ImageModel
	previousImage?: string // base64 of the previous image
	editMode?: boolean
	aspectRatio?: string // e.g., "1:1", "16:9", "9:16", "21:9"
	imageSize?: string // e.g., "1K", "2K" for Imagen models
}

2. Update the hook to pass aspect ratio (apps/pro-web/lib/hooks/use-image-generation.tsx)

Modify the generateImage function signature and request construction:

const generateImage = useCallback(
	async (
		prompt: string,
		modelId: ImageModel,
		previousImageData?: GeneratedImage,
		aspectRatio?: string, // Add this parameter
	) => {
		// ... existing code ...
		
		const request: GenerateImageRequest = {
			prompt,
			modelId,
			...(aspectRatio && { aspectRatio }), // Add aspect ratio
			...(isEdit &&
				editImage && {
					previousImage: editImage.base64,
					editMode: true,
				}),
		}
		
		// ... rest of the code ...
	},
	[isEditMode, previousImage],
)

3. Pass aspect ratio from Media Workspace UI (apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx)

Update the handlePromptSubmit to include the aspect ratio:

const handlePromptSubmit = useCallback(
	async (prompt: string) => {
		if (!selectedTemplate || !selectedSize) {
			console.warn(
				'Please select a size and template before generating an image',
			)
			return
		}

		const modelId = resolveImageModel(!!generatedImage)
		await generateImage(
			prompt, 
			modelId, 
			generatedImage || undefined,
			selectedSize.ratio // Pass the aspect ratio here
		)
	},
	[selectedTemplate, selectedSize, generatedImage, generateImage],
)

4. Use aspect ratio in the Gemini API call (apps/pro-web/app/api/generate-images/route.ts)

Update the Gemini generateContent call around lines 109-112:

const response = await googleAI.models.generateContent({
	model: modelId,
	contents: contentParts,
	generationConfig: {
		...(aspectRatio && { aspectRatio }), // Add aspect ratio from request
		imageSize: '1K', // Or '2K' for higher resolution
	},
})

Summary

This implementation will:

  • ✅ Pass the selected frame's aspect ratio (e.g., "1:1", "16:9", "9:16", "21:9") from the UI through to the Gemini API
  • ✅ Ensure generated images match the chosen template's framing
  • ✅ Maintain consistency with the frame sizes you've defined (Square, Landscape, Portrait, Wide)

The aspect ratio values in your frameSizes array already match the format expected by the Gemini API, so they'll work directly without transformation.


🧬 Code Graph Analysis Results

apps/pro-web/types/index.ts

<possibly_relevant_code_snippets>

Snippet 1 (line 453-458)

export interface GenerateImageRequest {
	prompt: string
	modelId: ImageModel
	previousImage?: string // base64 of the previous image
	editMode?: boolean
}

</possibly_relevant_code_snippets>


🧠 Learnings used
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 504
File: apps/masterbots.ai/app/api/generate-images/route.ts:58-80
Timestamp: 2025-06-10T05:48:25.508Z
Learning: In apps/masterbots.ai/app/api/generate-images/route.ts, the conditional check for modelId === 'gpt-image-1' is correct and uses the OpenAI client directly to handle this advanced model, while other models like 'dall-e-2' and 'dall-e-3' use the AI SDK. This implementation pattern is appropriate for handling different model capabilities.

Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 504
File: apps/masterbots.ai/app/api/generate-images/route.ts:58-80
Timestamp: 2025-06-10T05:48:25.508Z
Learning: GPT-Image-1 is a legitimate and advanced OpenAI image generation model released in March 2025 as the successor to DALL·E 3. It's built on the multimodal GPT-4o architecture and supports enhanced capabilities including: up to 4096×4096 resolution, improved text rendering, image-to-image generation, inpainting/editing, multiple output formats (PNG, JPEG, WebP), transparent/opaque backgrounds, and both b64_json and URL response formats. It should be used with the OpenAI client directly rather than the experimental AI SDK for full feature support.

Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 542
File: apps/web/components/layout/profile/layout.tsx:67-68
Timestamp: 2025-08-29T20:34:24.433Z
Learning: AndlerRL prefers skeleton loading states over conditional rendering for better UX when components are waiting for data to load. Components should show loading indicators rather than blank spaces.

Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-09-04T21:31:18.830Z
Learning: Successfully created comprehensive GitHub issue #555 consolidating performance feedback and edge-case management for pro-web workspace features, including prioritized action items, testing requirements, and specific file references for implementation.

@derianrddev derianrddev requested a review from AndlerRL November 14, 2025 17:41
Copy link
Member

@AndlerRL AndlerRL left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good! The approach of creating these images is very nice and consistent, I would suggest though improve the API definition when generating images.

There is a Vercel request size limit in the API routes with templates/ref images could easily scale the request size hence, we need to be a bit creative on how to send the request base64 strings for AI analysis.

As is, for now, it would be nice to start preparing the API to add such amount of files. I made a comment with a suggestion approach to solve this limitation problem.

Comment on lines +86 to +107
const contentParts: Array<{
text?: string
inlineData?: { mimeType: string; data: string }
}> = []

// Add prompt
contentParts.push({ text: prompt })

// Add previous image if in edit mode
if (editMode && previousImage) {
// Remove data URL prefix if present
const base64Data = previousImage.includes('base64,')
? previousImage.split('base64,')[1]
: previousImage

contentParts.push({
inlineData: {
mimeType: 'image/png',
data: base64Data,
},
})
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@coderabbitai I think by default the LLMs returns a PNG file hence, various file forms won't happen—UNLESS we activate the "library" feature, there if we need to add reference files, we must pass the base64 string to the request. Also happens with the templates if user starts from one.

⚠️ It is highly suggested that ref images executes in a server action, a major limitation in the NextJS API routes is that we cannot send more than 2.5/3mb per request and some files may weight more than that. It is easier server actions to execute these or use these server actions to create a cache with a checksum (computeChecksum fn) to then request this temp cache to the API request and send it to the googleAI client.

cc - @derianrddev

Comment on lines +109 to +112
const response = await googleAI.models.generateContent({
model: modelId,
contents: contentParts,
})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to pass the frame to create the closest framing of the chosen template.

…pace

- Add new API route to fetch available media templates from the filesystem.
- Update MediaWorkspace component to load templates on mount and manage loading state.
- Refactor SelectTemplateStep to display templates with loading and empty states.
- Enhance SelectSizeStep with ScrollArea for better usability.
- Introduce helper functions for template parsing and filtering by frame and social media.
- Update context to include openTemplates action for dialog management.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
apps/pro-web/app/api/media/templates/route.ts (1)

14-36: Consider adding a caching layer for template scanning.

The route scans the filesystem on every request, which is unnecessary for static template files that change infrequently. For improved performance and reduced I/O:

Consider one of these approaches:

  1. Next.js ISR: Mark the route as static with revalidation:
export const revalidate = 3600 // revalidate every hour
  1. In-memory cache: Add a simple cache with a TTL
  2. Build-time generation: Move to a static JSON file generated at build time if templates are truly static

Given that templates are likely updated during deployments rather than at runtime, option 1 (ISR) would provide the best balance of freshness and performance.

apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx (2)

62-81: Template fetching should include cleanup.

The fetch in useEffect lacks an abort controller, which can cause warnings if the component unmounts before the fetch completes. While the TODO mentions migrating to TanStack Query, adding cleanup would be a quick improvement:

 useEffect(() => {
+  const abortController = new AbortController()
+
   async function fetchTemplates() {
     try {
       setIsLoadingTemplates(true)
-      const response = await fetch('/api/media/templates')
+      const response = await fetch('/api/media/templates', {
+        signal: abortController.signal
+      })
       if (!response.ok) {
         throw new Error('Failed to fetch templates')
       }
       const templates: Template[] = await response.json()
       setAllTemplates(templates)
     } catch (error) {
+      if (error.name === 'AbortError') return
       console.error('Error fetching templates:', error)
       setAllTemplates([])
     } finally {
       setIsLoadingTemplates(false)
     }
   }

   fetchTemplates()
+
+  return () => abortController.abort()
 }, [])

197-199: Use stable function references for event handlers.

Lines 197-199 and 216-218 use inline arrow functions for onClick, which violates the coding guideline to avoid inline arrows in JSX props. Even for placeholder TODO handlers, use stable references:

As per coding guidelines.

+ const handleSocialMediaClick = () => {
+   // TODO: Implement social media action
+ }
+
+ const handleBrandKitClick = () => {
+   // TODO: Implement brand kit action
+ }
+
  {/* Social Media Button */}
  <Tooltip>
    <TooltipTrigger asChild>
      <Button
        variant="ghost"
        size="icon"
        className="rounded-full w-9 h-9 lg:w-10 lg:h-10 bg-pink-500 hover:bg-pink-600 transition-colors shrink-0"
-       onClick={() => {
-         /* TODO: Implement social media action */
-       }}
+       onClick={handleSocialMediaClick}
      >
        <Instagram className="w-4 h-4 lg:w-5 lg:h-5 text-white" />
      </Button>
    </TooltipTrigger>
    {/* ... */}
  </Tooltip>
  
  {/* Brand Kit Button */}
  <Tooltip>
    <TooltipTrigger asChild>
      <Button
        variant="ghost"
        size="icon"
        className="rounded-full w-9 h-9 lg:w-10 lg:h-10 bg-orange-500 hover:bg-orange-600 transition-colors shrink-0"
-       onClick={() => {
-         /* TODO: Implement brand kit action */
-       }}
+       onClick={handleBrandKitClick}
      >
        <Palette className="w-4 h-4 lg:w-5 lg:h-5 text-white" />
      </Button>
    </TooltipTrigger>
    {/* ... */}
  </Tooltip>

Also applies to: 216-218

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 73e2143 and d511f82.

⛔ Files ignored due to path filters (41)
  • apps/pro-web/public/templates/Aesthetic-Crumpled Paper-Quote_instagram-video_9-16.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Aesthetic-Summer -Memories_instagram-reel_9-16.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Backlit-Beach-Calm-Motivational-Quote_tiktok-video_9-16.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Beige-Minimal-Positive Quote_twitter-post_16-9.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Black-&-Gray-Minimalist-Phone Mockup_pinterest-pin_2-3.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Black-&-Yellow Modern-Technology_instagram-story_9-16.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Black-Blue-Simple-Technology_linkedIn-ad_1-1.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Blue-&-Orange-Gradient-Mindfulness_instagram-story_9-16.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Blue-&-White-Minimalist-Motivation Quotes_pinterest pin_2-3.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Blue-Aesthetic-Vintage-Motivational-Quote_instagram-story_9-16.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Blue-Black-Vintage-Retro-Film-Video-Centric-The-Beggining-Animated_instagram-reel_9-16.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Blue-Minimalist-Sea Travel-Motivational_instagram-video_9-16.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Blue-Modern-Marketing-Live-Webinar-Meetup-Promotion_facebook ad_21-11.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Blue-Vintage-Cinematic_instagram-reel_9-16.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Brown-&-Green-Elegant-Curved-Frames-&-Border-Business-&-Entrepreneurship-Fundraising_twitter-post_16-9.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Brown-Beige-Pink-Scrapbooking-Book-Review_pinterest-pin_2-3.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Dark-Blue-Minimalist-Gradient-Daily-Tips-Inspiration_instagram-post_4-5.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Darkslate-Green-Modern-Save-Date-Promotional-Animated_twitter-ad_1-1.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Gradient-Orange-Daily-Reminder-Quotes_instagram-story_9-16.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Green-&-Orange-Modern-Creative-Online-Course_linkedIn-ad_1-1.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Green-&-White-Minimal-Modern-Simple-Typography-Art-Workshop_instagram-story_9-16.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Green-Modern-Minimalist-Basic-Daily-Reminder-Animated_instagram-post_1-1.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Green-Modern-Money-Management-Mobile-App-Promotion_facebook-ad_21-11.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Hot-Pink-Neon-Retro-TV-Glitch-Quote-Animated_twitter-post_1-1.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Kinetic-Typography_linkedin-video_1-1.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Light-Blue-&-Beige-Professional-Modern-New-Message Notification-Mobile-Mockup_tiktok-video_9-16.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Light-Blue-Gradient-Festive-Flat-Illustration-Quote_pinterest-pin_9-16.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Minimal-Aesthetic-Camera-Focus-Beach-Asmr-Vlog_tiktok-video_9-16.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Neutral-Minimal-Flower-Bouquet-Photo-Collage-Your-Story_instagram-reel_9-16.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Orange-&-Blue-Modern-Minimalist-We Are-Open-Coffee-Shop_instagram-post_4-5.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Orange-Minimalist-Bold-Motivational_facebook-post_5-4.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Orange-Motivational-Frase-Natural_facebook-post_1-1.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Photo-Video-Dump-Travel-Personal-Retro Cinematic-Style_tiktok -video_9-16.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Purple-&-White-Gradient-Modern-Quote_instagram-post_4-5.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Purple-&-White-Modern-Business-Conference_facebook-ad_21-11.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Purple-White-Quote-Of-The-Day-Animated_twitter-ad_1-1.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Team-Kudos-&-Company-Milestones-Tech-Style_linkedin-ad_1-1.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Team-Member-Birthday-Simple Professional-Style_linkedin-post_1-1.png is excluded by !**/*.png
  • apps/pro-web/public/templates/White-&-Yellow-Vintage-Old-Film-Vacation-Vlog_instagram-reel_9-16.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Yellow-&-Black-Colour-Bold-Quote_facebook-post_5-4.png is excluded by !**/*.png
  • apps/pro-web/public/templates/Yellow-Bold-Summer_ instagram-reel_9-16.png is excluded by !**/*.png
📒 Files selected for processing (7)
  • apps/pro-web/app/api/media/templates/route.ts (1 hunks)
  • apps/pro-web/components/routes/workspace/media-tab/media-tab-wrapper.tsx (0 hunks)
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx (5 hunks)
  • apps/pro-web/components/routes/workspace/media-tab/steps/select-size-step.tsx (1 hunks)
  • apps/pro-web/components/routes/workspace/media-tab/steps/select-template-step.tsx (1 hunks)
  • apps/pro-web/lib/helpers/workspace/media.ts (1 hunks)
  • apps/pro-web/lib/hooks/use-workspace-media.tsx (1 hunks)
💤 Files with no reviewable changes (1)
  • apps/pro-web/components/routes/workspace/media-tab/media-tab-wrapper.tsx
🧰 Additional context used
📓 Path-based instructions (10)
apps/{web,pro-web}/components/routes/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Place page-specific components under components/routes/[feature]/

Organize page-specific components under components/routes/

Files:

  • apps/pro-web/components/routes/workspace/media-tab/steps/select-size-step.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
  • apps/pro-web/components/routes/workspace/media-tab/steps/select-template-step.tsx
apps/{web,pro-web}/**/*.tsx

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

apps/{web,pro-web}/**/*.tsx: Declare React components with the function keyword
Name React components using PascalCase
Order component files: imports → constants → component → styled components → types/interfaces
Use functional components and hooks; type props with a TypeScript interface
Use regular function references (not inline arrows) for React event handlers to avoid extra re-renders

apps/{web,pro-web}/**/*.tsx: Use regular function references for event handlers instead of inline arrow functions in JSX
Declare React components with the function keyword (function ComponentName() {})
Use PascalCase for React component names
Order React component files: imports, constants, component, styled components, types/interfaces
Style components with Tailwind CSS utility classes

Files:

  • apps/pro-web/components/routes/workspace/media-tab/steps/select-size-step.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
  • apps/pro-web/lib/hooks/use-workspace-media.tsx
  • apps/pro-web/components/routes/workspace/media-tab/steps/select-template-step.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Avoid default exports; prefer named exports
Use meaningful variable names; prefix booleans with is/has/does/should
Use interface for objects/classes; type for unions/tuples/aliases; enum for fixed sets; const for literals
Avoid any; prefer specific types
Leverage type inference where clear; annotate function params and return types
Prefer type assertions with 'as' over angle-bracket syntax
Use type guards to narrow types in conditionals

**/*.{ts,tsx}: Avoid default exports; prefer named exports
Use modern JavaScript features with TypeScript across the codebase
Use meaningful names; prefix booleans with is/has/does/should (e.g., isDisabled)
Receive an object and return an object (RORO) for functions interfacing with external services
Type definitions: use interface for objects/classes; type for unions/tuples/aliases; const for literals; enum for fixed sets
Avoid any; prefer specific types
Leverage type inference; omit explicit annotations when obvious
Add explicit type annotations for function parameters and return values
Prefer type assertions with as over angle-bracket syntax
Use type guards to narrow types within conditionals
Favor composition over inheritance in code structure

**/*.{ts,tsx}: Avoid default exports; prefer named exports
Prefer RORO (Receive an object, return an object) for function signatures, especially for external service interactions
Use interface for object shapes/classes; type for unions/tuples/aliases; const for literals; enum for fixed enumerations
Avoid using any; prefer precise types
Leverage type inference when clear; omit redundant annotations
Explicitly annotate function parameters and return types
Prefer type assertions with as over angle-bracket syntax
Use type guards to narrow types safely
Use meaningful variable names; prefix booleans with is/has/does/should
Favor composition over inheritance
Use lowercase dash-separated names for files and folders; use extensions like .config.ts, .test.ts, .context.tsx, .typ...

Files:

  • apps/pro-web/components/routes/workspace/media-tab/steps/select-size-step.tsx
  • apps/pro-web/lib/helpers/workspace/media.ts
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
  • apps/pro-web/lib/hooks/use-workspace-media.tsx
  • apps/pro-web/components/routes/workspace/media-tab/steps/select-template-step.tsx
  • apps/pro-web/app/api/media/templates/route.ts
apps/{web,pro-web}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

apps/{web,pro-web}/**/*.{ts,tsx}: Use lowercase kebab-case for directories and filenames (components can omit extension)
Verify DOM operations and consider timing (RAF/delays) when manipulating the DOM in React
Use Tailwind CSS utility classes for styling React components

apps/{web,pro-web}/**/*.{ts,tsx}: Use TypeScript to define React props types (interfaces for props)
Use custom hooks (useMBChat, useThread, useSidebar, useModel) for domain-specific state and keep providers focused and composed hierarchically
Separate presentation from business logic and compose small components
Use hasura.service.ts for all GraphQL operations from UI layers

apps/{web,pro-web}/**/*.{ts,tsx}: Prefer Server Components; use the use client directive only when client-side features are required
Implement Nested Layouts using the App Router
Use Streaming and Suspense in Next.js 14/15 where appropriate
Follow Next.js file conventions as per documentation
Use IndexedDB for local caching to enable immediate UI updates

Files:

  • apps/pro-web/components/routes/workspace/media-tab/steps/select-size-step.tsx
  • apps/pro-web/lib/helpers/workspace/media.ts
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
  • apps/pro-web/lib/hooks/use-workspace-media.tsx
  • apps/pro-web/components/routes/workspace/media-tab/steps/select-template-step.tsx
  • apps/pro-web/app/api/media/templates/route.ts
**/*

📄 CodeRabbit inference engine (CLAUDE.md)

**/*: Use lowercase with dash-separated directory and file names; use specific extensions: .config.ts, .test.ts, .context.tsx, .type.ts, .hook.ts; components may omit extension
Use Bun for package management and scripts instead of npm/yarn
Use Biome for formatting and linting via bun format-and-lint:fix; avoid Prettier/ESLint configs

Files:

  • apps/pro-web/components/routes/workspace/media-tab/steps/select-size-step.tsx
  • apps/pro-web/lib/helpers/workspace/media.ts
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
  • apps/pro-web/lib/hooks/use-workspace-media.tsx
  • apps/pro-web/components/routes/workspace/media-tab/steps/select-template-step.tsx
  • apps/pro-web/app/api/media/templates/route.ts
**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

**/*.tsx: Avoid inline arrow functions in JSX props; use stable function references for event handlers
Declare React components with the function keyword (functional components)
Use PascalCase for React component names
Use functional components and hooks instead of class components
Type component props with TypeScript interfaces

Files:

  • apps/pro-web/components/routes/workspace/media-tab/steps/select-size-step.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
  • apps/pro-web/lib/hooks/use-workspace-media.tsx
  • apps/pro-web/components/routes/workspace/media-tab/steps/select-template-step.tsx
apps/{web,pro-web}/components/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Order component files: imports → constants → component → styled components → types/interfaces

Files:

  • apps/pro-web/components/routes/workspace/media-tab/steps/select-size-step.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
  • apps/pro-web/components/routes/workspace/media-tab/steps/select-template-step.tsx
apps/{web,pro-web}/lib/hooks/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

apps/{web,pro-web}/lib/hooks/**: Place custom React hooks under lib/hooks/
Encapsulate complex state in custom hooks and separate presentation from business logic

Store custom React hooks under lib/hooks/

Files:

  • apps/pro-web/lib/hooks/use-workspace-media.tsx
apps/{web,pro-web}/lib/hooks/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Place custom React hooks in lib/hooks/

Files:

  • apps/pro-web/lib/hooks/use-workspace-media.tsx
apps/{web,pro-web}/app/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

apps/{web,pro-web}/app/**: Prefer Next.js Server Components; use 'use client' only when necessary
Leverage Streaming and Suspense for responsiveness in Next.js 15
Follow Next.js file conventions in the App Router

apps/{web,pro-web}/app/**: Leverage Server Components by default; use the use client directive only when client-side features are needed
Implement Nested Layouts using the App Router
Use Streaming and Suspense features in Next.js 14/15 where appropriate
Follow Next.js file conventions for routing and layout in the App Router
Optimize data fetching: fetch on the server, fetch where needed, and use preload patterns to avoid waterfalls

Files:

  • apps/pro-web/app/api/media/templates/route.ts
🧠 Learnings (21)
📓 Common learnings
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 584
File: apps/pro-web/app/api/generate-images/route.ts:86-107
Timestamp: 2025-11-14T19:14:07.226Z
Learning: In apps/pro-web/app/api/generate-images/route.ts, the hardcoded 'image/png' MIME type for Gemini previousImage is intentional—LLM-generated images are PNG by default. When the library/template features are added (allowing user-uploaded reference images), the architecture should use Next.js server actions with checksum-based caching (computeChecksum fn) to handle files larger than the 2.5-3MB API route limit, rather than detecting MIME types in the API route directly.
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 504
File: apps/masterbots.ai/app/api/generate-images/route.ts:58-80
Timestamp: 2025-06-10T05:48:25.508Z
Learning: GPT-Image-1 is a legitimate and advanced OpenAI image generation model released in March 2025 as the successor to DALL·E 3. It's built on the multimodal GPT-4o architecture and supports enhanced capabilities including: up to 4096×4096 resolution, improved text rendering, image-to-image generation, inpainting/editing, multiple output formats (PNG, JPEG, WebP), transparent/opaque backgrounds, and both b64_json and URL response formats. It should be used with the OpenAI client directly rather than the experimental AI SDK for full feature support.
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-09-04T21:31:18.830Z
Learning: Successfully created comprehensive GitHub issue #555 consolidating performance feedback and edge-case management for pro-web workspace features, including prioritized action items, testing requirements, and specific file references for implementation.
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 504
File: apps/masterbots.ai/app/api/generate-images/route.ts:58-80
Timestamp: 2025-06-10T05:48:25.508Z
Learning: In apps/masterbots.ai/app/api/generate-images/route.ts, the conditional check for modelId === 'gpt-image-1' is correct and uses the OpenAI client directly to handle this advanced model, while other models like 'dall-e-2' and 'dall-e-3' use the AI SDK. This implementation pattern is appropriate for handling different model capabilities.
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Pro workspace editors: controlled/uncontrolled patterns, Markdown utilities, section state sync, and timed DOM operations

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-11-14T19:14:07.226Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 584
File: apps/pro-web/app/api/generate-images/route.ts:86-107
Timestamp: 2025-11-14T19:14:07.226Z
Learning: In apps/pro-web/app/api/generate-images/route.ts, the hardcoded 'image/png' MIME type for Gemini previousImage is intentional—LLM-generated images are PNG by default. When the library/template features are added (allowing user-uploaded reference images), the architecture should use Next.js server actions with checksum-based caching (computeChecksum fn) to handle files larger than the 2.5-3MB API route limit, rather than detecting MIME types in the API route directly.

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
  • apps/pro-web/lib/hooks/use-workspace-media.tsx
  • apps/pro-web/app/api/media/templates/route.ts
📚 Learning: 2025-06-10T05:48:25.508Z
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 504
File: apps/masterbots.ai/app/api/generate-images/route.ts:58-80
Timestamp: 2025-06-10T05:48:25.508Z
Learning: In apps/masterbots.ai/app/api/generate-images/route.ts, the conditional check for modelId === 'gpt-image-1' is correct and uses the OpenAI client directly to handle this advanced model, while other models like 'dall-e-2' and 'dall-e-3' use the AI SDK. This implementation pattern is appropriate for handling different model capabilities.

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-06-13T08:55:45.217Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 508
File: apps/masterbots.ai/lib/helpers/ai-helpers.ts:280-283
Timestamp: 2025-06-13T08:55:45.217Z
Learning: In `apps/masterbots.ai/lib/helpers/ai-helpers.ts` the `verifyDuplicateMessage` function should:
• Use `message.content` as the sole de-duplication key so provisional (no-slug) and persisted (slugged) messages merge properly.
• Return the full `message` object (not just a string key) for the continuation prompts (`CONTINUE_GENERATION_PROMPT`, `CONTINUE_GENERATION_PROMPT_2`) because their content repeats and they must remain distinct.
• No explicit `!message.content` guard is needed; `return message.content` already yields `undefined` when content is missing.

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to **/*.tsx : Avoid inline arrow functions in JSX props; use stable function references for event handlers

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to apps/{web,pro-web}/**/*.tsx : Use regular function references (not inline arrows) for React event handlers to avoid extra re-renders

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-02-17T16:51:19.102Z
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 376
File: apps/masterbots.ai/components/routes/chat/chat.tsx:92-102
Timestamp: 2025-02-17T16:51:19.102Z
Learning: For the Chat component in apps/masterbots.ai/components/routes/chat/chat.tsx, the developer prefers to verify potential optimizations through local testing before accepting suggestions, particularly for performance-related changes like useCallback usage in debounce implementations.

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Verify DOM operations and consider timing (RAF/delays) when manipulating the DOM in React

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2024-11-20T04:00:45.413Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 300
File: apps/masterbots.ai/components/routes/thread/user-thread-panel.tsx:120-123
Timestamp: 2024-11-20T04:00:45.413Z
Learning: In React code, when reviewing `useEffect` dependencies, it's not always necessary to add functions like `handleThreadsChange` to the dependency array, as this may lead to unnecessary re-renders and performance issues. Only include dependencies that are essential and may change.

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/**/*.tsx : Use regular function references for event handlers instead of inline arrow functions in JSX

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to apps/{web,pro-web}/**/*.tsx : Use functional components and hooks; type props with a TypeScript interface

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to **/*.tsx : Use functional components and hooks instead of class components

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2024-10-23T00:00:06.253Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 287
File: apps/masterbots.ai/components/routes/chat/share-button.tsx:10-29
Timestamp: 2024-10-23T00:00:06.253Z
Learning: When implementing the `handleShare` function in `apps/masterbots.ai/components/routes/chat/share-button.tsx`, prefer using modern APIs like the Clipboard API over deprecated methods like `document.execCommand('copy')`, as the project no longer needs to support very old web browsers.

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/**/*.tsx : Declare React components with the function keyword (function ComponentName() {})

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2024-11-28T18:54:45.949Z
Learnt from: sheriffjimoh
Repo: bitcashorg/masterbots PR: 313
File: apps/masterbots.ai/components/layout/sidebar/sidebar-link.tsx:150-151
Timestamp: 2024-11-28T18:54:45.949Z
Learning: When handling navigation programmatically in the application, prefer using `<button>` elements instead of `Link` components to prevent unintended page reloads caused by default link behavior.

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2024-10-03T20:10:44.311Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 276
File: apps/masterbots.ai/app/wordware/layout.tsx:12-19
Timestamp: 2024-10-03T20:10:44.311Z
Learning: In `apps/masterbots.ai/app/wordware/layout.tsx`, the current layout is intentional to prevent layout issues such as unwanted gaps and sidebar design problems. A similar design is used in `apps/c/layout`.

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Use custom hooks (useMBChat, useThread, useSidebar, useModel) for domain-specific state and keep providers focused and composed hierarchically

Applied to files:

  • apps/pro-web/lib/hooks/use-workspace-media.tsx
📚 Learning: 2024-10-23T07:33:36.041Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 287
File: apps/masterbots.ai/lib/hooks/use-thread-visibility.tsx:3-3
Timestamp: 2024-10-23T07:33:36.041Z
Learning: Always use explicit imports for React hooks to maintain consistency across the monorepo, and avoid using both named and default imports simultaneously.

Applied to files:

  • apps/pro-web/lib/hooks/use-workspace-media.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to apps/{web,pro-web}/components/shared/**/*.{ts,tsx} : Store reusable UI elements in components/shared/

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/steps/select-template-step.tsx
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to apps/{web,pro-web}/**/*.tsx : Order component files: imports → constants → component → styled components → types/interfaces

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/steps/select-template-step.tsx
🧬 Code graph analysis (4)
apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx (5)
apps/pro-web/lib/helpers/workspace/media.ts (2)
  • Template (1-8)
  • getFrameSizeFromTemplate (155-177)
apps/pro-web/lib/hooks/use-workspace-media.tsx (1)
  • useWorkspaceMedia (181-189)
apps/pro-web/components/ui/wizard/index.tsx (1)
  • WizardStep (23-26)
apps/pro-web/components/routes/workspace/media-tab/steps/select-template-step.tsx (1)
  • SelectTemplateStep (12-109)
apps/pro-web/components/shared/image-display.tsx (1)
  • ImageDisplay (22-188)
apps/pro-web/lib/hooks/use-workspace-media.tsx (4)
apps/pro-web/types/index.ts (1)
  • ImageModel (450-450)
apps/pro-web/lib/helpers/workspace/media.ts (2)
  • Template (1-8)
  • imageUrlToBase64 (16-35)
apps/pro-web/components/routes/workspace/media-tab/steps/select-size-step.tsx (1)
  • FrameSize (5-11)
apps/pro-web/lib/hooks/use-image-generation.tsx (1)
  • useImageGeneration (18-175)
apps/pro-web/components/routes/workspace/media-tab/steps/select-template-step.tsx (2)
apps/pro-web/components/ui/wizard/index.tsx (1)
  • WizardStepProps (14-21)
apps/pro-web/lib/helpers/workspace/media.ts (1)
  • Template (1-8)
apps/pro-web/app/api/media/templates/route.ts (1)
apps/pro-web/lib/helpers/workspace/media.ts (2)
  • Template (1-8)
  • parseTemplateFilename (44-71)
🔇 Additional comments (21)
apps/pro-web/app/api/media/templates/route.ts (1)

37-53: LGTM: Graceful error handling.

The error handling strategy is sound—returning an empty array with Sentry logging ensures the UI remains functional even when template loading fails, while still capturing the error for monitoring.

apps/pro-web/lib/hooks/use-workspace-media.tsx (5)

9-48: LGTM: Well-structured context types.

The separation of state and actions into distinct interfaces provides clear organization, and the use of specific string literal types for dialogStep prevents invalid states.


72-77: Model resolution logic is correct.

The resolveImageModel function correctly maps image presence to model selection (Gemini for edits, GPT for new generation), and selectedModel accurately reflects the current state.


97-113: Template-to-base64 conversion is well-structured.

The conditional conversion of template images to base64 before generation is properly handled with error recovery. The hardcoded provider: 'google' at line 106 aligns with the model selection logic (Gemini when base image exists).

Based on learnings.


118-137: LGTM: Action handlers correctly update state.

The action handlers appropriately update dialog and UI state. The TODO in uploadMedia is acceptable for future implementation.


139-189: LGTM: Standard context provider pattern.

The provider correctly exposes all state and actions, and the hook includes proper error handling for usage outside the provider.

As per coding guidelines.

apps/pro-web/components/routes/workspace/media-tab/steps/select-size-step.tsx (1)

18-88: LGTM: Improved layout with sticky sections.

The refactored three-section layout (sticky header, scrollable body, sticky footer) provides better UX on long lists. The responsive sizing and dark mode support are well-implemented.

apps/pro-web/components/routes/workspace/media-tab/steps/select-template-step.tsx (3)

32-48: LGTM: Loading and empty states provide clear feedback.

The loading spinner and empty state messaging ensure users understand the current state of the template selection interface.


50-101: LGTM: Accessible template cards with good hover affordances.

The use of semantic button elements with aria-label improves accessibility, and the hover effects (overlay, badges, name pill) provide clear visual feedback.

As per coding guidelines.


61-70: LGTM: Proper image handling with fallback.

The conditional rendering with a gradient fallback and loading="lazy" attribute provides both resilience and performance.

apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx (6)

107-132: LGTM: Auto-size selection improves UX.

The automatic frame size selection based on the template's frame ratio (lines 119-123) is a thoughtful UX improvement that reduces user friction.


162-166: LGTM: Reset logic prevents stale generated images.

The effect correctly resets the generated image when the user changes templates or sizes, ensuring consistency. The biome-ignore comment documents the intentional behavior.


235-245: LGTM: Clear call-to-action in placeholder state.

The placeholder card effectively guides users to the Templates or Social Media buttons to begin their workflow.


247-277: Canvas rendering supports multiple aspect ratios.

The dynamic aspect ratio classes (lines 252-275) correctly handle all frame sizes defined in the frameSizes array, with responsive sizing constraints.


312-349: LGTM: Loading and error states provide clear feedback and recovery.

The loading overlay with conditional messaging (generation vs. update) and the error overlay with retry functionality enhance the user experience during image generation.


526-584: LGTM: Comprehensive frame sizes with platform mappings.

The frame size definitions cover a wide range of social media and design use cases, with clear descriptions mapping each to specific platforms.

apps/pro-web/lib/helpers/workspace/media.ts (5)

1-8: LGTM: Clear and focused Template interface.

The interface includes all necessary fields for template identification, display, and rendering.


16-35: LGTM: Base64 conversion properly strips data URL prefix.

The function correctly converts images to base64 and removes the data URL prefix as documented, which is required for API submission.

Based on learnings.


44-71: LGTM: Robust filename parsing with validation.

The parsing logic correctly handles the expected template filename format and gracefully returns null for invalid inputs with a warning.


80-118: LGTM: Filter functions provide flexible querying.

The frame filter correctly maps UI frame IDs to template frame values, and the social media filter's case-insensitive comparison improves robustness.


155-177: LGTM: Mapping function provides appropriate fallbacks.

The getFrameSizeFromTemplate function includes both a matched size lookup and fallback to the first available size, ensuring graceful handling of unknown frame ratios.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
apps/pro-web/components/ui/wizard/index.tsx (2)

61-78: Conditional progress bar rendering looks good; consider guarding percent for empty steps

The change to only show the progress UI when there are multiple steps (total > 1) is sensible and avoids noisy chrome for single-step flows. One small defensive improvement: if steps is ever misconfigured as an empty array, percent will become Infinity/NaN due to division by zero.

You can make this safe without changing behavior for valid wizards:

-	const total = steps.length
-	const percent = Math.round(((currentStep + 1) / total) * 100)
+	const total = steps.length
+	const percent = total > 0 ? Math.round(((currentStep + 1) / total) * 100) : 0

This keeps current behavior for total >= 1 and avoids surprising runtime values if steps is empty.


139-139: Align export style with repo guideline (prefer named exports over default)

The component is currently exported as a default export. To match the codebase guideline of preferring named exports, consider switching to:

-const DialogWizard: React.FC<DialogWizardProps> = ({
+export const DialogWizard: React.FC<DialogWizardProps> = ({
   // ...
 }) => {
   // ...
-}
-
-export default DialogWizard
+}

This is non-urgent but will bring the file in line with the shared TypeScript/React conventions.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d511f82 and f7974ea.

📒 Files selected for processing (1)
  • apps/pro-web/components/ui/wizard/index.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (8)
apps/{web,pro-web}/**/*.tsx

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

apps/{web,pro-web}/**/*.tsx: Declare React components with the function keyword
Name React components using PascalCase
Order component files: imports → constants → component → styled components → types/interfaces
Use functional components and hooks; type props with a TypeScript interface
Use regular function references (not inline arrows) for React event handlers to avoid extra re-renders

apps/{web,pro-web}/**/*.tsx: Use regular function references for event handlers instead of inline arrow functions in JSX
Declare React components with the function keyword (function ComponentName() {})
Use PascalCase for React component names
Order React component files: imports, constants, component, styled components, types/interfaces
Style components with Tailwind CSS utility classes

Files:

  • apps/pro-web/components/ui/wizard/index.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Avoid default exports; prefer named exports
Use meaningful variable names; prefix booleans with is/has/does/should
Use interface for objects/classes; type for unions/tuples/aliases; enum for fixed sets; const for literals
Avoid any; prefer specific types
Leverage type inference where clear; annotate function params and return types
Prefer type assertions with 'as' over angle-bracket syntax
Use type guards to narrow types in conditionals

**/*.{ts,tsx}: Avoid default exports; prefer named exports
Use modern JavaScript features with TypeScript across the codebase
Use meaningful names; prefix booleans with is/has/does/should (e.g., isDisabled)
Receive an object and return an object (RORO) for functions interfacing with external services
Type definitions: use interface for objects/classes; type for unions/tuples/aliases; const for literals; enum for fixed sets
Avoid any; prefer specific types
Leverage type inference; omit explicit annotations when obvious
Add explicit type annotations for function parameters and return values
Prefer type assertions with as over angle-bracket syntax
Use type guards to narrow types within conditionals
Favor composition over inheritance in code structure

**/*.{ts,tsx}: Avoid default exports; prefer named exports
Prefer RORO (Receive an object, return an object) for function signatures, especially for external service interactions
Use interface for object shapes/classes; type for unions/tuples/aliases; const for literals; enum for fixed enumerations
Avoid using any; prefer precise types
Leverage type inference when clear; omit redundant annotations
Explicitly annotate function parameters and return types
Prefer type assertions with as over angle-bracket syntax
Use type guards to narrow types safely
Use meaningful variable names; prefix booleans with is/has/does/should
Favor composition over inheritance
Use lowercase dash-separated names for files and folders; use extensions like .config.ts, .test.ts, .context.tsx, .typ...

Files:

  • apps/pro-web/components/ui/wizard/index.tsx
apps/{web,pro-web}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

apps/{web,pro-web}/**/*.{ts,tsx}: Use lowercase kebab-case for directories and filenames (components can omit extension)
Verify DOM operations and consider timing (RAF/delays) when manipulating the DOM in React
Use Tailwind CSS utility classes for styling React components

apps/{web,pro-web}/**/*.{ts,tsx}: Use TypeScript to define React props types (interfaces for props)
Use custom hooks (useMBChat, useThread, useSidebar, useModel) for domain-specific state and keep providers focused and composed hierarchically
Separate presentation from business logic and compose small components
Use hasura.service.ts for all GraphQL operations from UI layers

apps/{web,pro-web}/**/*.{ts,tsx}: Prefer Server Components; use the use client directive only when client-side features are required
Implement Nested Layouts using the App Router
Use Streaming and Suspense in Next.js 14/15 where appropriate
Follow Next.js file conventions as per documentation
Use IndexedDB for local caching to enable immediate UI updates

Files:

  • apps/pro-web/components/ui/wizard/index.tsx
apps/{web,pro-web}/components/ui/**

📄 CodeRabbit inference engine (CLAUDE.md)

Follow Radix UI patterns for UI components in components/ui/

Files:

  • apps/pro-web/components/ui/wizard/index.tsx
**/*

📄 CodeRabbit inference engine (CLAUDE.md)

**/*: Use lowercase with dash-separated directory and file names; use specific extensions: .config.ts, .test.ts, .context.tsx, .type.ts, .hook.ts; components may omit extension
Use Bun for package management and scripts instead of npm/yarn
Use Biome for formatting and linting via bun format-and-lint:fix; avoid Prettier/ESLint configs

Files:

  • apps/pro-web/components/ui/wizard/index.tsx
**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

**/*.tsx: Avoid inline arrow functions in JSX props; use stable function references for event handlers
Declare React components with the function keyword (functional components)
Use PascalCase for React component names
Use functional components and hooks instead of class components
Type component props with TypeScript interfaces

Files:

  • apps/pro-web/components/ui/wizard/index.tsx
apps/{web,pro-web}/components/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Order component files: imports → constants → component → styled components → types/interfaces

Files:

  • apps/pro-web/components/ui/wizard/index.tsx
apps/{web,pro-web}/components/ui/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Follow Radix UI patterns under components/ui/

Files:

  • apps/pro-web/components/ui/wizard/index.tsx
🧠 Learnings (2)
📓 Common learnings
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-09-04T21:31:18.830Z
Learning: Successfully created comprehensive GitHub issue #555 consolidating performance feedback and edge-case management for pro-web workspace features, including prioritized action items, testing requirements, and specific file references for implementation.
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 584
File: apps/pro-web/app/api/generate-images/route.ts:86-107
Timestamp: 2025-11-14T19:14:07.226Z
Learning: In apps/pro-web/app/api/generate-images/route.ts, the hardcoded 'image/png' MIME type for Gemini previousImage is intentional—LLM-generated images are PNG by default. When the library/template features are added (allowing user-uploaded reference images), the architecture should use Next.js server actions with checksum-based caching (computeChecksum fn) to handle files larger than the 2.5-3MB API route limit, rather than detecting MIME types in the API route directly.
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 504
File: apps/masterbots.ai/app/api/generate-images/route.ts:58-80
Timestamp: 2025-06-10T05:48:25.508Z
Learning: In apps/masterbots.ai/app/api/generate-images/route.ts, the conditional check for modelId === 'gpt-image-1' is correct and uses the OpenAI client directly to handle this advanced model, while other models like 'dall-e-2' and 'dall-e-3' use the AI SDK. This implementation pattern is appropriate for handling different model capabilities.
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to apps/{web,pro-web}/components/ui/**/*.{ts,tsx} : Follow Radix UI patterns under components/ui/

Applied to files:

  • apps/pro-web/components/ui/wizard/index.tsx

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (1)
apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx (1)

563-563: Use stable function references instead of inline arrow functions.

Lines 563, 571, and 579 use inline arrow functions for handleCloseWizard={() => setDialogStep(null)}, which violates the coding guideline to avoid inline arrows in JSX props. This issue was flagged in previous reviews.

As per coding guidelines.

Define a stable handler once and reuse it:

+	const handleCloseDialog = () => setDialogStep(null)
+
 	return (
 		<div className="flex flex-col lg:flex-row size-full bg-background min-h-0">
 			{/* ... */}
 			
 			{/* Media Selection Wizard - Size Step */}
 			<DialogWizard
 				steps={sizeWizardSteps}
 				dialogOpen={dialogStep === 'size'}
 				headerTitle="Frame Sizes"
-				handleCloseWizard={() => setDialogStep(null)}
+				handleCloseWizard={handleCloseDialog}
 			/>

 			{/* Media Selection Wizard - Template Step */}
 			<DialogWizard
 				steps={templateWizardSteps}
 				dialogOpen={dialogStep === 'template'}
 				headerTitle="Templates"
-				handleCloseWizard={() => setDialogStep(null)}
+				handleCloseWizard={handleCloseDialog}
 			/>

 			{/* Library Wizard */}
 			<DialogWizard
 				steps={librarySteps}
 				dialogOpen={dialogStep === 'library'}
 				headerTitle="Select from Library"
-				handleCloseWizard={() => setDialogStep(null)}
+				handleCloseWizard={handleCloseDialog}
 			/>
 		</div>
 	)

Also applies to: 571-571, 579-579

🧹 Nitpick comments (2)
apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx (2)

61-82: Consider migrating to TanStack Query for template loading.

The TODO comment indicates a planned migration to TanStack Query. This would provide benefits like automatic caching, background refetching, loading/error state management, and better separation of concerns.

Since this is already noted, consider prioritizing this refactor to align with modern React data-fetching patterns and reduce component complexity.


85-85: Add explanation for biome-ignore directive.

The biome-ignore directive on line 85 (and similarly on line 107) lacks an explanation. Biome-ignore comments should clearly document why the rule is being suppressed.

Add a brief explanation:

-	// biome-ignore lint/correctness/useExhaustiveDependencies: <explanation>
+	// biome-ignore lint/correctness/useExhaustiveDependencies: setSelectedSize and setDialogStep are stable setState functions

Also applies to: 107-107

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f7974ea and 2a3b0b0.

📒 Files selected for processing (2)
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx (6 hunks)
  • apps/pro-web/components/routes/workspace/media-tab/reference-upload-slot.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
apps/{web,pro-web}/components/routes/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Place page-specific components under components/routes/[feature]/

Organize page-specific components under components/routes/

Files:

  • apps/pro-web/components/routes/workspace/media-tab/reference-upload-slot.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
apps/{web,pro-web}/**/*.tsx

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

apps/{web,pro-web}/**/*.tsx: Declare React components with the function keyword
Name React components using PascalCase
Order component files: imports → constants → component → styled components → types/interfaces
Use functional components and hooks; type props with a TypeScript interface
Use regular function references (not inline arrows) for React event handlers to avoid extra re-renders

apps/{web,pro-web}/**/*.tsx: Use regular function references for event handlers instead of inline arrow functions in JSX
Declare React components with the function keyword (function ComponentName() {})
Use PascalCase for React component names
Order React component files: imports, constants, component, styled components, types/interfaces
Style components with Tailwind CSS utility classes

Files:

  • apps/pro-web/components/routes/workspace/media-tab/reference-upload-slot.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Avoid default exports; prefer named exports
Use meaningful variable names; prefix booleans with is/has/does/should
Use interface for objects/classes; type for unions/tuples/aliases; enum for fixed sets; const for literals
Avoid any; prefer specific types
Leverage type inference where clear; annotate function params and return types
Prefer type assertions with 'as' over angle-bracket syntax
Use type guards to narrow types in conditionals

**/*.{ts,tsx}: Avoid default exports; prefer named exports
Use modern JavaScript features with TypeScript across the codebase
Use meaningful names; prefix booleans with is/has/does/should (e.g., isDisabled)
Receive an object and return an object (RORO) for functions interfacing with external services
Type definitions: use interface for objects/classes; type for unions/tuples/aliases; const for literals; enum for fixed sets
Avoid any; prefer specific types
Leverage type inference; omit explicit annotations when obvious
Add explicit type annotations for function parameters and return values
Prefer type assertions with as over angle-bracket syntax
Use type guards to narrow types within conditionals
Favor composition over inheritance in code structure

**/*.{ts,tsx}: Avoid default exports; prefer named exports
Prefer RORO (Receive an object, return an object) for function signatures, especially for external service interactions
Use interface for object shapes/classes; type for unions/tuples/aliases; const for literals; enum for fixed enumerations
Avoid using any; prefer precise types
Leverage type inference when clear; omit redundant annotations
Explicitly annotate function parameters and return types
Prefer type assertions with as over angle-bracket syntax
Use type guards to narrow types safely
Use meaningful variable names; prefix booleans with is/has/does/should
Favor composition over inheritance
Use lowercase dash-separated names for files and folders; use extensions like .config.ts, .test.ts, .context.tsx, .typ...

Files:

  • apps/pro-web/components/routes/workspace/media-tab/reference-upload-slot.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
apps/{web,pro-web}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

apps/{web,pro-web}/**/*.{ts,tsx}: Use lowercase kebab-case for directories and filenames (components can omit extension)
Verify DOM operations and consider timing (RAF/delays) when manipulating the DOM in React
Use Tailwind CSS utility classes for styling React components

apps/{web,pro-web}/**/*.{ts,tsx}: Use TypeScript to define React props types (interfaces for props)
Use custom hooks (useMBChat, useThread, useSidebar, useModel) for domain-specific state and keep providers focused and composed hierarchically
Separate presentation from business logic and compose small components
Use hasura.service.ts for all GraphQL operations from UI layers

apps/{web,pro-web}/**/*.{ts,tsx}: Prefer Server Components; use the use client directive only when client-side features are required
Implement Nested Layouts using the App Router
Use Streaming and Suspense in Next.js 14/15 where appropriate
Follow Next.js file conventions as per documentation
Use IndexedDB for local caching to enable immediate UI updates

Files:

  • apps/pro-web/components/routes/workspace/media-tab/reference-upload-slot.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
**/*

📄 CodeRabbit inference engine (CLAUDE.md)

**/*: Use lowercase with dash-separated directory and file names; use specific extensions: .config.ts, .test.ts, .context.tsx, .type.ts, .hook.ts; components may omit extension
Use Bun for package management and scripts instead of npm/yarn
Use Biome for formatting and linting via bun format-and-lint:fix; avoid Prettier/ESLint configs

Files:

  • apps/pro-web/components/routes/workspace/media-tab/reference-upload-slot.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

**/*.tsx: Avoid inline arrow functions in JSX props; use stable function references for event handlers
Declare React components with the function keyword (functional components)
Use PascalCase for React component names
Use functional components and hooks instead of class components
Type component props with TypeScript interfaces

Files:

  • apps/pro-web/components/routes/workspace/media-tab/reference-upload-slot.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
apps/{web,pro-web}/components/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Order component files: imports → constants → component → styled components → types/interfaces

Files:

  • apps/pro-web/components/routes/workspace/media-tab/reference-upload-slot.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
🧠 Learnings (17)
📓 Common learnings
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-09-04T21:31:18.830Z
Learning: Successfully created comprehensive GitHub issue #555 consolidating performance feedback and edge-case management for pro-web workspace features, including prioritized action items, testing requirements, and specific file references for implementation.
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 584
File: apps/pro-web/app/api/generate-images/route.ts:86-107
Timestamp: 2025-11-14T19:14:07.226Z
Learning: In apps/pro-web/app/api/generate-images/route.ts, the hardcoded 'image/png' MIME type for Gemini previousImage is intentional—LLM-generated images are PNG by default. When the library/template features are added (allowing user-uploaded reference images), the architecture should use Next.js server actions with checksum-based caching (computeChecksum fn) to handle files larger than the 2.5-3MB API route limit, rather than detecting MIME types in the API route directly.
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 504
File: apps/masterbots.ai/app/api/generate-images/route.ts:58-80
Timestamp: 2025-06-10T05:48:25.508Z
Learning: GPT-Image-1 is a legitimate and advanced OpenAI image generation model released in March 2025 as the successor to DALL·E 3. It's built on the multimodal GPT-4o architecture and supports enhanced capabilities including: up to 4096×4096 resolution, improved text rendering, image-to-image generation, inpainting/editing, multiple output formats (PNG, JPEG, WebP), transparent/opaque backgrounds, and both b64_json and URL response formats. It should be used with the OpenAI client directly rather than the experimental AI SDK for full feature support.
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 504
File: apps/masterbots.ai/app/api/generate-images/route.ts:58-80
Timestamp: 2025-06-10T05:48:25.508Z
Learning: In apps/masterbots.ai/app/api/generate-images/route.ts, the conditional check for modelId === 'gpt-image-1' is correct and uses the OpenAI client directly to handle this advanced model, while other models like 'dall-e-2' and 'dall-e-3' use the AI SDK. This implementation pattern is appropriate for handling different model capabilities.
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to apps/{web,pro-web}/components/shared/**/*.{ts,tsx} : Store reusable UI elements in components/shared/

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/reference-upload-slot.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to apps/{web,pro-web}/**/*.tsx : Use functional components and hooks; type props with a TypeScript interface

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/reference-upload-slot.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Pro workspace editors: controlled/uncontrolled patterns, Markdown utilities, section state sync, and timed DOM operations

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-06-10T05:48:25.508Z
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 504
File: apps/masterbots.ai/app/api/generate-images/route.ts:58-80
Timestamp: 2025-06-10T05:48:25.508Z
Learning: In apps/masterbots.ai/app/api/generate-images/route.ts, the conditional check for modelId === 'gpt-image-1' is correct and uses the OpenAI client directly to handle this advanced model, while other models like 'dall-e-2' and 'dall-e-3' use the AI SDK. This implementation pattern is appropriate for handling different model capabilities.

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-11-14T19:14:07.226Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 584
File: apps/pro-web/app/api/generate-images/route.ts:86-107
Timestamp: 2025-11-14T19:14:07.226Z
Learning: In apps/pro-web/app/api/generate-images/route.ts, the hardcoded 'image/png' MIME type for Gemini previousImage is intentional—LLM-generated images are PNG by default. When the library/template features are added (allowing user-uploaded reference images), the architecture should use Next.js server actions with checksum-based caching (computeChecksum fn) to handle files larger than the 2.5-3MB API route limit, rather than detecting MIME types in the API route directly.

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-06-13T08:55:45.217Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 508
File: apps/masterbots.ai/lib/helpers/ai-helpers.ts:280-283
Timestamp: 2025-06-13T08:55:45.217Z
Learning: In `apps/masterbots.ai/lib/helpers/ai-helpers.ts` the `verifyDuplicateMessage` function should:
• Use `message.content` as the sole de-duplication key so provisional (no-slug) and persisted (slugged) messages merge properly.
• Return the full `message` object (not just a string key) for the continuation prompts (`CONTINUE_GENERATION_PROMPT`, `CONTINUE_GENERATION_PROMPT_2`) because their content repeats and they must remain distinct.
• No explicit `!message.content` guard is needed; `return message.content` already yields `undefined` when content is missing.

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to **/*.tsx : Avoid inline arrow functions in JSX props; use stable function references for event handlers

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to apps/{web,pro-web}/**/*.tsx : Use regular function references (not inline arrows) for React event handlers to avoid extra re-renders

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-02-17T16:51:19.102Z
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 376
File: apps/masterbots.ai/components/routes/chat/chat.tsx:92-102
Timestamp: 2025-02-17T16:51:19.102Z
Learning: For the Chat component in apps/masterbots.ai/components/routes/chat/chat.tsx, the developer prefers to verify potential optimizations through local testing before accepting suggestions, particularly for performance-related changes like useCallback usage in debounce implementations.

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Verify DOM operations and consider timing (RAF/delays) when manipulating the DOM in React

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2024-11-20T04:00:45.413Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 300
File: apps/masterbots.ai/components/routes/thread/user-thread-panel.tsx:120-123
Timestamp: 2024-11-20T04:00:45.413Z
Learning: In React code, when reviewing `useEffect` dependencies, it's not always necessary to add functions like `handleThreadsChange` to the dependency array, as this may lead to unnecessary re-renders and performance issues. Only include dependencies that are essential and may change.

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/**/*.tsx : Use regular function references for event handlers instead of inline arrow functions in JSX

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to **/*.tsx : Use functional components and hooks instead of class components

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2024-10-23T00:00:06.253Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 287
File: apps/masterbots.ai/components/routes/chat/share-button.tsx:10-29
Timestamp: 2024-10-23T00:00:06.253Z
Learning: When implementing the `handleShare` function in `apps/masterbots.ai/components/routes/chat/share-button.tsx`, prefer using modern APIs like the Clipboard API over deprecated methods like `document.execCommand('copy')`, as the project no longer needs to support very old web browsers.

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/**/*.tsx : Declare React components with the function keyword (function ComponentName() {})

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
📚 Learning: 2024-11-28T18:54:45.949Z
Learnt from: sheriffjimoh
Repo: bitcashorg/masterbots PR: 313
File: apps/masterbots.ai/components/layout/sidebar/sidebar-link.tsx:150-151
Timestamp: 2024-11-28T18:54:45.949Z
Learning: When handling navigation programmatically in the application, prefer using `<button>` elements instead of `Link` components to prevent unintended page reloads caused by default link behavior.

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
🧬 Code graph analysis (2)
apps/pro-web/components/routes/workspace/media-tab/reference-upload-slot.tsx (1)
apps/pro-web/lib/utils.ts (1)
  • cn (9-11)
apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx (6)
apps/pro-web/lib/helpers/workspace/media.ts (2)
  • Template (1-8)
  • getFrameSizeFromTemplate (155-177)
apps/pro-web/lib/hooks/use-workspace-media.tsx (1)
  • useWorkspaceMedia (181-189)
apps/pro-web/components/ui/wizard/index.tsx (1)
  • WizardStep (23-26)
apps/pro-web/components/routes/workspace/media-tab/steps/select-template-step.tsx (1)
  • SelectTemplateStep (12-109)
apps/pro-web/components/shared/image-display.tsx (1)
  • ImageDisplay (22-188)
apps/pro-web/components/routes/workspace/media-tab/reference-upload-slot.tsx (1)
  • ReferenceUploadSlot (15-178)

Comment on lines +23 to +58
const validateAndProcessFile = (file: File): string | null => {
// Validate file type
const validTypes = ['image/jpeg', 'image/png', 'image/webp']
if (!validTypes.includes(file.type)) {
console.error(
`Invalid file type for ${file.name}. Please upload JPEG, PNG, or WebP.`,
)
return null
}

// Validate file size (5MB max)
const maxSize = 5 * 1024 * 1024 // 5MB in bytes
if (file.size > maxSize) {
console.error(`File ${file.name} exceeds 5MB limit.`)
return null
}

// Create preview URL
return URL.createObjectURL(file)
}

const validateAndProcessFiles = (files: File[]) => {
const validUrls: string[] = []

// Process up to availableSlots files
const filesToProcess = files.slice(0, availableSlots)

for (const file of filesToProcess) {
const url = validateAndProcessFile(file)
if (url) {
validUrls.push(url)
}
}

return validUrls
}
Copy link
Contributor

@coderabbitai coderabbitai bot Nov 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Revoke object URLs to prevent memory leaks.

The helpers create object URLs via URL.createObjectURL but never call URL.revokeObjectURL, causing a memory leak. Object URLs persist until the page unloads or explicitly revoked, consuming browser memory.

Track created URLs in a ref and revoke them when the component unmounts or when new URLs replace them:

 export function ReferenceUploadSlot({
 	onUpload,
 	onMultipleUpload,
 	availableSlots = 1,
 }: ReferenceUploadSlotProps) {
 	const [isDragActive, setIsDragActive] = useState(false)
 	const fileInputRef = useRef<HTMLInputElement>(null)
+	const objectUrlsRef = useRef<string[]>([])
+
+	// Cleanup object URLs on unmount
+	useEffect(() => {
+		return () => {
+			for (const url of objectUrlsRef.current) {
+				URL.revokeObjectURL(url)
+			}
+		}
+	}, [])

 	const validateAndProcessFile = (file: File): string | null => {
 		// Validate file type
 		const validTypes = ['image/jpeg', 'image/png', 'image/webp']
 		if (!validTypes.includes(file.type)) {
 			console.error(
 				`Invalid file type for ${file.name}. Please upload JPEG, PNG, or WebP.`,
 			)
 			return null
 		}

 		// Validate file size (5MB max)
 		const maxSize = 5 * 1024 * 1024 // 5MB in bytes
 		if (file.size > maxSize) {
 			console.error(`File ${file.name} exceeds 5MB limit.`)
 			return null
 		}

 		// Create preview URL
-		return URL.createObjectURL(file)
+		const url = URL.createObjectURL(file)
+		objectUrlsRef.current.push(url)
+		return url
 	}

Committable suggestion skipped: line range outside the PR's diff.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can take this in a new PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AndlerRL, sounds good! Would you like me to create a GitHub issue to track this memory leak fix for the follow-up PR? I can document the object URL cleanup requirement with the relevant context.


🧠 Learnings used
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 542
File: apps/web/components/layout/profile/layout.tsx:67-68
Timestamp: 2025-08-29T20:34:24.433Z
Learning: AndlerRL prefers skeleton loading states over conditional rendering for better UX when components are waiting for data to load. Components should show loading indicators rather than blank spaces.

Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 584
File: apps/pro-web/app/api/generate-images/route.ts:86-107
Timestamp: 2025-11-14T19:14:07.243Z
Learning: In apps/pro-web/app/api/generate-images/route.ts, the hardcoded 'image/png' MIME type for Gemini previousImage is intentional—LLM-generated images are PNG by default. When the library/template features are added (allowing user-uploaded reference images), the architecture should use Next.js server actions with checksum-based caching (computeChecksum fn) to handle files larger than the 2.5-3MB API route limit, rather than detecting MIME types in the API route directly.

Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-09-04T21:31:18.830Z
Learning: Successfully created comprehensive GitHub issue #555 consolidating performance feedback and edge-case management for pro-web workspace features, including prioritized action items, testing requirements, and specific file references for implementation.

- Added MediaCanvas component for displaying generated images and templates.
- Introduced ReferenceImagesPanel for managing reference images with upload functionality.
- Created MediaSidebar for navigation between templates and social media actions.
- Implemented wizards for selecting sizes and templates, including LibraryStep for image selection.
- Enhanced hooks to manage workspace media state and integrate new components.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

♻️ Duplicate comments (1)
apps/pro-web/components/routes/workspace/media-tab/ui/reference-images/reference-upload-slot.tsx (1)

23-42: Memory leak remains unresolved from previous review.

Object URLs created via URL.createObjectURL are never revoked, causing a memory leak that persists until page unload. The past review comment flagged this issue and provided a fix using a ref to track URLs and a cleanup effect.

🧹 Nitpick comments (9)
apps/pro-web/components/routes/workspace/media-tab/ui/sidebar/media-sidebar.tsx (1)

40-46: Extract inline arrow functions from event handlers.

Per coding guidelines, use regular function references for event handlers instead of inline arrow functions to avoid extra re-renders.

Apply this pattern to both TODO buttons:

+const handleSocialMediaClick = () => {
+  // TODO: Implement social media action
+}
+
 <Button
   variant="ghost"
   size="icon"
   className="rounded-full w-9 h-9 lg:w-10 lg:h-10 bg-pink-500 hover:bg-pink-600 transition-colors shrink-0"
-  onClick={() => {
-    /* TODO: Implement social media action */
-  }}
+  onClick={handleSocialMediaClick}
 >

Similarly for the Brand Kit button at lines 59-65.

As per coding guidelines

apps/pro-web/components/routes/workspace/media-tab/wizards/steps/select-size-step.tsx (2)

18-21: Signature doesn't use all WizardStepProps properties.

The component extends WizardStepProps but only destructures frameSizes and onSizeSelect from its props. The standard wizard props (next, prev, close, goTo, lastStep, currentStep) are not used in the component body. Consider not extending WizardStepProps if these properties aren't needed, or document why the extension is necessary for wizard integration.


38-82: Consider extracting the inline arrow function to a stable reference.

The onClick handler on line 42 uses an inline arrow function, which creates a new function on each render for each frame size. While this may not cause performance issues in practice, the coding guidelines recommend using stable function references for event handlers.

As per coding guidelines.

Apply this pattern if you want to optimize:

const handleSizeSelect = useCallback((size: FrameSize) => {
  onSizeSelect(size)
}, [onSizeSelect])

// Then in JSX:
onClick={() => handleSizeSelect(frame)}

However, for a small list of frame sizes (typically <10 items), the current pattern is acceptable and more readable.

apps/pro-web/components/routes/workspace/media-tab/ui/reference-images/reference-images-panel.tsx (2)

22-31: Consider moving helper functions outside the component or memoizing them.

The helper functions getFirstEmptySlotIndex and getAvailableSlots are redefined on every render. While this is unlikely to cause performance issues, it's better practice to either:

  1. Move them outside the component (if they don't need closure over props)
  2. Wrap them with useCallback if they depend on referenceImages
const getFirstEmptySlotIndex = useCallback(() => {
  for (let i = 0; i < 4; i++) {
    if (!referenceImages[i]) return i
  }
  return -1
}, [referenceImages])

const getAvailableSlots = useCallback(() => {
  return 4 - referenceImages.length
}, [referenceImages.length])

68-79: Consider extracting inline event handler to a stable reference.

The onClick handler uses an inline arrow function. Per coding guidelines, prefer stable function references for event handlers to avoid creating new functions on each render.

As per coding guidelines.

const handleRemoveImage = useCallback((e: React.MouseEvent, idx: number) => {
  e.stopPropagation()
  onRemoveImage(idx)
}, [onRemoveImage])

// In JSX:
onClick={(e) => handleRemoveImage(e, idx)}
apps/pro-web/components/routes/workspace/media-tab/media-workspace.tsx (2)

37-58: Address the TODO for migrating to TanStack Query.

The comment on line 37 indicates a planned migration to TanStack Query for template fetching. The current implementation uses plain fetch with manual loading state management.

Do you want me to open an issue to track the migration to TanStack Query for this template-fetching logic? This would provide benefits like automatic caching, request deduplication, and better error/loading state management.


61-81: Consider consolidating reference image management functions.

Four separate functions (removeReferenceImage, addReferenceImage, addMultipleReferenceImages, addImageFromLibrary) handle reference images. addReferenceImage and addImageFromLibrary have identical implementations.

Consider:

  1. Removing addImageFromLibrary and using addReferenceImage directly
  2. Or creating a single useReferenceImages custom hook to encapsulate this logic
// Option 1: Use addReferenceImage directly
<MediaWizards
  // ...
  onImageSelect={addReferenceImage}  // instead of addImageFromLibrary
/>
apps/pro-web/components/routes/workspace/media-tab/wizards/steps/select-template-step.tsx (1)

12-16: Signature doesn't use all WizardStepProps properties.

Similar to SelectSizeStep, this component extends WizardStepProps but doesn't use the standard wizard navigation methods. Consider not extending if these aren't needed for wizard integration.

apps/pro-web/components/routes/workspace/media-tab/ui/canvas/media-canvas.tsx (1)

210-215: Magic number for version card width calculation.

Line 214 uses a hardcoded value 288 + 16 for transform calculation. The 288 appears to be the card width (72 * 4 = 288px for w-72 at sm breakpoint), and 16 is the gap.

Consider extracting these as constants or calculating them dynamically:

const CARD_WIDTH_SM = 288 // w-72 in pixels
const CARD_GAP_SM = 16    // gap-4 in pixels

// In the style prop:
transform: `translateX(-${currentVersion * (CARD_WIDTH_SM + CARD_GAP_SM)}px)`

This makes the relationship between the Tailwind classes and the transform calculation more explicit.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2a3b0b0 and 5abc70a.

📒 Files selected for processing (16)
  • apps/pro-web/components/routes/workspace/media-tab/index.ts (1 hunks)
  • apps/pro-web/components/routes/workspace/media-tab/media-tab-wrapper.tsx (1 hunks)
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx (0 hunks)
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace.tsx (1 hunks)
  • apps/pro-web/components/routes/workspace/media-tab/ui/canvas/index.ts (1 hunks)
  • apps/pro-web/components/routes/workspace/media-tab/ui/canvas/media-canvas.tsx (1 hunks)
  • apps/pro-web/components/routes/workspace/media-tab/ui/reference-images/index.ts (1 hunks)
  • apps/pro-web/components/routes/workspace/media-tab/ui/reference-images/reference-images-panel.tsx (1 hunks)
  • apps/pro-web/components/routes/workspace/media-tab/ui/reference-images/reference-upload-slot.tsx (1 hunks)
  • apps/pro-web/components/routes/workspace/media-tab/ui/sidebar/index.ts (1 hunks)
  • apps/pro-web/components/routes/workspace/media-tab/ui/sidebar/media-sidebar.tsx (1 hunks)
  • apps/pro-web/components/routes/workspace/media-tab/wizards/index.ts (1 hunks)
  • apps/pro-web/components/routes/workspace/media-tab/wizards/media-wizards.tsx (1 hunks)
  • apps/pro-web/components/routes/workspace/media-tab/wizards/steps/select-size-step.tsx (1 hunks)
  • apps/pro-web/components/routes/workspace/media-tab/wizards/steps/select-template-step.tsx (1 hunks)
  • apps/pro-web/lib/hooks/use-workspace-media.tsx (1 hunks)
💤 Files with no reviewable changes (1)
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace-ui.tsx
✅ Files skipped from review due to trivial changes (1)
  • apps/pro-web/components/routes/workspace/media-tab/index.ts
🧰 Additional context used
📓 Path-based instructions (9)
apps/{web,pro-web}/components/routes/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Place page-specific components under components/routes/[feature]/

Organize page-specific components under components/routes/

Files:

  • apps/pro-web/components/routes/workspace/media-tab/ui/reference-images/index.ts
  • apps/pro-web/components/routes/workspace/media-tab/ui/sidebar/index.ts
  • apps/pro-web/components/routes/workspace/media-tab/ui/canvas/index.ts
  • apps/pro-web/components/routes/workspace/media-tab/wizards/steps/select-template-step.tsx
  • apps/pro-web/components/routes/workspace/media-tab/ui/sidebar/media-sidebar.tsx
  • apps/pro-web/components/routes/workspace/media-tab/wizards/media-wizards.tsx
  • apps/pro-web/components/routes/workspace/media-tab/wizards/steps/select-size-step.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace.tsx
  • apps/pro-web/components/routes/workspace/media-tab/wizards/index.ts
  • apps/pro-web/components/routes/workspace/media-tab/ui/reference-images/reference-upload-slot.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-tab-wrapper.tsx
  • apps/pro-web/components/routes/workspace/media-tab/ui/reference-images/reference-images-panel.tsx
  • apps/pro-web/components/routes/workspace/media-tab/ui/canvas/media-canvas.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Avoid default exports; prefer named exports
Use meaningful variable names; prefix booleans with is/has/does/should
Use interface for objects/classes; type for unions/tuples/aliases; enum for fixed sets; const for literals
Avoid any; prefer specific types
Leverage type inference where clear; annotate function params and return types
Prefer type assertions with 'as' over angle-bracket syntax
Use type guards to narrow types in conditionals

**/*.{ts,tsx}: Avoid default exports; prefer named exports
Use modern JavaScript features with TypeScript across the codebase
Use meaningful names; prefix booleans with is/has/does/should (e.g., isDisabled)
Receive an object and return an object (RORO) for functions interfacing with external services
Type definitions: use interface for objects/classes; type for unions/tuples/aliases; const for literals; enum for fixed sets
Avoid any; prefer specific types
Leverage type inference; omit explicit annotations when obvious
Add explicit type annotations for function parameters and return values
Prefer type assertions with as over angle-bracket syntax
Use type guards to narrow types within conditionals
Favor composition over inheritance in code structure

**/*.{ts,tsx}: Avoid default exports; prefer named exports
Prefer RORO (Receive an object, return an object) for function signatures, especially for external service interactions
Use interface for object shapes/classes; type for unions/tuples/aliases; const for literals; enum for fixed enumerations
Avoid using any; prefer precise types
Leverage type inference when clear; omit redundant annotations
Explicitly annotate function parameters and return types
Prefer type assertions with as over angle-bracket syntax
Use type guards to narrow types safely
Use meaningful variable names; prefix booleans with is/has/does/should
Favor composition over inheritance
Use lowercase dash-separated names for files and folders; use extensions like .config.ts, .test.ts, .context.tsx, .typ...

Files:

  • apps/pro-web/components/routes/workspace/media-tab/ui/reference-images/index.ts
  • apps/pro-web/components/routes/workspace/media-tab/ui/sidebar/index.ts
  • apps/pro-web/components/routes/workspace/media-tab/ui/canvas/index.ts
  • apps/pro-web/components/routes/workspace/media-tab/wizards/steps/select-template-step.tsx
  • apps/pro-web/components/routes/workspace/media-tab/ui/sidebar/media-sidebar.tsx
  • apps/pro-web/components/routes/workspace/media-tab/wizards/media-wizards.tsx
  • apps/pro-web/components/routes/workspace/media-tab/wizards/steps/select-size-step.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace.tsx
  • apps/pro-web/lib/hooks/use-workspace-media.tsx
  • apps/pro-web/components/routes/workspace/media-tab/wizards/index.ts
  • apps/pro-web/components/routes/workspace/media-tab/ui/reference-images/reference-upload-slot.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-tab-wrapper.tsx
  • apps/pro-web/components/routes/workspace/media-tab/ui/reference-images/reference-images-panel.tsx
  • apps/pro-web/components/routes/workspace/media-tab/ui/canvas/media-canvas.tsx
apps/{web,pro-web}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

apps/{web,pro-web}/**/*.{ts,tsx}: Use lowercase kebab-case for directories and filenames (components can omit extension)
Verify DOM operations and consider timing (RAF/delays) when manipulating the DOM in React
Use Tailwind CSS utility classes for styling React components

apps/{web,pro-web}/**/*.{ts,tsx}: Use TypeScript to define React props types (interfaces for props)
Use custom hooks (useMBChat, useThread, useSidebar, useModel) for domain-specific state and keep providers focused and composed hierarchically
Separate presentation from business logic and compose small components
Use hasura.service.ts for all GraphQL operations from UI layers

apps/{web,pro-web}/**/*.{ts,tsx}: Prefer Server Components; use the use client directive only when client-side features are required
Implement Nested Layouts using the App Router
Use Streaming and Suspense in Next.js 14/15 where appropriate
Follow Next.js file conventions as per documentation
Use IndexedDB for local caching to enable immediate UI updates

Files:

  • apps/pro-web/components/routes/workspace/media-tab/ui/reference-images/index.ts
  • apps/pro-web/components/routes/workspace/media-tab/ui/sidebar/index.ts
  • apps/pro-web/components/routes/workspace/media-tab/ui/canvas/index.ts
  • apps/pro-web/components/routes/workspace/media-tab/wizards/steps/select-template-step.tsx
  • apps/pro-web/components/routes/workspace/media-tab/ui/sidebar/media-sidebar.tsx
  • apps/pro-web/components/routes/workspace/media-tab/wizards/media-wizards.tsx
  • apps/pro-web/components/routes/workspace/media-tab/wizards/steps/select-size-step.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace.tsx
  • apps/pro-web/lib/hooks/use-workspace-media.tsx
  • apps/pro-web/components/routes/workspace/media-tab/wizards/index.ts
  • apps/pro-web/components/routes/workspace/media-tab/ui/reference-images/reference-upload-slot.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-tab-wrapper.tsx
  • apps/pro-web/components/routes/workspace/media-tab/ui/reference-images/reference-images-panel.tsx
  • apps/pro-web/components/routes/workspace/media-tab/ui/canvas/media-canvas.tsx
**/*

📄 CodeRabbit inference engine (CLAUDE.md)

**/*: Use lowercase with dash-separated directory and file names; use specific extensions: .config.ts, .test.ts, .context.tsx, .type.ts, .hook.ts; components may omit extension
Use Bun for package management and scripts instead of npm/yarn
Use Biome for formatting and linting via bun format-and-lint:fix; avoid Prettier/ESLint configs

Files:

  • apps/pro-web/components/routes/workspace/media-tab/ui/reference-images/index.ts
  • apps/pro-web/components/routes/workspace/media-tab/ui/sidebar/index.ts
  • apps/pro-web/components/routes/workspace/media-tab/ui/canvas/index.ts
  • apps/pro-web/components/routes/workspace/media-tab/wizards/steps/select-template-step.tsx
  • apps/pro-web/components/routes/workspace/media-tab/ui/sidebar/media-sidebar.tsx
  • apps/pro-web/components/routes/workspace/media-tab/wizards/media-wizards.tsx
  • apps/pro-web/components/routes/workspace/media-tab/wizards/steps/select-size-step.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace.tsx
  • apps/pro-web/lib/hooks/use-workspace-media.tsx
  • apps/pro-web/components/routes/workspace/media-tab/wizards/index.ts
  • apps/pro-web/components/routes/workspace/media-tab/ui/reference-images/reference-upload-slot.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-tab-wrapper.tsx
  • apps/pro-web/components/routes/workspace/media-tab/ui/reference-images/reference-images-panel.tsx
  • apps/pro-web/components/routes/workspace/media-tab/ui/canvas/media-canvas.tsx
apps/{web,pro-web}/**/*.tsx

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

apps/{web,pro-web}/**/*.tsx: Declare React components with the function keyword
Name React components using PascalCase
Order component files: imports → constants → component → styled components → types/interfaces
Use functional components and hooks; type props with a TypeScript interface
Use regular function references (not inline arrows) for React event handlers to avoid extra re-renders

apps/{web,pro-web}/**/*.tsx: Use regular function references for event handlers instead of inline arrow functions in JSX
Declare React components with the function keyword (function ComponentName() {})
Use PascalCase for React component names
Order React component files: imports, constants, component, styled components, types/interfaces
Style components with Tailwind CSS utility classes

Files:

  • apps/pro-web/components/routes/workspace/media-tab/wizards/steps/select-template-step.tsx
  • apps/pro-web/components/routes/workspace/media-tab/ui/sidebar/media-sidebar.tsx
  • apps/pro-web/components/routes/workspace/media-tab/wizards/media-wizards.tsx
  • apps/pro-web/components/routes/workspace/media-tab/wizards/steps/select-size-step.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace.tsx
  • apps/pro-web/lib/hooks/use-workspace-media.tsx
  • apps/pro-web/components/routes/workspace/media-tab/ui/reference-images/reference-upload-slot.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-tab-wrapper.tsx
  • apps/pro-web/components/routes/workspace/media-tab/ui/reference-images/reference-images-panel.tsx
  • apps/pro-web/components/routes/workspace/media-tab/ui/canvas/media-canvas.tsx
**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

**/*.tsx: Avoid inline arrow functions in JSX props; use stable function references for event handlers
Declare React components with the function keyword (functional components)
Use PascalCase for React component names
Use functional components and hooks instead of class components
Type component props with TypeScript interfaces

Files:

  • apps/pro-web/components/routes/workspace/media-tab/wizards/steps/select-template-step.tsx
  • apps/pro-web/components/routes/workspace/media-tab/ui/sidebar/media-sidebar.tsx
  • apps/pro-web/components/routes/workspace/media-tab/wizards/media-wizards.tsx
  • apps/pro-web/components/routes/workspace/media-tab/wizards/steps/select-size-step.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace.tsx
  • apps/pro-web/lib/hooks/use-workspace-media.tsx
  • apps/pro-web/components/routes/workspace/media-tab/ui/reference-images/reference-upload-slot.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-tab-wrapper.tsx
  • apps/pro-web/components/routes/workspace/media-tab/ui/reference-images/reference-images-panel.tsx
  • apps/pro-web/components/routes/workspace/media-tab/ui/canvas/media-canvas.tsx
apps/{web,pro-web}/components/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Order component files: imports → constants → component → styled components → types/interfaces

Files:

  • apps/pro-web/components/routes/workspace/media-tab/wizards/steps/select-template-step.tsx
  • apps/pro-web/components/routes/workspace/media-tab/ui/sidebar/media-sidebar.tsx
  • apps/pro-web/components/routes/workspace/media-tab/wizards/media-wizards.tsx
  • apps/pro-web/components/routes/workspace/media-tab/wizards/steps/select-size-step.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace.tsx
  • apps/pro-web/components/routes/workspace/media-tab/ui/reference-images/reference-upload-slot.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-tab-wrapper.tsx
  • apps/pro-web/components/routes/workspace/media-tab/ui/reference-images/reference-images-panel.tsx
  • apps/pro-web/components/routes/workspace/media-tab/ui/canvas/media-canvas.tsx
apps/{web,pro-web}/lib/hooks/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

apps/{web,pro-web}/lib/hooks/**: Place custom React hooks under lib/hooks/
Encapsulate complex state in custom hooks and separate presentation from business logic

Store custom React hooks under lib/hooks/

Files:

  • apps/pro-web/lib/hooks/use-workspace-media.tsx
apps/{web,pro-web}/lib/hooks/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Place custom React hooks in lib/hooks/

Files:

  • apps/pro-web/lib/hooks/use-workspace-media.tsx
🧠 Learnings (17)
📓 Common learnings
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-09-04T21:31:18.830Z
Learning: Successfully created comprehensive GitHub issue #555 consolidating performance feedback and edge-case management for pro-web workspace features, including prioritized action items, testing requirements, and specific file references for implementation.
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 584
File: apps/pro-web/app/api/generate-images/route.ts:86-107
Timestamp: 2025-11-14T19:14:07.226Z
Learning: In apps/pro-web/app/api/generate-images/route.ts, the hardcoded 'image/png' MIME type for Gemini previousImage is intentional—LLM-generated images are PNG by default. When the library/template features are added (allowing user-uploaded reference images), the architecture should use Next.js server actions with checksum-based caching (computeChecksum fn) to handle files larger than the 2.5-3MB API route limit, rather than detecting MIME types in the API route directly.
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 504
File: apps/masterbots.ai/app/api/generate-images/route.ts:58-80
Timestamp: 2025-06-10T05:48:25.508Z
Learning: GPT-Image-1 is a legitimate and advanced OpenAI image generation model released in March 2025 as the successor to DALL·E 3. It's built on the multimodal GPT-4o architecture and supports enhanced capabilities including: up to 4096×4096 resolution, improved text rendering, image-to-image generation, inpainting/editing, multiple output formats (PNG, JPEG, WebP), transparent/opaque backgrounds, and both b64_json and URL response formats. It should be used with the OpenAI client directly rather than the experimental AI SDK for full feature support.
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 504
File: apps/masterbots.ai/app/api/generate-images/route.ts:58-80
Timestamp: 2025-06-10T05:48:25.508Z
Learning: The 'gpt-image-1' is a valid and new OpenAI image generation model that can be used with the OpenAI images.generate() API. It should be treated as a legitimate model ID alongside 'dall-e-2' and 'dall-e-3' in image generation applications.
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to apps/{web,pro-web}/components/shared/**/*.{ts,tsx} : Store reusable UI elements in components/shared/

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/ui/reference-images/index.ts
  • apps/pro-web/components/routes/workspace/media-tab/ui/sidebar/index.ts
  • apps/pro-web/components/routes/workspace/media-tab/wizards/steps/select-template-step.tsx
  • apps/pro-web/components/routes/workspace/media-tab/ui/sidebar/media-sidebar.tsx
  • apps/pro-web/components/routes/workspace/media-tab/wizards/media-wizards.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace.tsx
  • apps/pro-web/components/routes/workspace/media-tab/wizards/index.ts
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to apps/{web,pro-web}/components/ui/**/*.{ts,tsx} : Follow Radix UI patterns under components/ui/

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/wizards/steps/select-template-step.tsx
  • apps/pro-web/components/routes/workspace/media-tab/ui/sidebar/media-sidebar.tsx
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Separate presentation from business logic and compose small components

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/wizards/steps/select-template-step.tsx
  • apps/pro-web/components/routes/workspace/media-tab/ui/sidebar/media-sidebar.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace.tsx
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/**/*.tsx : Order React component files: imports, constants, component, styled components, types/interfaces

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/wizards/steps/select-template-step.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace.tsx
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to apps/{web,pro-web}/**/*.tsx : Use functional components and hooks; type props with a TypeScript interface

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/wizards/steps/select-template-step.tsx
  • apps/pro-web/components/routes/workspace/media-tab/ui/sidebar/media-sidebar.tsx
  • apps/pro-web/components/routes/workspace/media-tab/media-workspace.tsx
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to apps/{web,pro-web}/**/*.tsx : Order component files: imports → constants → component → styled components → types/interfaces

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace.tsx
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Use TypeScript to define React props types (interfaces for props)

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to apps/{web,pro-web}/components/**/*.tsx : Order component files: imports → constants → component → styled components → types/interfaces

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Implement Nested Layouts using the App Router

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace.tsx
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Use custom hooks (useMBChat, useThread, useSidebar, useModel) for domain-specific state and keep providers focused and composed hierarchically

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace.tsx
  • apps/pro-web/lib/hooks/use-workspace-media.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Follow Next.js file conventions as per documentation

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-workspace.tsx
📚 Learning: 2025-11-14T19:14:07.226Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 584
File: apps/pro-web/app/api/generate-images/route.ts:86-107
Timestamp: 2025-11-14T19:14:07.226Z
Learning: In apps/pro-web/app/api/generate-images/route.ts, the hardcoded 'image/png' MIME type for Gemini previousImage is intentional—LLM-generated images are PNG by default. When the library/template features are added (allowing user-uploaded reference images), the architecture should use Next.js server actions with checksum-based caching (computeChecksum fn) to handle files larger than the 2.5-3MB API route limit, rather than detecting MIME types in the API route directly.

Applied to files:

  • apps/pro-web/lib/hooks/use-workspace-media.tsx
📚 Learning: 2024-10-23T07:33:36.041Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 287
File: apps/masterbots.ai/lib/hooks/use-thread-visibility.tsx:3-3
Timestamp: 2024-10-23T07:33:36.041Z
Learning: Always use explicit imports for React hooks to maintain consistency across the monorepo, and avoid using both named and default imports simultaneously.

Applied to files:

  • apps/pro-web/lib/hooks/use-workspace-media.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to **/*.{ts,tsx} : Avoid default exports; prefer named exports

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/wizards/index.ts
📚 Learning: 2025-04-26T10:58:44.341Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 465
File: apps/masterbots.ai/components/routes/browse/browse-list.tsx:1-1
Timestamp: 2025-04-26T10:58:44.341Z
Learning: The browse-list.tsx component and related components in the browse directory are redundant since thread-list.tsx has been developed to support all pages including public pages, and should be removed to simplify the codebase.

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-tab-wrapper.tsx
📚 Learning: 2025-04-26T10:58:44.341Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 465
File: apps/masterbots.ai/components/routes/browse/browse-list.tsx:1-1
Timestamp: 2025-04-26T10:58:44.341Z
Learning: The browse-list.tsx component is redundant as thread-list.tsx has been developed to support all the same functionality including public pages. The codebase should be cleaned up to remove browse-list.tsx and related components in the browse directory, along with the BrowseProvider context.

Applied to files:

  • apps/pro-web/components/routes/workspace/media-tab/media-tab-wrapper.tsx
🧬 Code graph analysis (8)
apps/pro-web/components/routes/workspace/media-tab/wizards/steps/select-template-step.tsx (2)
apps/pro-web/components/ui/wizard/index.tsx (1)
  • WizardStepProps (14-21)
apps/pro-web/lib/helpers/workspace/media.ts (1)
  • Template (1-8)
apps/pro-web/components/routes/workspace/media-tab/wizards/media-wizards.tsx (5)
apps/pro-web/components/routes/workspace/media-tab/wizards/steps/select-size-step.tsx (2)
  • FrameSize (5-11)
  • SelectSizeStep (18-90)
apps/pro-web/lib/helpers/workspace/media.ts (2)
  • Template (1-8)
  • getFrameSizeFromTemplate (155-177)
apps/pro-web/components/ui/wizard/index.tsx (1)
  • WizardStep (23-26)
apps/pro-web/components/routes/workspace/media-tab/wizards/steps/select-template-step.tsx (1)
  • SelectTemplateStep (12-109)
apps/pro-web/components/routes/workspace/media-tab/wizards/steps/library-step.tsx (1)
  • LibraryStep (10-35)
apps/pro-web/components/routes/workspace/media-tab/wizards/steps/select-size-step.tsx (1)
apps/pro-web/components/ui/wizard/index.tsx (1)
  • WizardStepProps (14-21)
apps/pro-web/components/routes/workspace/media-tab/media-workspace.tsx (7)
apps/pro-web/lib/helpers/workspace/media.ts (1)
  • Template (1-8)
apps/pro-web/lib/hooks/use-workspace-media.tsx (1)
  • useWorkspaceMedia (181-189)
apps/pro-web/components/routes/workspace/media-tab/ui/sidebar/media-sidebar.tsx (1)
  • MediaSidebar (16-77)
apps/pro-web/components/routes/workspace/media-tab/ui/canvas/media-canvas.tsx (1)
  • MediaCanvas (44-267)
apps/pro-web/components/routes/workspace/media-tab/ui/reference-images/reference-images-panel.tsx (1)
  • ReferenceImagesPanel (16-111)
apps/pro-web/components/routes/workspace/media-tab/wizards/media-wizards.tsx (1)
  • MediaWizards (25-138)
apps/pro-web/components/routes/workspace/media-tab/wizards/steps/select-size-step.tsx (1)
  • FrameSize (5-11)
apps/pro-web/lib/hooks/use-workspace-media.tsx (4)
apps/pro-web/types/index.ts (1)
  • ImageModel (450-450)
apps/pro-web/lib/helpers/workspace/media.ts (2)
  • Template (1-8)
  • imageUrlToBase64 (16-35)
apps/pro-web/components/routes/workspace/media-tab/wizards/steps/select-size-step.tsx (1)
  • FrameSize (5-11)
apps/pro-web/lib/hooks/use-image-generation.tsx (1)
  • useImageGeneration (18-175)
apps/pro-web/components/routes/workspace/media-tab/ui/reference-images/reference-upload-slot.tsx (1)
apps/pro-web/lib/utils.ts (1)
  • cn (9-11)
apps/pro-web/components/routes/workspace/media-tab/ui/reference-images/reference-images-panel.tsx (2)
apps/pro-web/lib/utils.ts (1)
  • cn (9-11)
apps/pro-web/components/routes/workspace/media-tab/ui/reference-images/reference-upload-slot.tsx (1)
  • ReferenceUploadSlot (15-178)
apps/pro-web/components/routes/workspace/media-tab/ui/canvas/media-canvas.tsx (4)
apps/pro-web/components/routes/workspace/media-tab/wizards/steps/select-size-step.tsx (1)
  • FrameSize (5-11)
apps/pro-web/lib/helpers/workspace/media.ts (1)
  • Template (1-8)
apps/pro-web/lib/utils.ts (1)
  • cn (9-11)
apps/pro-web/components/shared/image-display.tsx (1)
  • ImageDisplay (22-188)
🔇 Additional comments (13)
apps/pro-web/components/routes/workspace/media-tab/ui/sidebar/index.ts (1)

1-1: LGTM!

Clean barrel export following the named export guideline.

apps/pro-web/components/routes/workspace/media-tab/media-tab-wrapper.tsx (1)

1-9: LGTM! Clean refactor to relative import.

The removal of the "use client" directive and switch to a relative import path are appropriate changes, allowing this wrapper to remain a server component while MediaWorkspace (the child) handles client-side state.

apps/pro-web/components/routes/workspace/media-tab/ui/canvas/index.ts (1)

1-1: LGTM!

Standard barrel export following project conventions.

apps/pro-web/components/routes/workspace/media-tab/wizards/index.ts (1)

1-2: LGTM!

Clean barrel exports aggregating the wizards module and step components.

apps/pro-web/components/routes/workspace/media-tab/ui/reference-images/index.ts (1)

1-2: LGTM!

Properly structured barrel export for the reference images module.

apps/pro-web/components/routes/workspace/media-tab/wizards/media-wizards.tsx (3)

59-86: Verify the biome-ignore suppression is correct.

Similar to the size wizard, this useMemo only includes [allTemplates, isLoadingTemplates] but closes over onTemplateSelect, onSizeSelect, and onDialogClose. This could lead to stale closures.

The same verification script above will help confirm callback stability from the parent.


88-109: Verify the biome-ignore suppression is correct.

This useMemo includes [libraryImages, referenceImages] but closes over onImageSelect and onDialogClose, which could become stale.

The verification script mentioned earlier will help confirm callback stability.


98-103: Good defensive check for reference image limit.

The library step correctly enforces the 4-image limit by only calling onImageSelect when referenceImages.length < 4. This prevents exceeding the maximum reference images.

apps/pro-web/components/routes/workspace/media-tab/media-workspace.tsx (1)

83-89: Verify the intentional image reset behavior.

The useEffect resets the generated image whenever selectedTemplate?.id or selectedSize?.id changes. The biome-ignore indicates this is intentional, but consider whether users expect their generated image to persist when changing size (for example, to preview the same image at different aspect ratios).

Confirm with the product team whether:

  1. Changing size should reset the image (current behavior)
  2. Or if the image should be preserved and re-displayed at the new size
apps/pro-web/components/routes/workspace/media-tab/wizards/steps/select-template-step.tsx (2)

32-48: Well-implemented loading and empty states.

The component properly handles three states: loading (with spinner), empty (with message), and content. This provides good user feedback.


50-100: Good use of CSS masonry layout for templates.

The columns-1 sm:columns-2 md:columns-3 lg:columns-4 approach with break-inside-avoid-column is an excellent way to create a responsive masonry grid for variable-height template previews. The hover effects and badge overlays provide nice visual polish.

apps/pro-web/components/routes/workspace/media-tab/ui/canvas/media-canvas.tsx (2)

77-105: Complex responsive sizing logic is well-structured.

The dynamic className generation using cn() with multiple conditional size variants provides comprehensive responsive sizing for different aspect ratios. The logic is clear and well-commented.


175-262: Version history feature is well-implemented.

The version history popup provides good UX with:

  • Left/right navigation buttons
  • Current version highlighting
  • Smooth carousel animation
  • Gradient fade edges
  • Close button

The implementation is comprehensive and user-friendly.

Comment on lines +125 to +136
<MediaWizards
dialogStep={dialogStep}
frameSizes={frameSizes}
allTemplates={allTemplates}
isLoadingTemplates={isLoadingTemplates}
libraryImages={libraryImages}
referenceImages={referenceImages}
onDialogClose={() => setDialogStep(null)}
onSizeSelect={setSelectedSize}
onTemplateSelect={setSelectedTemplate}
onImageSelect={addImageFromLibrary}
/>
Copy link
Contributor

@coderabbitai coderabbitai bot Nov 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Callbacks passed to MediaWizards are not stable.

The addImageFromLibrary function (line 135) is defined inline in the component and will have a new identity on each render. This confirms the concern raised in the MediaWizards review about stale closures in useMemo.

Wrap the callback in useCallback:

const addImageFromLibrary = useCallback((image: string) => {
  if (referenceImages.length < 4) {
    setReferenceImages([...referenceImages, image])
  }
}, [referenceImages])

Note: setSelectedSize and setSelectedTemplate from the context are likely stable, but verify that setDialogStep is also stable or wrap it accordingly.

🤖 Prompt for AI Agents
In apps/pro-web/components/routes/workspace/media-tab/media-workspace.tsx around
lines 125 to 136, the inline callback addImageFromLibrary is recreated each
render causing unstable props for MediaWizards and potential stale closures;
wrap addImageFromLibrary in useCallback so it retains identity and captures
current referenceImages via dependency array (e.g. [referenceImages]) and update
its body to push a new array when adding an image; also verify whether
setDialogStep, setSelectedSize and setSelectedTemplate are stable (from context
or useState) and wrap them in useCallback if they are not to prevent passing
unstable handlers to MediaWizards.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can revise this in a new PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AndlerRL, sounds good! Would you like me to create a follow-up issue to track this optimization for the next PR?


🧠 Learnings used
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 376
File: apps/masterbots.ai/components/routes/chat/chat.tsx:92-102
Timestamp: 2025-02-17T16:51:19.102Z
Learning: For the Chat component in apps/masterbots.ai/components/routes/chat/chat.tsx, the developer prefers to verify potential optimizations through local testing before accepting suggestions, particularly for performance-related changes like useCallback usage in debounce implementations.

Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to **/*.tsx : Avoid inline arrow functions in JSX props; use stable function references for event handlers

Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Separate presentation from business logic and compose small components

Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/**/*.tsx : Order React component files: imports, constants, component, styled components, types/interfaces

Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to apps/{web,pro-web}/components/shared/**/*.{ts,tsx} : Store reusable UI elements in components/shared/

Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-09-04T21:31:18.830Z
Learning: The pro-web workspace system has identified performance bottlenecks in markdown parsing, AI streaming response handling, selection range management, Base64 document processing, and multiple debounced state operations that require optimization and better coordination.

Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-09-04T21:31:18.830Z
Learning: Successfully created comprehensive GitHub issue #555 consolidating performance feedback and edge-case management for pro-web workspace features, including prioritized action items, testing requirements, and specific file references for implementation.

Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to apps/{web,pro-web}/**/*.tsx : Use functional components and hooks; type props with a TypeScript interface

Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-09-04T21:31:18.830Z
Learning: The pro-web workspace features have complex performance considerations including markdown parsing optimization, AI streaming response handling, state persistence coordination, and selection range management that require careful monitoring and optimization.

Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to apps/{web,pro-web}/**/*.tsx : Order component files: imports → constants → component → styled components → types/interfaces

Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 542
File: apps/web/components/layout/profile/layout.tsx:67-68
Timestamp: 2025-08-29T20:34:24.433Z
Learning: AndlerRL prefers skeleton loading states over conditional rendering for better UX when components are waiting for data to load. Components should show loading indicators rather than blank spaces.

Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 584
File: apps/pro-web/app/api/generate-images/route.ts:86-107
Timestamp: 2025-11-14T19:14:07.243Z
Learning: In apps/pro-web/app/api/generate-images/route.ts, the hardcoded 'image/png' MIME type for Gemini previousImage is intentional—LLM-generated images are PNG by default. When the library/template features are added (allowing user-uploaded reference images), the architecture should use Next.js server actions with checksum-based caching (computeChecksum fn) to handle files larger than the 2.5-3MB API route limit, rather than detecting MIME types in the API route directly.

Comment on lines +20 to +23
interface FrameSize {
id: string
name: string
}
Copy link
Contributor

@coderabbitai coderabbitai bot Nov 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Duplicate FrameSize type definition.

This FrameSize interface is a subset of the one exported from select-size-step.tsx (lines 5-11). Having multiple definitions risks inconsistency.

Import the full FrameSize type from the shared location:

+import type { FrameSize } from '../../wizards/steps/select-size-step'
 import type { Template } from '@/lib/helpers/workspace/media'
 import { cn } from '@/lib/utils'
 import { ChevronLeft, ChevronRight, X } from 'lucide-react'

-interface FrameSize {
-  id: string
-  name: string
-}

Or better yet, export FrameSize from a shared types file like apps/pro-web/lib/helpers/workspace/media.ts alongside Template.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
interface FrameSize {
id: string
name: string
}
import type { FrameSize } from '../../wizards/steps/select-size-step'
import type { Template } from '@/lib/helpers/workspace/media'
import { cn } from '@/lib/utils'
import { ChevronLeft, ChevronRight, X } from 'lucide-react'
🤖 Prompt for AI Agents
In apps/pro-web/components/routes/workspace/media-tab/ui/canvas/media-canvas.tsx
around lines 20 to 23, there is a duplicate FrameSize interface that mirrors the
one exported by select-size-step.tsx; remove this local definition and import
the shared FrameSize type instead (either directly from select-size-step.tsx or
— preferably — from a common types file such as
apps/pro-web/lib/helpers/workspace/media.ts where you should add/export
FrameSize alongside Template), then update any local references to use the
imported type to avoid duplication and keep a single source of truth.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's take this clean up in a new PR

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AndlerRL, sounds good! Would you like me to create a GitHub issue to track this type consolidation cleanup for a future PR?


🧠 Learnings used
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 584
File: apps/pro-web/app/api/generate-images/route.ts:86-107
Timestamp: 2025-11-14T19:14:07.243Z
Learning: In apps/pro-web/app/api/generate-images/route.ts, the hardcoded 'image/png' MIME type for Gemini previousImage is intentional—LLM-generated images are PNG by default. When the library/template features are added (allowing user-uploaded reference images), the architecture should use Next.js server actions with checksum-based caching (computeChecksum fn) to handle files larger than the 2.5-3MB API route limit, rather than detecting MIME types in the API route directly.

Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 542
File: apps/web/components/layout/profile/layout.tsx:67-68
Timestamp: 2025-08-29T20:34:24.433Z
Learning: AndlerRL prefers skeleton loading states over conditional rendering for better UX when components are waiting for data to load. Components should show loading indicators rather than blank spaces.

Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-09-04T21:31:18.830Z
Learning: Successfully created comprehensive GitHub issue #555 consolidating performance feedback and edge-case management for pro-web workspace features, including prioritized action items, testing requirements, and specific file references for implementation.

Comment on lines +72 to +77
// Determine model: use gemini for editing existing images, gpt for new generation
const resolveImageModel = (hasImage: boolean): ImageModel => {
return hasImage ? 'gemini-2.5-flash-image' : 'gpt-image-1'
}

const selectedModel: ImageModel = resolveImageModel(!!generatedImage)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

Verify model selection logic consistency.

The resolveImageModel function and selectedModel state only consider generatedImage, but handlePromptSubmit (lines 88-91) evaluates both generatedImage AND selectedTemplate.filePath to determine hasBaseImage. This inconsistency means selectedModel may not accurately reflect the actual model that will be used during generation.

Consider updating line 77 to match the handlePromptSubmit logic:

-const selectedModel: ImageModel = resolveImageModel(!!generatedImage)
+const selectedModel: ImageModel = resolveImageModel(!!generatedImage || !!selectedTemplate?.filePath)

Or refactor to compute hasBaseImage once and reuse it in both places.




🏁 Script executed:

#!/bin/bash
# Read the full use-workspace-media.tsx file to verify the logic
cat apps/pro-web/lib/hooks/use-workspace-media.tsx

Length of output: 5139


🏁 Script executed:

#!/bin/bash
# Search for how selectedModel is used in the file
rg -n "selectedModel" apps/pro-web/lib/hooks/use-workspace-media.tsx -A 2 -B 2

Length of output: 391


🏁 Script executed:

#!/bin/bash
# Search for selectedTemplate usage to understand its structure
rg -n "selectedTemplate" apps/pro-web/lib/hooks/use-workspace-media.tsx -C 3

Length of output: 1723


🏁 Script executed:

#!/bin/bash
# Search for generatedImage usage to understand when it's set
rg -n "generatedImage" apps/pro-web/lib/hooks/use-workspace-media.tsx -C 2

Length of output: 1227


🏁 Script executed:

#!/bin/bash
# Look for the handlePromptSubmit function definition and its hasBaseImage logic
rg -n "handlePromptSubmit\|hasBaseImage" apps/pro-web/lib/hooks/use-workspace-media.tsx -A 5 -B 2

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check the ImageModel type definition to understand valid values
rg -n "type ImageModel\|enum ImageModel\|ImageModel =" apps/pro-web/lib/hooks/use-workspace-media.tsx -B 2 -A 5

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search for useImageGeneration hook to understand what it returns
rg -n "useImageGeneration" apps/pro-web/lib/hooks/ -B 2 -A 10

Length of output: 3680


🏁 Script executed:

#!/bin/bash
# Check how the hook is used/exported
rg -n "export.*useWorkspaceMedia\|export default" apps/pro-web/lib/hooks/use-workspace-media.tsx

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for any model selection in the entire hooks directory
rg -n "gemini-2.5-flash-image\|gpt-image-1" apps/pro-web/lib/hooks/ -B 2 -A 2

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search for where resolveImageModel or selectedModel might be called/used
rg -n "resolveImageModel\|selectedModel" apps/pro-web/ -g '!node_modules' -C 2

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search for where selectedModel from useWorkspaceMedia is consumed
rg -n "selectedModel" apps/pro-web/ -g '!node_modules' -g '!*.test.*' -C 3

Length of output: 22078


🏁 Script executed:

#!/bin/bash
# Check if there are any TypeScript exports showing Template interface including filePath
rg -n "interface Template\|type Template" apps/pro-web/lib/helpers/ -A 10

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Find all files in media-tab that might use useWorkspaceMedia
find apps/pro-web/components/routes/workspace/media-tab -type f -name "*.tsx" -o -name "*.ts"

Length of output: 1254


🏁 Script executed:

#!/bin/bash
# Search for imports of useWorkspaceMedia in media-tab
rg -n "useWorkspaceMedia" apps/pro-web/components/routes/workspace/media-tab/ -B 2 -A 5

Length of output: 1736


🏁 Script executed:

#!/bin/bash
# Check the Template type definition to confirm filePath property
rg -n "type Template\|interface Template\|filePath" apps/pro-web/lib/helpers/workspace/media -B 2 -A 10

Length of output: 80


🏁 Script executed:

#!/bin/bash
# Search for Template type definition across the lib/helpers directory
rg -n "type Template\|interface Template" apps/pro-web/lib/helpers/ -B 2 -A 10

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Find the media helper file
find apps/pro-web/lib/helpers -name "*media*" -type f

Length of output: 43


🏁 Script executed:

#!/bin/bash
# Check what's exported from the media helper mentioned in imports
rg -n "export.*Template\|filePath" apps/pro-web/lib/helpers/ -B 2 -A 3 | head -50

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Read the media.ts helper file to see Template definition
cat apps/pro-web/lib/helpers/workspace/media.ts

Length of output: 4705


Fix model selection logic inconsistency in resolveImageModel usage.

The selectedModel state (line 77) only considers generatedImage, but handlePromptSubmit (line 90) evaluates both generatedImage and selectedTemplate.filePath to determine the actual model. When a template with filePath exists but generatedImage is null, selectedModel incorrectly reflects 'gpt-image-1' while the actual generation uses 'gemini-2.5-flash-image'.

Update line 77 to match the logic in handlePromptSubmit:

-const selectedModel: ImageModel = resolveImageModel(!!generatedImage)
+const selectedModel: ImageModel = resolveImageModel(!!generatedImage || !!selectedTemplate?.filePath)

This ensures consistent model selection throughout the hook and maintains single source of truth for the selectedModel exposed via the context provider.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Determine model: use gemini for editing existing images, gpt for new generation
const resolveImageModel = (hasImage: boolean): ImageModel => {
return hasImage ? 'gemini-2.5-flash-image' : 'gpt-image-1'
}
const selectedModel: ImageModel = resolveImageModel(!!generatedImage)
// Determine model: use gemini for editing existing images, gpt for new generation
const resolveImageModel = (hasImage: boolean): ImageModel => {
return hasImage ? 'gemini-2.5-flash-image' : 'gpt-image-1'
}
const selectedModel: ImageModel = resolveImageModel(!!generatedImage || !!selectedTemplate?.filePath)
🤖 Prompt for AI Agents
In apps/pro-web/lib/hooks/use-workspace-media.tsx around lines 72 to 77, the
selectedModel calculation only checks generatedImage but handlePromptSubmit uses
both generatedImage and selectedTemplate.filePath to choose the image model;
update the selectedModel assignment to use the same predicate as
handlePromptSubmit (i.e., treat presence of generatedImage OR
selectedTemplate.filePath as “hasImage” and pick 'gemini-2.5-flash-image',
otherwise 'gpt-image-1'), keeping the ImageModel type and ensuring you reference
selectedTemplate safely (null/undefined checks) to avoid runtime errors.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
apps/pro-web/components/routes/workspace/workspace-tab-menu.tsx (1)

135-135: Recheck cursor-pointer on disabled items and inline handlers

Adding cursor-pointer on the trigger button and menu items improves affordance, but it may override disabled-state styling so that the pointer cursor still appears even when disabled is true. Also, the inline onClick={() => handleAction(...)} handlers here will be re-created every render; our TSX guidelines prefer stable function references for event handlers. Both are minor, but worth revisiting if you notice UX or perf issues. As per coding guidelines

Also applies to: 170-172, 197-197

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5abc70a and 7aa9aa0.

📒 Files selected for processing (2)
  • apps/pro-web/components/routes/workspace/workspace-tab-menu.tsx (6 hunks)
  • apps/pro-web/types/index.ts (3 hunks)
🧰 Additional context used
📓 Path-based instructions (9)
apps/{web,pro-web}/types/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Place shared TypeScript definitions under types/

Keep TypeScript type definitions under types/

Files:

  • apps/pro-web/types/index.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Avoid default exports; prefer named exports
Use meaningful variable names; prefix booleans with is/has/does/should
Use interface for objects/classes; type for unions/tuples/aliases; enum for fixed sets; const for literals
Avoid any; prefer specific types
Leverage type inference where clear; annotate function params and return types
Prefer type assertions with 'as' over angle-bracket syntax
Use type guards to narrow types in conditionals

**/*.{ts,tsx}: Avoid default exports; prefer named exports
Use modern JavaScript features with TypeScript across the codebase
Use meaningful names; prefix booleans with is/has/does/should (e.g., isDisabled)
Receive an object and return an object (RORO) for functions interfacing with external services
Type definitions: use interface for objects/classes; type for unions/tuples/aliases; const for literals; enum for fixed sets
Avoid any; prefer specific types
Leverage type inference; omit explicit annotations when obvious
Add explicit type annotations for function parameters and return values
Prefer type assertions with as over angle-bracket syntax
Use type guards to narrow types within conditionals
Favor composition over inheritance in code structure

**/*.{ts,tsx}: Avoid default exports; prefer named exports
Prefer RORO (Receive an object, return an object) for function signatures, especially for external service interactions
Use interface for object shapes/classes; type for unions/tuples/aliases; const for literals; enum for fixed enumerations
Avoid using any; prefer precise types
Leverage type inference when clear; omit redundant annotations
Explicitly annotate function parameters and return types
Prefer type assertions with as over angle-bracket syntax
Use type guards to narrow types safely
Use meaningful variable names; prefix booleans with is/has/does/should
Favor composition over inheritance
Use lowercase dash-separated names for files and folders; use extensions like .config.ts, .test.ts, .context.tsx, .typ...

Files:

  • apps/pro-web/types/index.ts
  • apps/pro-web/components/routes/workspace/workspace-tab-menu.tsx
apps/{web,pro-web}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

apps/{web,pro-web}/**/*.{ts,tsx}: Use lowercase kebab-case for directories and filenames (components can omit extension)
Verify DOM operations and consider timing (RAF/delays) when manipulating the DOM in React
Use Tailwind CSS utility classes for styling React components

apps/{web,pro-web}/**/*.{ts,tsx}: Use TypeScript to define React props types (interfaces for props)
Use custom hooks (useMBChat, useThread, useSidebar, useModel) for domain-specific state and keep providers focused and composed hierarchically
Separate presentation from business logic and compose small components
Use hasura.service.ts for all GraphQL operations from UI layers

apps/{web,pro-web}/**/*.{ts,tsx}: Prefer Server Components; use the use client directive only when client-side features are required
Implement Nested Layouts using the App Router
Use Streaming and Suspense in Next.js 14/15 where appropriate
Follow Next.js file conventions as per documentation
Use IndexedDB for local caching to enable immediate UI updates

Files:

  • apps/pro-web/types/index.ts
  • apps/pro-web/components/routes/workspace/workspace-tab-menu.tsx
**/*

📄 CodeRabbit inference engine (CLAUDE.md)

**/*: Use lowercase with dash-separated directory and file names; use specific extensions: .config.ts, .test.ts, .context.tsx, .type.ts, .hook.ts; components may omit extension
Use Bun for package management and scripts instead of npm/yarn
Use Biome for formatting and linting via bun format-and-lint:fix; avoid Prettier/ESLint configs

Files:

  • apps/pro-web/types/index.ts
  • apps/pro-web/components/routes/workspace/workspace-tab-menu.tsx
apps/{web,pro-web}/types/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Place shared TypeScript types under types/

Files:

  • apps/pro-web/types/index.ts
apps/{web,pro-web}/components/routes/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Place page-specific components under components/routes/[feature]/

Organize page-specific components under components/routes/

Files:

  • apps/pro-web/components/routes/workspace/workspace-tab-menu.tsx
apps/{web,pro-web}/**/*.tsx

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

apps/{web,pro-web}/**/*.tsx: Declare React components with the function keyword
Name React components using PascalCase
Order component files: imports → constants → component → styled components → types/interfaces
Use functional components and hooks; type props with a TypeScript interface
Use regular function references (not inline arrows) for React event handlers to avoid extra re-renders

apps/{web,pro-web}/**/*.tsx: Use regular function references for event handlers instead of inline arrow functions in JSX
Declare React components with the function keyword (function ComponentName() {})
Use PascalCase for React component names
Order React component files: imports, constants, component, styled components, types/interfaces
Style components with Tailwind CSS utility classes

Files:

  • apps/pro-web/components/routes/workspace/workspace-tab-menu.tsx
**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

**/*.tsx: Avoid inline arrow functions in JSX props; use stable function references for event handlers
Declare React components with the function keyword (functional components)
Use PascalCase for React component names
Use functional components and hooks instead of class components
Type component props with TypeScript interfaces

Files:

  • apps/pro-web/components/routes/workspace/workspace-tab-menu.tsx
apps/{web,pro-web}/components/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Order component files: imports → constants → component → styled components → types/interfaces

Files:

  • apps/pro-web/components/routes/workspace/workspace-tab-menu.tsx
🧠 Learnings (12)
📓 Common learnings
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 584
File: apps/pro-web/app/api/generate-images/route.ts:86-107
Timestamp: 2025-11-14T19:14:07.226Z
Learning: In apps/pro-web/app/api/generate-images/route.ts, the hardcoded 'image/png' MIME type for Gemini previousImage is intentional—LLM-generated images are PNG by default. When the library/template features are added (allowing user-uploaded reference images), the architecture should use Next.js server actions with checksum-based caching (computeChecksum fn) to handle files larger than the 2.5-3MB API route limit, rather than detecting MIME types in the API route directly.
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-09-04T21:31:18.830Z
Learning: Successfully created comprehensive GitHub issue #555 consolidating performance feedback and edge-case management for pro-web workspace features, including prioritized action items, testing requirements, and specific file references for implementation.
📚 Learning: 2025-06-10T05:48:25.508Z
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 504
File: apps/masterbots.ai/app/api/generate-images/route.ts:58-80
Timestamp: 2025-06-10T05:48:25.508Z
Learning: In apps/masterbots.ai/app/api/generate-images/route.ts, the conditional check for modelId === 'gpt-image-1' is correct and uses the OpenAI client directly to handle this advanced model, while other models like 'dall-e-2' and 'dall-e-3' use the AI SDK. This implementation pattern is appropriate for handling different model capabilities.

Applied to files:

  • apps/pro-web/types/index.ts
📚 Learning: 2025-06-10T05:48:25.508Z
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 504
File: apps/masterbots.ai/app/api/generate-images/route.ts:58-80
Timestamp: 2025-06-10T05:48:25.508Z
Learning: GPT-Image-1 is a legitimate and advanced OpenAI image generation model released in March 2025 as the successor to DALL·E 3. It's built on the multimodal GPT-4o architecture and supports enhanced capabilities including: up to 4096×4096 resolution, improved text rendering, image-to-image generation, inpainting/editing, multiple output formats (PNG, JPEG, WebP), transparent/opaque backgrounds, and both b64_json and URL response formats. It should be used with the OpenAI client directly rather than the experimental AI SDK for full feature support.

Applied to files:

  • apps/pro-web/types/index.ts
📚 Learning: 2025-11-14T19:14:07.226Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 584
File: apps/pro-web/app/api/generate-images/route.ts:86-107
Timestamp: 2025-11-14T19:14:07.226Z
Learning: In apps/pro-web/app/api/generate-images/route.ts, the hardcoded 'image/png' MIME type for Gemini previousImage is intentional—LLM-generated images are PNG by default. When the library/template features are added (allowing user-uploaded reference images), the architecture should use Next.js server actions with checksum-based caching (computeChecksum fn) to handle files larger than the 2.5-3MB API route limit, rather than detecting MIME types in the API route directly.

Applied to files:

  • apps/pro-web/types/index.ts
📚 Learning: 2025-06-10T05:48:25.508Z
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 504
File: apps/masterbots.ai/app/api/generate-images/route.ts:58-80
Timestamp: 2025-06-10T05:48:25.508Z
Learning: The 'gpt-image-1' is a valid and new OpenAI image generation model that can be used with the OpenAI images.generate() API. It should be treated as a legitimate model ID alongside 'dall-e-2' and 'dall-e-3' in image generation applications.

Applied to files:

  • apps/pro-web/types/index.ts
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to apps/{web,pro-web}/**/*.tsx : Order component files: imports → constants → component → styled components → types/interfaces

Applied to files:

  • apps/pro-web/components/routes/workspace/workspace-tab-menu.tsx
📚 Learning: 2025-09-04T21:31:18.830Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-09-04T21:31:18.830Z
Learning: The pro-web workspace system has identified performance bottlenecks in markdown parsing, AI streaming response handling, selection range management, Base64 document processing, and multiple debounced state operations that require optimization and better coordination.

Applied to files:

  • apps/pro-web/components/routes/workspace/workspace-tab-menu.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to apps/{web,pro-web}/components/**/*.tsx : Order component files: imports → constants → component → styled components → types/interfaces

Applied to files:

  • apps/pro-web/components/routes/workspace/workspace-tab-menu.tsx
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Pro workspace editors: controlled/uncontrolled patterns, Markdown utilities, section state sync, and timed DOM operations

Applied to files:

  • apps/pro-web/components/routes/workspace/workspace-tab-menu.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to apps/{web,pro-web}/components/shared/**/*.{ts,tsx} : Store reusable UI elements in components/shared/

Applied to files:

  • apps/pro-web/components/routes/workspace/workspace-tab-menu.tsx
📚 Learning: 2025-04-26T10:58:44.341Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 465
File: apps/masterbots.ai/components/routes/browse/browse-list.tsx:1-1
Timestamp: 2025-04-26T10:58:44.341Z
Learning: The browse-list.tsx component and related components in the browse directory are redundant since thread-list.tsx has been developed to support all pages including public pages, and should be removed to simplify the codebase.

Applied to files:

  • apps/pro-web/components/routes/workspace/workspace-tab-menu.tsx
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to apps/{web,pro-web}/**/*.tsx : Use functional components and hooks; type props with a TypeScript interface

Applied to files:

  • apps/pro-web/components/routes/workspace/workspace-tab-menu.tsx
🔇 Additional comments (9)
apps/pro-web/types/index.ts (5)

448-448: LGTM!

Clean extension of the provider union type to support Google alongside OpenAI.


453-457: Model ID verified as correct.

The model ID 'gemini-2.5-flash-image' is the correct identifier for Google Gemini 2.5 Flash image generation in the Google GenAI API, as documented in Google's official sources. The code is correct as written.


462-462: The type widening is not a breaking change—all consumers already handle both provider types.

The API route and hook both use runtime checks (.startsWith(), === comparisons) to route based on model ID values, not compile-time type dispatch. The API route explicitly handles Gemini models, gpt-image-1, and DALL-E models through these runtime checks, and the hook determines the provider via modelId.startsWith('gemini-'). Neither code relies on type-based dispatch, so widening modelId from OpenAIImageModel to ImageModel presents no breaking changes. The implementation was already designed to support multiple providers.

Likely an incorrect or invalid review comment.


628-632: All generateImage call sites verified and correct.

The signature changes in apps/pro-web are properly implemented:

  1. Breaking change confirmed: modelId parameter widened from OpenAIImageModel to ImageModel (union of OpenAI and Google Gemini models). Call sites apps/pro-web/components/shared/image-generator.tsx:57 and apps/pro-web/lib/hooks/use-workspace-media.tsx:51 pass correct types.

  2. Non-breaking addition confirmed: Optional previousImageData?: GeneratedImage parameter correctly used in apps/pro-web/lib/hooks/use-workspace-media.tsx:115 for edit chaining workflows.

  3. Cross-provider editing supported: The implementation allows passing a DALL-E image as reference for Gemini models (or vice versa) via the previousImageData parameter, with no type-level validation—this appears intentional for flexible image editing workflows.


478-478: Cross-provider model support is correctly implemented.

Verification confirms that GeneratedImage consumers properly handle both OpenAI and Google models:

  • Type definition: ImageModel = OpenAIImageModel | GoogleImageModel correctly unions both provider types
  • API routing: generate-images/route.ts has conditional logic for Gemini and GPT-Image-1 models, with DALL-E fallback
  • Display layer: generated-image.tsx accepts base64 + mimeType (provider-agnostic)
  • Helpers: Image creation and extraction functions work with any ImageModel without assumptions
  • Components: No provider-specific feature logic detected in display or state management layers

The modelId type change from OpenAIImageModel to ImageModel is correctly implemented and all consumers handle cross-provider images appropriately.

apps/pro-web/components/routes/workspace/workspace-tab-menu.tsx (4)

24-34: Icon imports align with new menu items

The expanded lucide-react icon set matches the updated document and media menu options; no issues from a typing or usage perspective.


92-99: Dynamic document view-mode option is coherent

The document-view-mode entry correctly flips label and icon based on viewMode (Preview/FileText vs Edit/TextCursorInputIcon), and the document history/save/export actions remain clear and consistent.


113-115: Media menu IDs and icons fit the media workspace flow

media-sizes, media-library, and media-version clearly map to frame sizing, library, and version history actions and use appropriate icons; assuming onAction is wired for these IDs elsewhere, this looks good.


164-167: Action id rename properly propagated—no updates needed

Verification confirms document-history-rollback is consistently used across handlers and no stale references to the previous id exist. Handler implementation in workspace-content.tsx (line 75) correctly matches the action invocation in workspace-tab-menu.tsx (line 164). No analytics tracking or test files reference this action, so nothing further requires updating.

Copy link
Member

@AndlerRL AndlerRL left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Great initial version for this new Workspace Media Mode 🔥 there are so many things to add on the next PRs, hence, I added comments for the next iterations. With this version, I can now take it for Figma and develop a polished design for the definitive first MVP. Right now we are showing a good core functionality: The AI generation from scratch and from a template—which is great!

Thanks for these efforts, I will be delivering the updated design ASAP by next week. Also, for the next updates, consider to start integrating TanStack Query into the React Context Hooks whenever they fit... hooks that need shared side effects (and small UI states) across components.

In a future, we will be upgrading the State Management to align it with TanStack Query on the rest of the hooks and even further with a new state management to replace React Context Hooks 👀

Merging now! As this version is good to go 👍

Comment on lines +20 to +23
interface FrameSize {
id: string
name: string
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's take this clean up in a new PR

Comment on lines +23 to +58
const validateAndProcessFile = (file: File): string | null => {
// Validate file type
const validTypes = ['image/jpeg', 'image/png', 'image/webp']
if (!validTypes.includes(file.type)) {
console.error(
`Invalid file type for ${file.name}. Please upload JPEG, PNG, or WebP.`,
)
return null
}

// Validate file size (5MB max)
const maxSize = 5 * 1024 * 1024 // 5MB in bytes
if (file.size > maxSize) {
console.error(`File ${file.name} exceeds 5MB limit.`)
return null
}

// Create preview URL
return URL.createObjectURL(file)
}

const validateAndProcessFiles = (files: File[]) => {
const validUrls: string[] = []

// Process up to availableSlots files
const filesToProcess = files.slice(0, availableSlots)

for (const file of filesToProcess) {
const url = validateAndProcessFile(file)
if (url) {
validUrls.push(url)
}
}

return validUrls
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can take this in a new PR.

Comment on lines +125 to +136
<MediaWizards
dialogStep={dialogStep}
frameSizes={frameSizes}
allTemplates={allTemplates}
isLoadingTemplates={isLoadingTemplates}
libraryImages={libraryImages}
referenceImages={referenceImages}
onDialogClose={() => setDialogStep(null)}
onSizeSelect={setSelectedSize}
onTemplateSelect={setSelectedTemplate}
onImageSelect={addImageFromLibrary}
/>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can revise this in a new PR.

}

// Last part is frame, second to last is social media, everything else is name
const frame = parts[parts.length - 1]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 PRO TIP: For variables asignations from different index form the same array source, it is better to use array destructuring. Which destructuring, we can assign the 3 values in a single line, making it easier to read. i.e.: const [ name, socialMedia, frame ] = parts is the equivalent to the 3 constant variables.

Please take the tip in the next PR

@AndlerRL
Copy link
Member

LGTM! Great initial version for this new Workspace Media Mode 🔥 there are so many things to add on the next PRs, hence, I added comments for the next iterations. With this version, I can now take it for Figma and develop a polished design for the definitive first MVP. Right now we are showing a good core functionality: The AI generation from scratch and from a template—which is great!

Thanks for these efforts, I will be delivering the updated design ASAP by next week. Also, for the next updates, consider to start integrating TanStack Query into the React Context Hooks whenever they fit... hooks that need shared side effects (and small UI states) across components.

In a future, we will be upgrading the State Management to align it with TanStack Query on the rest of the hooks and even further with a new state management to replace React Context Hooks 👀

Merging now! As this version is good to go 👍

@coderabbitai create a new issue to track the observations to take in a future PR. Assign Derian to it and provide a plan with the required context and labels for better tracking and AI agentic process.

@AndlerRL AndlerRL merged commit 3c1d231 into develop Nov 21, 2025
4 checks passed
@AndlerRL AndlerRL deleted the feat/media-tab-v1 branch November 21, 2025 19:43
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 21, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Fetch review comments from PR #584 to gather observations for the issue
gh pr view 584 --json reviews,comments --jq '.reviews[] | select(.author.login == "coderabbitai") | {body: .body, state: .state}' | head -50

# Also get regular comments
gh pr view 584 --json comments --jq '.comments[] | select(.author.login == "coderabbitai" or .author.login == "AndlerRL") | {author: .author.login, body: .body}' | head -100

Length of output: 314329


🏁 Script executed:

#!/bin/bash
# Create a comprehensive GitHub issue for future Media Workspace enhancements
gh issue create \
  --title "[pro-web] Media Workspace: Future Enhancements & State Management Upgrades" \
  --body "## Overview

This issue tracks observations and planned enhancements for the Media Workspace feature introduced in PR #584. The initial version provides core functionality for AI image generation from scratch and from templates using GPT-Image-1 and Gemini (Nano Banana).

## Context

**Related PR:** #584 - [pro-web] feat: add image generation with gpt-image-1 and Nano Banana (Gemini) in Media Workspace tab

The current implementation provides:
- Multi-provider image generation (OpenAI & Google Gemini)
- Template-based image generation
- Media wizard workflow (Size → Template → Library)
- Reference images panel
- Version history UI (placeholder)

## Future Enhancements

### 1. State Management Migration
**Priority:** High
**Scope:** Architectural improvement

- [ ] Integrate **TanStack Query** into React Context Hooks for:
  - Shared side effects management
  - Small UI states across components
  - Better caching and synchronization
  - Automatic refetching and background updates

- [ ] Align existing hooks with TanStack Query patterns:
  - \`useWorkspaceMedia\` (\`apps/pro-web/lib/hooks/use-workspace-media.tsx\`)
  - \`useImageGeneration\` (\`apps/pro-web/lib/hooks/use-image-generation.tsx\`)
  - Other workspace-related hooks

- [ ] Long-term: Replace React Context Hooks with modern state management solution
  - Research alternatives (Zustand, Jotai, etc.)
  - Create migration plan
  - Ensure backward compatibility during transition

### 2. Media Workspace Feature Enhancements
**Priority:** Medium-High
**Scope:** Feature development

From review observations, consider:

- [ ] **Template Library Integration**
  - Implement user-uploaded reference images with checksum-based caching
  - Support files larger than 2.5-3MB API route limit using Next.js server actions
  - Add MIME type detection for user uploads (PNG, JPEG, WebP)
  - Expand template management features

- [ ] **Image Editing Capabilities**
  - Enhance edit-mode functionality with Gemini
  - Add image manipulation tools
  - Support multiple edit operations

- [ ] **Version History**
  - Implement actual version tracking (currently placeholder)
  - Add rollback functionality
  - Persist version history

- [ ] **Social Media & Brand Kit**
  - Complete Social Media button implementation (currently TODO)
  - Complete Brand Kit button implementation (currently TODO)
  - Add platform-specific optimizations

- [ ] **UI/UX Polish**
  - Apply updated Figma designs (delivery expected next week)
  - Skeleton loading states (per existing preference)
  - Error handling improvements
  - Accessibility enhancements

### 3. Performance Optimizations
**Priority:** Medium
**Scope:** Performance & optimization

- [ ] Image caching strategy with TanStack Query
- [ ] Lazy loading for template thumbnails
- [ ] Optimize API routes for large payloads
- [ ] Add request debouncing where appropriate

### 4. Testing & Documentation
**Priority:** Medium
**Scope:** Quality assurance

- [ ] Add unit tests for media hooks
- [ ] Add integration tests for image generation flow
- [ ] Document TanStack Query integration patterns
- [ ] Update component documentation

## Technical Notes

**Current Architecture:**
- Uses React Context for state management (\`WorkspaceMediaProvider\`)
- Direct API calls without caching layer
- Manual loading state management

**Target Architecture:**
- TanStack Query for server state
- Optimistic updates and caching
- Automatic background refetching
- Centralized error handling

**Files to Focus On:**
- \`apps/pro-web/lib/hooks/use-workspace-media.tsx\` - Main media context
- \`apps/pro-web/lib/hooks/use-image-generation.tsx\` - Image generation logic
- \`apps/pro-web/app/api/generate-images/route.ts\` - Generation API
- \`apps/pro-web/app/api/media/templates/route.ts\` - Template API
- \`apps/pro-web/components/routes/workspace/media-tab/\` - UI components

## Success Criteria

- [ ] TanStack Query successfully integrated for all media-related data fetching
- [ ] State management is more predictable and easier to maintain
- [ ] Loading states and error handling are consistent across the workspace
- [ ] Performance metrics show improvement in data fetching and caching
- [ ] Updated design from Figma is fully implemented
- [ ] Code follows established patterns for future contributors

## References

- PR #584: https://github.com/bitcashorg/masterbots/pull/584
- TanStack Query Docs: https://tanstack.com/query/latest
- Existing learning: Image generation checksum-based caching pattern (ID: 9caa6185-0076-4b6c-9ef8-ad8c8ba6625b)
- Existing learning: Skeleton loading state preference (ID: 721ae14e-5746-468b-a622-1ca669e59973)

## Assignee

@derianrddev - Please review and break down into actionable tasks as needed.

---
**Note:** This is a tracking issue for incremental improvements. Feel free to create separate issues for individual features as work progresses." \
  --label "enhancement,feature,frontend,state-management" \
  --assignee "derianrddev"

Length of output: 49


@AndlerRL Issue created and assigned to Derian with a detailed, agentic plan and context. I intentionally used the existing labels (enhancement, feature, frontend) after the first attempt failed due to a non-existent label state-management. The plan references our prior learnings on skeleton loading and the PNG/server-actions + checksum approach for Gemini uploads, and consolidates all actionable follow-ups from this PR’s discussion.

If you’d like me to add or create a new label (e.g., state-management or tracking) for better triage, say the word and I’ll update the issue accordingly.


🏁 Script executed:

#!/bin/bash
set -euo pipefail

ISSUE_TITLE="[pro-web] Media Workspace: Future Enhancements & State Management Upgrades"

ISSUE_BODY=$(cat <<'EOF'
## Overview
Tracking follow-ups for the new Media Workspace introduced by PR #584. This will coordinate UX polish, state management migration, API robustness, and feature completeness so we can ship the first polished MVP aligned with the upcoming Figma update (target: by Friday, November 28, 2025).

## Context
- Related PR: #584 — pro-web Media Tab with GPT-Image-1 and Gemini image generation, template workflow, wizards, and reference images.
- Team preferences captured in prior learnings:
  - Use skeleton loading states in UI where possible (avoid blank spaces).
  - For Gemini edit flow, PNG mime is intentional; for user uploads and >3MB files, plan Next.js Server Actions + checksum caching rather than handling in API routes.

## Action Plan (high level)
1) State management and data layer (High)
- [ ] Introduce TanStack Query where hooks have shared side effects or server state (templates, versions, library items).
- [ ] Migrate media-related fetches (e.g., /api/media/templates) to queries with caching, background refetch, and error boundaries.
- [ ] Draft roadmap to replace ad-hoc React Context with a scalable store (e.g., Zustand/Jotai) that coexists cleanly with TanStack Query.

2) API/Robustness (High)
- [ ] apps/pro-web/app/api/generate-images/route.ts
  - [ ] Validate Gemini model IDs via a supported list/map.
  - [ ] Extract Gemini content part type (e.g., GeminiContentPart).
  - [ ] Simplify/strengthen response parsing via optional chaining; add structured warning logs for unexpected shapes.
- [ ] Plan server actions + checksum-based upload pipeline for user-provided reference images; respect 2.5–3MB API route limits.
- [ ] Centralize model→provider mapping rather than relying on string prefixes.

3) UX/Interactions (Medium-High)
- [ ] Replace inline JSX arrow handlers with named, stable callbacks across Media Workspace (sidebar buttons, wizards, reference grid, version nav) to match guidelines and reduce re-renders.
- [ ] Fix history submenu condition in workspace-tab-menu (ensure 'document-history' and/or 'media-version' are recognized).
- [ ] Fix unconditional “Unknown menu action” secondary log in workspace-content (log only in default case).
- [ ] Media mode attachments: clarify behavior (disable/clear or integrate) so UI matches functionality.
- [ ] Use functional setState for reference images updates to avoid stale state on rapid interactions.

4) Versioning & persistence (Medium)
- [ ] Wire actual image version history (source from context/backend rather than static array).
- [ ] Implement rollback and annotate versions with prompts/models.

5) Templates & Library (Medium)
- [ ] Expand template filters (social/platform/frame) and add lazy-loading for thumbnails.
- [ ] Library import: multiple uploads, validations, and error surfaced via toasts; persist to cache/store.

6) Testing & Docs (Medium)
- [ ] Unit tests for use-workspace-media and use-image-generation (new edit chaining).
- [ ] Integration tests: end-to-end generation (new + edit), error overlays, retry paths.
- [ ] Document TanStack Query patterns and media workflow architecture.

## Success Criteria
- [ ] Media data flows use TanStack Query (templates, versions, library); predictable loading/error states with skeletons.
- [ ] Generation API is resilient to provider quirks and logs actionable diagnostics.
- [ ] No inline JSX arrow handlers remain in hot paths; handler identities are stable.
- [ ] Version history and rollback work against real data.
- [ ] Attachments behavior is explicit and consistent in media mode.
- [ ] Figma-polished MVP aligns with design delivered by Nov 28, 2025.

## Backlinks
- PR #584: https://github.com/bitcashorg/masterbots/pull/584

## Notes
- This is a tracking issue. As work proceeds, feel free to break items into separate issues and link them here.
EOF
)

# Create the issue with existing labels only
gh issue create \
  --title "$ISSUE_TITLE" \
  --body "$ISSUE_BODY" \
  --assignee "derianrddev" \
  --label enhancement \
  --label feature \
  --label frontend

Length of output: 51


@AndlerRL Done. I created and assigned the tracking issue with plan and context: #591. It carries the existing labels enhancement, feature, and frontend, and is assigned to @derianrddev.

Highlights included in the plan:

  • State/data layer (High): Introduce TanStack Query for media server state (templates, versions, library), and draft a roadmap to evolve beyond ad‑hoc React Context while coexisting with TanStack Query.
  • API robustness (High): Validate supported Gemini model IDs, extract a Gemini content-part type, simplify/strengthen response parsing with optional chaining and structured logs, centralize model→provider mapping, and plan Next.js Server Actions + checksum-based caching for user uploads >3MB.
  • UX/Interactions (Med‑High): Replace inline JSX arrow handlers with stable callbacks, fix the history submenu condition in workspace-tab-menu, fix the unconditional “Unknown menu action” log in workspace-content, clarify attachment behavior in media mode, and use functional setState for reference images.
  • Versioning & persistence (Med): Wire real image versions + rollback (replace static array).
  • Templates & Library (Med): Filters by social/frame, lazy-load thumbnails, multiple uploads with validation and toasts, cache/store persistence.
  • Testing & docs (Med): Unit tests for use-workspace-media/use-image-generation (incl. edit chaining), integration tests for generate/edit/error overlays, and docs on TanStack Query patterns.
  • Success criteria and timeline: target first polished MVP aligned with the Figma update by Friday, November 28, 2025.

I also incorporated our existing learnings in the issue:

  • Preference for skeleton loading states in UI.
  • PNG mime for Gemini edits is intentional; for user uploads and larger files we’ll use Server Actions + checksum caching instead of handling in the API route.

If you want me to add a new label like state-management (and then tag the issue), I can create it and update #591. Would you like me to do that?


✏️ Learnings added
Learnt from: AndlerRL
URL: https://github.com/bitcashorg/masterbots/pull/584

Timestamp: 2025-11-21T19:47:50.167Z
Learning: For repo bitcashorg/masterbots (apps/pro-web), AndlerRL prefers integrating TanStack Query into React Context Hooks wherever they fit to manage shared server state and side effects, with a longer-term plan to align broader state management with TanStack Query and potentially replace React Context hooks. Captured from PR #584 discussion on Nov 21, 2025.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-09-04T21:31:18.830Z
Learning: Successfully created comprehensive GitHub issue #555 consolidating performance feedback and edge-case management for pro-web workspace features, including prioritized action items, testing requirements, and specific file references for implementation.

Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 542
File: apps/web/components/layout/profile/layout.tsx:67-68
Timestamp: 2025-08-29T20:34:24.433Z
Learning: AndlerRL prefers skeleton loading states over conditional rendering for better UX when components are waiting for data to load. Components should show loading indicators rather than blank spaces.

Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 584
File: apps/pro-web/app/api/generate-images/route.ts:86-107
Timestamp: 2025-11-14T19:14:07.243Z
Learning: In apps/pro-web/app/api/generate-images/route.ts, the hardcoded 'image/png' MIME type for Gemini previousImage is intentional—LLM-generated images are PNG by default. When the library/template features are added (allowing user-uploaded reference images), the architecture should use Next.js server actions with checksum-based caching (computeChecksum fn) to handle files larger than the 2.5-3MB API route limit, rather than detecting MIME types in the API route directly.

AndlerRL added a commit that referenced this pull request Dec 10, 2025
* fix: increase execution time - image generation

* chore: increase maxDuration

* fix: attachment upload management (#517)

* fix: attachment upload management

* chore: clean up

* perf(impr): log failed chunks

* feat: attachment upt cron n public browse tweaks (#520)

* feat: reresh attch cron + user attach async dep upt

* fix: load more missing props

* fix: attachment expires typeof sql value

* fix: public browse search + load more deps

* perf(impr): trnx support in attch link refresh cron

* [masterbots.ai] feat: stripe subscription plans and promocode support (#513)

* fix whirlpool animation

* feat: add validation for promo codes and subscriptions

* fix: initital coderabbitai recomendations

* chore: add improve to subscription flow

* chore: add card switcher

* chore: impr pro card

* chore: fix custom class

* chore: add free card newcolor

* [masterbots.ai] feat: thread context file (#519)

* feat(wip): thread context file

* fix: typo

* fix: attachment prop dep

* fix: user attachments upt concurrency

* feat(wip): thread context focus on open

* fix: content editable selection on first render

* fix: new line after enabling content editable

* fix: paste text in editable content + paste context

* fix: paste context + show attachment text content in public

* fix: show continue message cta in cutoff content trigger

* fix: contentEditable text encoding

* fix: hook race condition build

* [masterbots.ai] fix: bug fix and improvements (#523)

* fix whirlpool animation

* feat: add validation for promo codes and subscriptions

* fix: initital coderabbitai recomendations

* chore: add improve to subscription flow

* chore: add card switcher

* chore: impr pro card

* chore: fix custom class

* chore: add free card newcolor

* chore: add improvements and medium level bug fix

* feat: add example question modal

* chore: fix biome format

* chore: add modal and botcard redesing

* chore: fix sizes

* chore: enable example questions feat flag

* fix(impr): onboarding card responsiveness + space & bg style

---------

Co-authored-by: Roberto 'Andler' Lucas <contact@andler.dev>

* chore: enable subscription page navigation

* fix: attachment css + optimistic attch upt (#528)

* fix: attachment css + optimistic attch upt

* fix: messageAttachment ref assig loc

* chore: attch cnt read for dev

* [masterbots.ai] feat: onboarding  and ui ux tweaks (#526)

* chore: fix color and new card style

* chore: restore white line

* fix: flicker + include new images

* chore: fix regresion issues

* chore: biome corrections

* fix: layout tweaks + onboard card render

* fix: tailwind class

* fix: tailwind class

---------

Co-authored-by: Roberto 'Andler' Lucas <contact@andler.dev>

* [masterbots.ai] chore(fix): change logic flow (#531)

* perf: dynamic imports (#530)

* perf(wip): dynamic imports

* chore(fix): rm static skeleton

* perf: dynamic imports in chat routes

* fix: tailwind class

* fix: persistent route (#529)

* fix: add persistent route build

* chore: remove comment section

* feat: phase 4, topics & chatbot order fields + new & upt seeds (#522)

* feat(wip): phase 4, topics + cat & chatbot order fields

* chore: add order field in gen types

* chore(wip): upt init config seed, phase 4, category order upt + wip chatbot new descriptions

* style: format and lint

* chore: upt chatbot new descriptions + new bots and prompts

* chore: upt chatbot prompt junction seeds inserts

* chore: upt chatbot categories juntion seeds

* chore: upt chatbots & relationships

* chore: upt chatbots & relationships

* fix: order field permissions + gen

* fix: onboarding chatbot description

* [masterbots.ai] fix: thread popup for threadquestion page (#516)

* update

* fix: update

* update

* update

* update

* update

* fix: thread style

* fix: thread style

* fix: added popup to threadQuestionPage

* fix: update

* fix: sub thread slug update on url:

* fix: update thread question slug navigation

* fix: update thread question slug navigation

* fix: update thread question slug navigation

* fix: update

* fix: update thread path

* fix: update

* fix: update package data

* fix: use proper error handling component on server

* fix: update

* fix: make the selected thread in popup  open by the default

* fix: focus the last sub-thread when know sub-thread slug is on the pathname

* fix: popup flickering

* fix: handle bot page routing and  threadquestion page

* fix: disable link on the bot view page

* fix: question not displaying

* fix: question not displaying

* fix: chatbot page loading more unrelated threads

---------

Co-authored-by: Roberto 'Andler' Lucas <contact@andler.dev>

* [hasura] fix(restore): is_pro + pro-exclusive chatbot table params

* revert: "fix: persistent route (#529)" (#533)

This reverts commit 5a464ab13a01165450fe602f3ec7964e43b14921.

* chore: upt canonical domains (#532)

* chore: upt canonical domains

* fix: getRouteType

* fix: missing canonical domains and topics

* fix: category slug

* fix: hydration warns + continue thread upt after start

* fix: upt init config chatbot inserts

* chore: upt biblebot expertise + chefbot n growbot descr puntuation

* fix: coderabbitai observation

* [materbots.ai] perf: impr onboarding cards ui (#535)

* [masterbots.ai] chore(style): logo updates (#525)

* update

* fix: update

* update

* update

* update

* update

* feat: import  logos

* feat: added logo to app header

* feat: app logo

* chore: user page text

* fix: update

* feat: added bg to auth pages

* fix: update

* fix: wait for page to mount to load custom logos

* fix: update

* fix: update

* fix: update

* fix: update theme to use resolvedTheme instead

* fix: update assets

---------

Co-authored-by: Roberto 'Andler' Lucas <contact@andler.dev>

* perf(impr): overall layout css spacing at mob + footer mob loc

* fix: thread search context (#534)

* update

* fix: update

* update

* update

* update

* update

* fix: thread fetching render on search

* fix: thread fetching render on search

* fix: rm search input from botpage welcome view

* fix: introduce global search component

* fix: clean up browe(public) search

* fix: update

* fix: search from  db on  personal pages instead of the eveilable threads

* fix: search update

* fix: clean up

* chore: upt gemini models ref, web (#538)

* [masterbots.ai] feat: dashboard modal (#536)

* chore:add dashboard modal

* chore: add dashboard to public

* chore:upt design

* chore: add new flow

* chore: build issue + new ui

* chore: fix local storage - user pref

* fix: mobile chat panel a11y

* fix: mobile chat panel a11y

---------

Co-authored-by: Roberto 'Andler' Lucas <contact@andler.dev>

* chore: gpt reasoning model upt (#543)

* fix: new gpt 5 models selection & default

* fix: profile layout render

* [masterbots.ai] feat: impr sidebar nav onboarding (#540)

* chore:add dashboard modal

* chore: add dashboard to public

* chore:upt design

* chore: add new flow

* chore: build issue + new ui

* chore: fix local storage - user pref

* feat: sidebar nav onboarding

* chore: fix build

* chore: upt local storage conditions and debug

* fix: add persistent localstorage selection

* feat: add consistent selection

* fix: onboarding display logic

---------

Co-authored-by: brandonfernandezf <brandon@bitcash.org>
Co-authored-by: bran18 <andreyfdez18@gmail.com>
Co-authored-by: Brandon Fernández <31634868+Bran18@users.noreply.github.com>

* fix: create response stream object model temperature + impr output prompt

* chore: upt default llm

* chore: upt canonical domains + christbot, biblebot and new bot updated

* chore: upt core app folder name

* [pro-web] feat: masterbots pro, working documents (#423)

* wip: pro version layout

* perf(impr): pro navigation + layout

* feat: hasura chatbot pro properties + web TS formatting

* revert: showVerificationNotice condition at sign-up form

* fix: subcategory missing fields

* fix: thread + msg init seeds

* feat(pro): implement specialized pro chat interface components

- Add Pro-specific message, panel and action components
- Create Pro extended layout with improved UI
- Update workspace hooks for Pro interface support
- Add tabs component and markdown utilities
- Update package dependencies

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* feat(workspace): integrate workspace with chat UI

- Display workspace editor above chat input when workspace is active
- Keep chat input available for workspace mode to handle queries
- Update placeholder text to better reflect dual-purpose usage
- Remove separate workspace input component to avoid redundancy

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* feat(workspace): improve workspace integration with chat UI

- Extend workspace area to fill available height
- Standardize input handling by using PromptForm for both modes
- Add conditional logic to handle different input behaviors based on mode
- Improve placeholder text for better user context

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* feat(workspace): always show UI controls with toolbar and workspace

- Display expertise, reasoning, web search and workspace toggle buttons regardless of workspace mode
- Keep workspace toggle button in the main toolbar with other feature toggles
- Keep main right side controls visible regardless of mode
- Only conditionally show chat-specific buttons when in chat mode

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: prevent maximum update depth exceeded in workspace component

- Enhanced useEffect hooks with better null checking and early returns
- Added conditionals to skip unnecessary state updates
- Fixed cascading dropdown behavior for Organization→Department→Project→Document
- Added value comparison in onChange handlers to prevent update loops
- Improved setDocumentContent to only update when values change
- Enhanced logging for better debugging

* fix: resolve maximum update depth exceeded error

- Fixed circular dependency in React hooks
- Added memoization for document options to prevent unnecessary re-renders
- Optimized useEffect hooks with proper dependency arrays
- Added proper state updates batching with requestAnimationFrame
- Improved state synchronization between components
- Added checks to prevent unnecessary state changes

* feat: improved document selector empty state

- Added '---' placeholder for document selector when no documents are available
- Enhanced document options handling in chat-panel-pro.tsx
- Added better disabled state checks for empty document lists
- Improved validation of document selection to handle edge cases

* fix: document selector displaying blank

- Fixed document selector initialization issue
- Added proper handling of null filteredDocumentList
- Added document dropdown state synchronization
- Added extra diagnostics for document selection
- Improved reliability of document type switching

* fix: document selection not working for Campaign A

- Added force re-render in document select dropdown with key
- Fixed document options memoization to create new references
- Added deep copy of document sources to prevent reference issues
- Enhanced debugging to trace document options availability
- Added special handling for Campaign A document options
- Improved option type handling and selection state updates

* fix: text document dropdown not working

- Fixed text document dropdown selection to match spreadsheet functionality
- Added deep copy with JSON stringify/parse for consistent references
- Added force re-render mechanism to ensure dropdown updates
- Enhanced document type selection to handle all document types consistently
- Improved debugging with render IDs to trace document selection issues
- Fixed reference handling for document type changes

* feat: integrate Yoopta rich text editor with context-based state management

  - Add useRichEditor state and toggleRichEditor function to workspace context
  - Update workspace-content to use context-based editor preference
  - Create placeholder implementation for Yoopta editor
  - Add documentation with installation instructions

  The integration persists user preferences for the rich editor across
  sessions and provides an intuitive, minimalist toggle UI.

* fix: prevent runtime errors in thread list and rich text editor

* Revert "fix: prevent runtime errors in thread list and rich text editor"

This reverts commit e61341d875f4f5fcbc05452bdb86de9fd20799b3.

* Revert "feat: integrate Yoopta rich text editor with context-based state management"

This reverts commit 0a79633458e6682bb1cc99ed8f0a6419b3eecba7.

* chore: add context-attachment component

* fix: workspace prompt exe w meta prompt

* chore: sync thread & msgs seeds

* chore: sync thread & msgs seeds

* fix: render ai request to selected working document

* chore(impr): add claude code monorepo ctx

* wip: save content live at cursor pos

* wip: working document live upt

* fix: pro infinite loop in output

* fix: section doc expand

* feat(wip): working document, fix init doc obj

* fix: missing pkg dep

* fix: pro user message

* fix: pro user message

* fix: workspace initial messages

* feat: edit, rewrite, expand workspace ctas

* fix: react render hoisting

* perf: impr project doc nav + saving working doc state in server cache + thread linking

* fix: web build

* feat(wip): thread pop-up chat connect workspace

* feat(wip): chat workspace connection

* fix(wip): workspace ui + chat connect w workspace

* fix: connect workspace chat w/mb chat

* fix: breadcrumb nav consistency w/state

* fix: breadcrumb nav consistency w/state

* fix: workspace doc thread creation + save doc version

* feat(impr): thread popup layout

---------

Co-authored-by: Jun Dam <jun@bitcash.org>
Co-authored-by: Claude <noreply@anthropic.com>

* [web] feat: refactor subscription flow (#549)

* chore: refactor subscription flow

* chore: fix import

* chore: add recent payment

* chore: revert condition

---------

Co-authored-by: Roberto 'Andler' Lucas <contact@andler.dev>

* fix: new thread pop-up ui aligment

* [pro-web] fix: pro workspace ui state & navigation (#552)

* fix: payment api missing routes

* fix: breadcrumb connect with thread documents

* fix: fetch missing docuemnts

* fix: document select & sync remote w local

* fix: document select & sync remote w local

* fix: header breadcrumb navigation + prompt + document creation impr

* fix: tailwindcss conflict

* fix: ts typo

* [pro-web] refactor: ai config, default gpt-5-mini, update routing and workspace (#554)

* fix: active section focus content

* fix: connect workspace prompt to chat panel and ctas

* fix(wip): attach new content to working document in workspace mode

* fix: implement preserved content structure for streaming LLM updates

- Add refs to preserve before/after selection content during streaming updates
- Use validStart position as anchor point for stable text replacement
- Ensure content structure is preserved across multiple LLM iterations
- Reset preserved content refs at start and end of operations
- Apply same logic to both section-based and full document editing modes

* fix: generated ai content in correct working document pos

* fix(wip): working document stream updates + preview section changes

* fix(wip): working document stream updates + preview section changes

* fix: del component unused prop

* fix: followingImages prompt loc in use-mb-chat

* fix: generated-imgage loader

* fix: following img prompt data

* fix: following img prompt data

* perf(impr): following img prompt

* fix: document update padEnd string in LLM responses

* fix: llm document stream results (#557)

* fix: llm document stream results

* fix: debounce save full source

* fix(pro-web): add missing onboarding logic

* [web] feat: upt dynamic og (#545)

* chore(wip): upt dynamic og

* fix: og image render issues

* chore: refactor og version

* chore: add suggestion

* chore: fix build

* chore: remove extra fallback

* chore: fix

---------

Co-authored-by: bran18 <andreyfdez18@gmail.com>
Co-authored-by: Brandon Fernández <31634868+Bran18@users.noreply.github.com>

* [pro-web] fix: refactor doc sourcing; add category dashboard; update hooks & header (#560)

* fix(wip): reactive doc breadcrumb header nav

* fix: breadcrumb navigation with active thread n user docs

* fix: hook arg dep

* fix(wip): build user breadcrumb nav from remote db

* feat: edit section prompt cta + auto-scroll in full source + delete doc section

* perf(impr): copilot instructions

* perf(impr): workspace document prompts

* fix: createWorkspaceMetaPrompt args

* fix(feat): add cron refresh workspace docs api route + add to active workspace doc cta

* fix: init config seeds statement typos

* [web/pro-web] feat: impr user profile and preferences (#561)

* Remove .env file

* Remove .env file

* Remove .env file

* update

* fix: update

* update

* update

* fix: rm breadcrumb on profile page

* fix: arrow pointed right for closed/collapsed and arrow pointed down for open/expanded

* feat: added user profile to preference

* fix: update

* fix: server pages restrictions

* fix: verify email ui

* feat: endpoint route for verify token

* feat: verify email setup

* fix: updating session and validate username

* fix: username update

* fix: prefrences updates

* feat: added theme and font-size setting

* feat: added theme and font-size setting

* fix: merged develop

* fix: update

* fix: update

* fix: google language translation updates

* fix: app clean up

* fix: update anon permision to see Isverified column

* fix:  lint update

* fix: username update func

* fix: rm bredcrum on pref page

* fix: font icons

* fix: update

* fix: build error

* fix: error build

* fix: error build

* fix: rem master.ai folder

* fix: added isUsernameTaken verifycation to  username on auth

* fix: add ts def

* fix: update

* fix: update font size in gloabl.css

---------

Co-authored-by: Jun Dam <jun@100xinvestors.com>
Co-authored-by: Roberto Lucas <andler@bitcash.org>
Co-authored-by: Roberto 'Andler' Lucas <contact@andler.dev>

* fix: thread questions's slug (chat & bot) (#562)

* fix: chat threadquestion showing cinema

* fix: bot page thread question url

* [pro-web] fix: switch to org routing; impr workspace file mgmt + refresh signed links (#563)

* fix: get user remote documents + refresh workspace document cron

* fix(feat): add cron refresh workspace docs api route + add to active workspace doc cta

* fix: init config seeds statement typos

* fix: providers render + onboarding card & sidebar ui tweaks

* fix: refresh workspace document old versions + wip pro flag in threads

* chore: sync latest changes with pro web

* feat: add is_pro flag on mb threads

* fix(pro): import typo

* fix(pro-web): og-image version

* fix(pro-web): upt route type conditions

* fix: missing ts def

* fix(pro-web): typo

* fix: import typo

* [pro-web] fix: workspace mode ui tweak + doc tree render (#565)

* fix: workspace mode ui tweak + doc tree render

* fix: tailwindcss contradicting classname

* chore: route /c clean up in pro + lazy load & loader in pro

* chore: upt prompt agent files (#566)

* [pro-web] fix: workspace chat state reset and thread creation logic (#567)

* fix: workspace chat state reset and thread creation logic

- Add error handling to reset workspaceProcessingState when errors occur
- Fix state cleanup to handle both successful and failed operations
- Remove premature thread creation from document save function
- Allow thread creation to happen naturally through use-mb-chat flow
- Ensure CTAs (edit/rewrite/expand) are re-enabled after errors or success

This fixes the issue where edit/rewrite/expand CTAs remained disabled
after errors and resolves thread creation inconsistencies in workspace mode.

Co-Authored-By: Andler Lucas <andre.rlucas@outlook.com>

* fix: handle undefined threadSlug in workspace document save

- Add early return when no thread exists to save document locally only
- Save to IndexedDB when thread hasn't been created yet
- Prevents TypeScript error from passing undefined to uploadWorkspaceDocument
- Thread will be created when first message is sent via use-mb-chat flow

Co-Authored-By: Andler Lucas <andre.rlucas@outlook.com>

* feat: add complete workspace document metadata when creating threads

- Include organization, department, URL, content, size, versions, expires, and messageIds
- Update threadSlug after thread is created to maintain consistency
- Ensures documents attached to newly created threads have full metadata
- Matches the comprehensive metadata structure used in saveDocument function

Co-Authored-By: Andler Lucas <andre.rlucas@outlook.com>

* feat: upload workspace documents to bucket when creating threads

- Upload documents to bucket using uploadWorkspaceDocument API
- Get proper URLs and metadata from bucket upload
- Fallback to original document data if upload fails
- Ensures workspace documents have same treatment as attachments
- Documents now get bucket URLs, checksums, and versioning like manual saves

Co-Authored-By: Andler Lucas <andre.rlucas@outlook.com>

* fix: resolve TypeScript type mismatch for workspace document versions

- Initialize uploadedDocuments as empty WorkspaceDocumentMetadata array
- Explicitly cast upload result to WorkspaceDocumentMetadata type
- Cast fallback documents with proper versions type
- Fixes Vercel build error with versions field type incompatibility

Co-Authored-By: Andler Lucas <andre.rlucas@outlook.com>

* refactor: use API route for document uploads and optimize upload logic

- Replace direct uploadWorkspaceDocument call with /api/documents/upload
- Only upload documents when new or content has changed
- Check existing documents in thread metadata before uploading
- Merge messageIds when document already exists
- Use fetch API for consistency with other API calls
- Remove uploadWorkspaceDocument import (unused after refactor)

Co-Authored-By: Andler Lucas <andre.rlucas@outlook.com>

* chore: remove accidentally committed bin/task binary

- Remove 18MB taskfile binary that was accidentally committed
- Add bin/task to .gitignore to prevent future commits
- Taskfile binary should be installed per-environment, not versioned

Co-Authored-By: Andler Lucas <andre.rlucas@outlook.com>

* fix: move document upload outside throttle for immediate execution

- Move workspace document upload outside throttled block
- Upload happens synchronously before thread metadata update
- Add detailed logging for upload tracking
- Capture thread slug before any async operations
- Ensures documents are uploaded and attached to thread immediately
- Fixes draft status not clearing after first message

Co-Authored-By: Andler Lucas <andre.rlucas@outlook.com>

* fix: delay workspace state cleanup to allow onFinish to complete

- Add 500ms delay before cleaning up workspace state
- Ensures onFinish in use-mb-chat has access to workspace values
- Prevents newDocuments array from being empty due to premature state reset
- Fixes document upload not triggering due to guard conditions

Co-Authored-By: Andler Lucas <andre.rlucas@outlook.com>

* docs: add next session implementation plan for workspace document upload fix

- Documents detailed analysis of the architectural issue
- Outlines correct flow: workspace hooks should handle uploads, not use-mb-chat
- Provides step-by-step implementation plan for next session
- Reverted incorrect changes to use-mb-chat.tsx
- Kept correct fixes for CTA reset and workspace state cleanup

Co-Authored-By: Andler Lucas <andre.rlucas@outlook.com>

* fix: improve workspace error handling and add document upload on thread creation

- Enhanced error handling to immediately reset state and show user feedback
- Added thread creation detection to automatically upload workspace documents
- Documents are now properly associated with threads when first message is sent
- CTAs (edit, rewrite, expand) are properly re-enabled after errors
- Follows correct architecture: workspace layer handles document upload
- Prevents Draft badge persistence by ensuring proper metadata updates

Co-Authored-By: Andler Lucas <andre.rlucas@outlook.com>

* chore: remove session planning document

Co-Authored-By: Andler Lucas <andre.rlucas@outlook.com>

* refactor: remove workspace document upload logic from use-mb-chat.tsx

- Remove workspace document upload logic from use-mb-chat.tsx
- Keep only the proper implementation in use-workspace-chat.tsx
- Follows correct architecture: workspace layer handles document lifecycle
- use-mb-chat.tsx restored to focus only on general chat functionality
- Prevents duplicate upload logic and timing issues

Co-Authored-By: Andler Lucas <andre.rlucas@outlook.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Andler Lucas <andre.rlucas@outlook.com>

* [pro-web] feat: add reusable popup for create new organizations, departments, and projects (#569)

* feat(pro-web): add CreateEntityAlert component to replace window.prompt

- Create reusable CreateEntityAlert component with shadcn/ui AlertDialog
- Support organization, department, and project creation
- Add entity-specific icons (Building2, FolderTree, Briefcase)
- Include informative hints below input field
- Replace window.prompt calls in header.tsx with dialog
- Maintain existing entity creation logic and state updates
- Add input validation and keyboard accessibility (Enter/ESC)
- Follow DocumentCreateAlert styling patterns

Requested by: @derianrddev
Link to Devin run: https://app.devin.ai/sessions/f76bee4bc20040208c2b7ad39a95ba3e

Co-Authored-By: dmrodriguez2000@gmail.com <dmrodriguez2000@gmail.com>

* refactor(pro-web): use react-hook-form with Zod validation in CreateEntityAlert

- Install react-hook-form@7.63.0 and @hookform/resolvers@5.2.2
- Replace useState/useRef with useForm hook
- Add Zod schema: z.string().trim().min(1).max(64)
- Configure form with zodResolver and mode: 'onChange'
- Disable Create button when !formState.isValid || formState.isSubmitting
- Wrap form fields in <form> element with handleSubmit
- Maintain all existing UI elements and accessibility features
- Keep icon, title, hint text, and keyboard shortcuts (Enter/ESC)

Requested by: @derianrddev

Co-Authored-By: dmrodriguez2000@gmail.com <dmrodriguez2000@gmail.com>

* feat(pro-web): add error validation display in CreateEntityAlert

- Add custom error messages to Zod schema (min/max)
- Display validation errors below input in red with role='alert'
- Add aria-invalid attribute to Input when errors exist
- Add aria-describedby linking to hint and error message IDs
- Maintain Create button disabled state based on form validity
- Improve accessibility for screen readers

Requested by: @derianrddev

Co-Authored-By: dmrodriguez2000@gmail.com <dmrodriguez2000@gmail.com>

* feat(pro-web): replace CreateEntityAlert with button component and remove Enter key handling

* refactor(pro-web): add description to CreateEntityAlert and clean up code

* refactor(pro-web): improve comments for entity creation handling in Header component

* feat(pro-web): enhance DocumentCrumb and Crumb components with icon for new item action

* fix(pro-web): use requestAnimationFrame for setting focus on name input in CreateEntityAlert

* refactor(pro-web): rename DocumentCreateAlert component and file for consistency

* feat(pro-web): improve CreateEntityAlert UX and consistency

- Add loading state with spinner and 'Creating...' text for better feedback
- Rename 'open' prop to 'isOpen' for consistency across alert components
- Disable cancel button during submission to prevent conflicts
- Import Loader2 icon from lucide-react
- Add aria-hidden attribute to spinner for accessibility
- Update header.tsx to use renamed prop

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: dmrodriguez2000@gmail.com <dmrodriguez2000@gmail.com>

* [pro-web] refactor: move document type filter outside breadcrumb as separate filter (#570)

* feat(pro-web): add standalone DocumentTypeFilter component

Add dedicated document type filter component with icon-based
dropdown for filtering documents by type (all, text, image,
spreadsheet)

* refactor(pro-web): remove DocumentTypeCrumb component from breadcrumb

Remove DocumentTypeCrumb component as document type filtering
is now handled by a separate DocumentTypeFilter component

* refactor(pro-web): replace DocumentTypeCrumb with DocumentTypeFilter component

Move document type filter from breadcrumb to separate header
section for better UX and UI organization

* fix(pro-web): improve documentList merging logic across document types

Update documentList computation to properly merge text, image,
and spreadsheet documents per project

* refactor(pro-web): improve header responsive layout and accessibility

- Optimize breadcrumb spacing for medium screens (md breakpoint)

- Make DocumentTypeFilter compact showing icon-only on md/lg

- Add aria-hidden attributes for better accessibility

- Add useMemo optimization for activeTypeData

- Rename DocType to DocumentType for consistency

- Adjust header margins and gaps for responsive behavior

- Add title attribute to filter button for tooltip support

* fix(pro-web): sync documentType state with filter changes

Keep documentType state in sync with activeDocumentType when user
changes the document type filter to ensure consistent state across
the header component

* refactor(pro-web): separate document type state for filter and dialog

Rename documentType to alertDocumentType to clearly separate the
document creation dialog state from the filter state. Set alert
type from active filter when opening new document dialog

* fix(pro-web): add activeDocumentType to persistence dependencies

Ensure document type filter ('all', 'text', 'image', 'spreadsheet')

is properly persisted when changed by adding it to the useEffect

dependencies that trigger localStorage and server state sync.

* [pro-web] perf(wip): optimize workspace editor performance (#568)

* perf(pro-web): optimize workspace editor performance

- Remove expensive parseMarkdownSections() on every keystroke in Full Source tab
- Defer section parsing until view switching for better typing responsiveness
- Increase API debounce from 125ms to 2s with 5s maxWait for workspace/state
- Add dynamic debounce times based on AI generation state (1s-3s vs 400ms-1s)
- Add proper typing state tracking to prevent external updates during typing

Fixes:
- Full Source tab typing latency and missed input events
- Document Sections tab becoming unresponsive after AI actions
- Excessive api/workspace/state calls during streaming generation
- Browser crashes due to rapid updates during AI generation

Performance improvements:
- Full Source tab now has smooth, responsive typing
- Reduced API calls during AI streaming by ~15x
- Better handling of concurrent updates during generation

Co-Authored-By: Andler Lucas <andre.rlucas@outlook.com>

* fix(pro-web): prevent jarring section updates during typing and AI generation

- Skip section re-parsing during active user typing
- Skip section re-parsing during AI generation (workspaceProcessingState !== 'idle')
- Add debounced section parsing (500ms) for non-active updates
- Trigger section parse after user stops typing (1s delay)
- Trigger section parse after AI streaming completes
- Add workspaceProcessingState to parsing effect dependencies

This prevents the 'crazy' section tree updates during:
1. AI streaming - sections won't flicker while AI generates content
2. User typing - new headings won't create sections immediately

Sections will update smoothly:
- 1 second after user stops typing
- After AI generation completes
- When switching views

Co-Authored-By: Andler Lucas <andre.rlucas@outlook.com>

* fix(pro-web): resolve stale closure issue in section parsing timeouts

- Add fullMarkdownRef and activeSectionRef to avoid stale closures
- Update markUserTyping to use refs for latest values
- Update handleStreamingComplete to use refs for latest values
- Remove fullMarkdown/activeSection from callback dependencies
- Keep refs synced with state via useEffect

This fixes the regression where:
1. User edits content
2. Timeout fires with stale fullMarkdown value
3. Old content overwrites new changes
4. Second edit works because timeout now has correct value

Now timeouts always read the latest values from refs.

Co-Authored-By: Andler Lucas <andre.rlucas@outlook.com>

* fix: workspace content scrolling wrapper

* perf(wip): fix ai content generate section upt

* fix: textarea workspace typing

* fix: workspace section item cta index in ui tree

* fix(wip): workspace text gen

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Andler Lucas <andre.rlucas@outlook.com>
Co-authored-by: Roberto 'Andler' Lucas <contact@andler.dev>

* [web/pro-web] fix: enable individual chatbot deselection and improve sidebar filter checkbox behavior (#572)

* fix(sidebar): implement indeterminate checkbox states for category filtering

- Add indeterminate state for category checkboxes (partial bot selection)
- Show categories when any bot is selected, not just when fully selected
- Simplify toggleChatbotSelection by removing auto-category logic
- Add memoized allBotsSelected and someBotsSelected calculations
- Update filteredCategories to check hasSomeBotsSelected condition
- Standardize urlBuilders parameter formatting
- Apply changes to both web and pro-web apps

* feat(sidebar): add custom checkbox config with indeterminate icon support

* feat(sidebar): persist chatbot selections to localStorage

- Add chatbot storage support to useCategorySelections hook
- Sync selectedChatbots state with localStorage in both apps
- Update category dashboard to preserve existing chatbot selections
- Implement incremental chatbot selection (add/remove instead of replace)
- Add deep comparison to prevent unnecessary localStorage writes
- Update onboarding section to handle chatbot state properly
- Apply changes to both web and pro-web apps for consistency

* fix(sidebar): auto-sync category selection based on chatbot selections

- Automatically update selectedCategories when chatbots are selected/deselected
- Include category in selection if at least one of its bots is selected
- Add categories dependency to chatbot sync effect
- Ensure category state stays in sync with chatbot selections
- Apply to both web and pro-web apps

* refactor(sidebar): centralize category/chatbot selection hooks in mb-lib

Move useLocalStorage, useCategorySelections to mb-lib

Extract filtering, initialization and sync hooks

Add array utility functions for normalized comparisons

Update imports in both web and pro-web apps

* refactor(mb-lib): migrate useSyncChatbotsToStorage to lodash utilities

Replace arraysHaveSameElements() with lodash isEqual()

Replace normalizeArray() with lodash sortBy() + uniq() for normalization and deduplication

Remove obsolete array-utils.ts

* fix: rm legacy seeds from main seeds

* [pro-web] feat: add pro onboarding ui (#574)

* feat(pro-web): add Pro Onboarding components (DialogWizard + StepQ1)

• Create ProOnboarding container that mounts DialogWizard with steps array

• Implement StepQ1 with Accordion sections (Local/Service/Online/Other) and selectable pill Buttons

• Define types (Group, GroupItem) and provide static groups dataset with specialties

• Add Lucide icon map + getIcon helper for each business type

• Include sticky step header/footer and scrollable content area

• Add keyboard accessibility (Enter/Space) and aria-pressed state handling

• Open all accordions by default; single-select state with Continue and Skip actions

* refactor(pro-web): move Education Services under Service Business and keep only one Crypto card

* feat(pro-web): create Bot Preselection array (rules + priorities)

• Define base types (BotRule, BotEntry) and static botsPreselection dataset

• Per-bot rules with OR lists (category/type/subtype) and priority resolution

• Route business profiles → deterministic shortlist of suggested bots

• Declarative, maintainable config (add/edit without coupled logic)

* feat(pro-web): add Pro Onboarding context + StepQ2 (subtype picker)

• Introduce context/provider + hook (selectedType, selectedSubType; setters)

• Implement StepQ2: load subTypes from businesses by selectedType

• Render pills grid; keyboard a11y (Enter/Space) + aria-pressed

• Add pills header with icon from icon map + selected type label

• General refactor: clarified variable names across steps

• Extract businesses and icon map constants to a separate file

• Update StepQ1 to persist selectedType and log selection

* feat(pro-web): add StepQ3 component and integrate into onboarding flow

• Create StepQ3 component to collect organization name (zod + react-hook-form)

• Extend ProOnboardingData with orgName and add setOrgName setter

• Wire StepQ3 into wizard flow

* feat(pro-web): auto-advance on pill/card selection (Q1/Q2) and remove continue

* fix(pro-web): update navigation methods in StepQ1 and StepQ3 components

* feat(pro-web): add progress bar to DialogWizard for step tracking

* feat(pro-web): enhance onboarding business types with structured subtypes and update context state

- Refactored business subtypes in onboarding constants to use structured objects with id and label.
- Updated the ProOnboardingData interface to include selectedCategory.
- Added setSelectedCategory function to manage selected category state in onboarding context.

* feat(pro-web): add Avatar and HoverCard components from shadcn/ui

* feat(pro-web): add StepQ4 component and improve onboarding flow

- Introduced BotCard component for displaying chatbots with selection functionality.
- Updated ProOnboarding to include a new step (StepQ4) for selecting recommended chatbots.
- Modified StepQ1 to change default selection logic for business items.
- Enhanced StepQ3 to handle navigation more intuitively based on current step.
- Updated bots preselection logic to simplify business types related to crypto.
- Refactored businesses data structure for consistency in IDs.
- Created mapping utility to match user answers with recommended bots.
- Extended useProOnboarding hook to manage selected bots state.

* feat(pro-web): refactor onboarding components and replace OnboardingSection with ProOnboarding

* feat(pro-web): enhance StepQ4 to save selected chatbots, categories and org name to LocalStorage

* feat(pro-web): replace HoverCard with Tooltip for bot name display in BotCard component

* fix(pro-web): adjust layout and styling in StepQ2 component for improved user experience

* feat(pro-web): enhance BotCard component with improved tooltip functionality and markdown rendering

* feat(pro-web): update SignUpPage message and redirect to signup after closing StepQ4 wizard

* docs: add comprehensive hasura readme with seed debugging and onboarding (#576)

* Initial plan

* Add comprehensive Hasura README with seed debugging and explanations

Co-authored-by: AndlerRL <35474730+AndlerRL@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: AndlerRL <35474730+AndlerRL@users.noreply.github.com>

* fix: Sep/22nd release merge regressions and issues (#571)

* fix: chat threadquestion showing cinema

* fix: bot page thread question url

* fix: threads not found message

* fix(pro): threads not found message

* fix: restored hero bg banner

* fix: update

* fix: added isverified colum perm

* fix: update

* fix: theme toggle resize

* fix: added select all category

* fix: update

* fix: select all fix

* revert: hasura latest thread table permissions

---------

Co-authored-by: Roberto 'Andler' Lucas <contact@andler.dev>

* [pro-web] perf(fix): workspace + chat rendering, ui tweaks & chat and workspace refactor (#573)

* refactor(wip): use-workspace-chat streaming update

* perf: impr typing and text gen rendering

* fix: build + reduce hook deps + wip view model togg

* fix(wip): document state reset to parent active section

* fix(wip): workspace content integrity

* fix: save document content condition

* fix: replaceSectionContent h1 to h3

* perf(impr): single chat panel pro for pro + workspace chat guards

* chore: rm unused component + prompt form disable typo

* fix(wip): workspace hook re-render in chat

* perf: add startTransition to crit hooks

* fix: slow chat mode in thread + smal ui color state tweaks

* perf: impr is workspacemode space w/smooth transition

* fix: debounce workspace state update

* fix: current thread in thread popup

* chore: upt output instructions details (#548)

* [pro-web] feat: persist the organizations and selected chatbots in the backend (#579)

* fix(hasura): remove chatbot_id column from preference table and update relationships

* fix(hasura): update user permissions to enforce user_id checks in insert and select permissions

* feat(hasura): create organizations table with permissions and relationships

* feat(pro-web): implement GET and POST endpoints for organizations management

* feat(hasura): add default value for id column in organizations table

* feat(pro-web): implement PATCH endpoint for updating organizations

* feat(pro-web): enhance organization management functionality with new hooks and updates

* feat(pro-web): add functionality to persist organization and their categories/chatbots during signup

* refactor(pro-web): simplify header, create orgs with ProOnboarding, and remove CategoryDashboard

* feat(hasura): remove chatbots and categories columns from organizations table

* feat(hasura): create departments table with id and name columns

* feat(hasura): add department_id column and foreign key constraint to chatbot table

* feat(hasura): create organization_chatbot table

* feat(hasura): update metadata for organizations, chatbot, departments, and organizations_chatbot

* feat(hasura): add default departments to the seed data

* chore: update drizzle and graphql types

* refactor(hasura): rename org/dept tables, PKs, and update org_chatbot refs

* refactor(pro-web): group chatbots into default departments (general, marketing, product/service)

* fix(pro-web): add form ID to organization form and link submit button

* feat(hasura): add department field to getAllChatbots function

* refactor(hasura): remove department field from getCategories and getAllChatbots functions

* refactor(hasura): remove departmentId from getBrowseThreads function metadata

* refactor(pro-web): use 'id' instead of 'organizationId' and adjust department in getDepartment

* fix(web): replace chatbot __scalar in sitemap chatbots

* fix: organization table insert columns permissions @coderabbitai[bot]

Apply suggestion from @coderabbitai[bot]

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

---------

Co-authored-by: Roberto Lucas <andler@bitcash.org>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* [pro-web] refactor: add transactional org/chatbot insertion and improve validation (#582)

* fix(pro-web): correct SEO description handling for department selection

* refactor(pro-web): optimize organization and chatbot insertion using transactions

* fix(pro-web): validate chatbot existence before updating organization chatbots

* feat(pro-web): add keyword parameter in BrowseList

* fix(pro-web): include allDepartments in useSidebar for ChatLayoutSection

* fix(pro-web): handle null department name in search placeholder

* fix(pro-web): handle errors in getDepartments and ensure safe return of department data

* fix: 578 workspace hotfixes v5 + workspace state refactor (#580)

* feat(workspace): phase 0 diagnostics

- workspace-debug.ts: debug flags & timing utils
- use-workspace: toggleWorkspace, addDocument,
  setDocumentContent, updateWorkspaceStateData
- use-workspace-content-hook: handleSaveDocument
  with checksum logging
- markdown-utils: parseMarkdownSections,
  replaceSectionContent
- use-mb-chat: onFinish streaming
- logs gated by window.__DEBUG_WORKSPACE__
- zero perf impact when disabled

refs #578

* fix: get user workspace documents

- Refactor how to get documents.
- Created default initial states for users upon landing.
- Created server initial state for workspaces.

* fix: table markdown nav

* feat(wip): tanstack query migration

* chore(feat): tanstack query integration flag, comparison

* fix: tanstack query server first & chk

* fix: pro web build and auth redir with init workspace state

* fix: tanstack query stream

* fix: tanstack document content integrity

* fix(refactor): tanstack streaming & doc save + handleDocumentUpdate

* chore: rm tst page

* refactor(feat): organization workspace

* feat(wip): upt workspace layout

* chore(fix): align upt workspace sidebar per organizations + onboarding

* fix: workspace build

* feat(wip): upt workspace layout

* feat(wip): workspace upt layout

* fix: pro missing hook var

* fix: gpt-5-nano & mini output headings + organization list

* [pro-web] refactor: workspace document mode queries with server-first persistence (#583)

* fix: workspadce doc init state + simplify workspace hook

* fix: workspace document state track

* fix: thread routing w/dept + doc ai gen & manual content upt

* fix(wip): query mutations & invalidations

* fix: document update integrity and gen

* fix: query mutations & invalidations

* fix: query mutations & invalidations

* fix: breadcrumb navigation on file and project creation

* feat(wip): workspace ai actions

* feat(wip): workspace ai actions

* fix: pro navigation + workspace ai actions, document mode

* fix: css build

* fix: css build

* fix: css build

* [pro-web] fix: updating accurate document section (#585)

* fix: updating accurate document section

* style(docs): add code comments for document update logic reminder

* [pro-web] fix: profile page preferences & layout (#587)

* fix: profile page preferences & layout UI

* fix: typo

* fix: user pro subscription guard

* perf(impr): mb pro onboarding init trigger (#588)

* [pro-web] fix: chk disable onboard in browse list

* [pro-web] fix: upt user workspace state with anon values (#589)

* fix: upt user workspace state with anon values

* style: normalize doc key with helper fn

* [pro-web] feat: workspace media tab, add img gen w/gpt-image-1 & nano banana (#584)

* chore(pro-web): update package dependencies to include @google/genai

* feat(pro-web): integrate Google Gemini model support for image generation

* feat(pro-web): update workspace context to include active tab management

* feat(pro-web): add WorkspaceMediaProvider and context to manage media-related state in the workspace

* feat(pro-web): integrate media tab in PromptForm for dynamic placeholder and submission handling

* feat(pro-web): enhance MediaWorkspace with image generation and context integration

* refactor(pro-web): align selected model with generation logic and stabilize prompt handler

* refactor(pro-web): add error handling for missing Google API key in image generation

* refactor(pro-web): streamline WorkspaceMediaHandlers interface for improved type safety and clarity

* refactor(pro-web): improve media tab context and move library/version history to workspace tab menu

* feat(pro-web): add centered frame size selector above canvas

* refactor(pro-web): revert frame size updates, move selector to menubar and improve responsiveness

* feat(pro-web): unify media selection wizard steps for size and template

* feat(pro-web): update media sidebar buttons, add tooltips and improve template flow

* feat(pro-web): expand frame sizes options and update your descriptions

* chore(pro-web): add new template images for various social media formats

* feat(pro-web): implement media templates API and integrate into workspace

- Add new API route to fetch available media templates from the filesystem.
- Update MediaWorkspace component to load templates on mount and manage loading state.
- Refactor SelectTemplateStep to display templates with loading and empty states.
- Enhance SelectSizeStep with ScrollArea for better usability.
- Introduce helper functions for template parsing and filtering by frame and social media.
- Update context to include openTemplates action for dialog management.

* feat(pro-web): hide progress bar when single step

* feat(pro-web): add reference image upload functionality with drag-and-drop support

* refactor(pro-web): split MediaWorkspace into reusable components

- Added MediaCanvas component for displaying generated images and templates.
- Introduced ReferenceImagesPanel for managing reference images with upload functionality.
- Created MediaSidebar for navigation between templates and social media actions.
- Implemented wizards for selecting sizes and templates, including LibraryStep for image selection.
- Enhanced hooks to manage workspace media state and integrate new components.

---------

Co-authored-by: Roberto 'Andler' Lucas <contact@andler.dev>

* [pro-web] chore: upt doc ai actions prompts + restructure workspace nav state (#592)

* chore: simplify ai actions document prompts

* fix: isWorkspaceActive prompts condition

* fix: workspace structure core nav + doc aai action prompt upt

* [pro-web] fix: workspace document display, drafts & navigation (#593)

* fix: normalize ai heading content

* fix: freeze active workspace section while stream

* refactor: workspace doc tab components reloc + doc nav impr

* fix: impr workspace doc ai action prompts

* fix: document drafts

* fix: document drafts

* fix: doc thread nav + draft nav + new doc creation + save new doc to server

* fix: workspace thread nav + whitelist user impr & clean-up

* fix: whitelist user impr

* fix: profile route relocated + workspace context leak

* fix: new document from thread nav

* fix: user docs filter + change docs alert a11y impr

* fix: get server init state in workspace structure

* fix: doc debounced save rm from doc-text-edit

* chore(style): add onsucess log in upt doc content cb fn

* fix: ts build

* [pro-web] feat: enhance media workspace with multi-ref img, template type filtering, and size reframing (#594)

* feat(pro-web): integrate TanStack Query for media templates fetching in MediaWorkspace

* refactor(pro-web): rename openFrameSizes to openSizeSelector for consistency in media actions

* refactor(pro-web): centralize media workspace types in dedicated file

* refactor(pro-web): optimize reference image management with useCallback

* refactor(pro-web): simplify parsing logic in parseTemplateFilename function

* refactor(pro-web): replace object URLs with base64 for image previews

* refactor(pro-web): update template type import path for consistency

* feat(pro-web): add multi-reference image support and eliminate prop drilling

- Add support for multiple reference images (up to 4) in Gemini image generation
- Centralize all state management in useWorkspaceMedia provider
- Remove prop drilling across all media tab components
- Add parseBase64Image helper for handling image data URLs
- Update API route to process reference images in Gemini content parts
- Refactor MediaWorkspace, MediaCanvas, MediaSidebar to use hook directly
- Move referenceImages and currentVersion state to provider
- Implement addReferenceImage, addMultipleReferenceImages, removeReferenceImage actions
- Update GenerateImageRequest type with optional referenceImages field
- Pass reference images through full generation pipeline

* feat(pro-web): add dynamic filter dropdown with adaptive layout

- Add Filter by Type dropdown with all social media and aspect ratio options
- Implement smart badge visibility based on active filter
- Add conditional layout: grid for square filter, masonry for others
- Capitalize social media names in badges
- Adjust column count based on filtered template count

* refactor(pro-web): enhance canvas empty state, simplify template step layout, persist filter type

* feat(pro-web): implement aspect ratio control and size change workflow

- Add aspectRatio parameter to Gemini image generation API
- Remove standalone size selector dialog in favor of menu-based workflow
- Add generateImageForSize action for dynamic aspect ratio changes
- Implement comprehensive reframing prompt for size transformations
- Add mediaSizeOptions with social media format presets
- Update canvas aspect ratios to match social media platforms
- Refactor media wizards to auto-set size from template selection
- Remove FrameSize description field from types

* chore: add gemini 3 pro image model to default img gen

* feat(pro-web): add aspect ratio validation and 2K resolution for Gemini API

- Define AspectRatio type with valid Gemini API values (1:1, 2:3, 3:2, etc.)
- Add runtime validation in generate-images route with clear error messages
- Update FrameSize interface to use strongly-typed AspectRatio
- Update GenerateImageRequest and GenerateImageOptions interfaces
- Configure Gemini imageSize to 2K for high-quality output
- Add type safety across media workspace components
- Fix error handling in imageUrlToBase64 helper
- Remove debug console.log statements

* fix(pro-web): improve frame size matching with semantic purpose

---------

Co-authored-by: Roberto 'Andler' Lucas <contact@andler.dev>

* chore: upt react ver

* fix: bun lock conflicts

* [pro-web] fix: workspace structure and nav state (#596)

* fix: dept from path guard

* fix: workspace structure chk missing project in dept

* fix: department n threads navigation

* fix: workspace active navigation persistent state

* style: header component clean up

* fix: css build

* fix: new proj among dept + thread refresh & filter

* chore: upt nextjs ver

* chore: upt react ver

* chore: rm legacy component

* chore: rm legacy component

* chore: rm legacy files

* [pro-web] feat: enhance media tab with version history UI & reference image storage (#595)

* feat(pro-web): simplify image reframing prompt

* feat(pro-web): add Gemini 3 Pro model to available image models

* feat(pro-web): enhance download/share functionality with loading state and mobile sharing support

* feat(pro-web): implement checksum-based reference image uploads with GCS storage

- Add server actions for reference image upload with checksum deduplication
- Replace client-side base64 uploads with server-side GCS bucket storage
- Upload images individually to avoid body size limits (5MB per request)
- Update workspace media context to use ReferenceImagePayload with checksums
- Modify image generation API to resolve checksums to base64 on server
- Add reference images debug page with dark/light mode support
- Configure Next.js serverActions bodySizeLimit to 5mb
- Maintain backward compatibility with legacy base64 approach

Storage: reference-images/${checksum} with 7-day signed URLs
Resolves payload size issues and enables efficient image reuse

* feat(pro-web): redesign version history dialog UI

- Create VersionHistoryDialog with current/previous version display
- Add carousel navigation for version browsing
- Implement restore and duplicate version actions
- Extract version history logic from media-canvas component
- Improve responsive design and user interactions

* feat(pro-web): implement smooth card stack animation for version history

- Add framer-motion animations with global progress tracking
- Implement horizontal slide with smooth sin curve for card transitions
- Add vertical arc movement as cards emerge from stack
- Apply scale interpolation with slight overshoot effect
- Add rotation straightening during transitions with directional snap
- Calculate shortest cycling direction for better UX
- Implement dynamic z-index management during animations
- Add stable random rotations for stacked cards
- Improve card depth calculation and visibility logic
- Enhance visual feedback with indigo ring for current card

* refactor(pro-web): extract version card logic to separate component

* refactor(media-tab): redesign version history UI from stacked cards to carousel layout

- Delete version-card.tsx component with complex motion animations
- Replace stack navigation (prev/next cycling) with carousel thumbnails
- Add side-by-side preview comparison (current vs selected)
- Implement direct thumbnail selection instead of animated card flipping
- Include carousel pagination with dots and arrow controls
- Enhance dialog structure with bordered sections and action buttons

* feat(media-tab): implement version history carousel with flying image transitions

* chore: update next.js version from 15.2.4 to 15.5.7 in package.json

* refactor(media-tab): update image display styles in version history dialog

* refactor(media-tab): improve styling for version history dialog header and images

* refactor(media-tab): adjust image display properties in FlyingImage component

* fix(media-tab): improve reference image upload reliability

Replace custom checksum with native crypto.createHash

Add upload state guard to prevent concurrent uploads

Improve error handling with early return and state reset

Adjust body size limit comment for clarity

Add TODO for library image checksum handling

* fix(reference-images): validate checksum format in fetchReferenceImageByChecksum function

---------

Co-authored-by: bran18 <andreyfdez18@gmail.com>
Co-authored-by: Brandon Fernández <31634868+Bran18@users.noreply.github.com>
Co-authored-by: Jimoh sherifdeen <63134009+sheriffjimoh@users.noreply.github.com>
Co-authored-by: brandonfernandezf <brandon@bitcash.org>
Co-authored-by: Jun Dam <jun@bitcash.org>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jun Dam <jun@100xinvestors.com>
Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: dmrodriguez2000@gmail.com <dmrodriguez2000@gmail.com>
Co-authored-by: Derian <59376626+derianrddev@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants