Last updated: Aug 12, 2025, 01:09 PM UTC

Lessons Learned - Sasha Studio Development

Overview

This document captures key insights and lessons learned during the transformation of Claude Code UI into Sasha Studio, a business-focused AI knowledge management platform.


1. Service Worker Caching Issues in Development

Problem

Service Workers aggressively cache resources, which can cause major issues during development when servers restart or ports change.

What Happened

  • Service Worker was caching all fetch requests
  • When Vite dev server wasn't running, cached resources became stale
  • Fetch failures resulted in "Failed to fetch" errors, preventing app from loading
  • Console showed: The FetchEvent for "<URL>" resulted in a network error response

Solution

Immediate Fix:

// Clear Service Worker and caches in browser console
navigator.serviceWorker.getRegistrations().then(function(registrations) {
  for(let registration of registrations) {
    registration.unregister();
  }
});
caches.keys().then(names => names.forEach(name => caches.delete(name)));

Long-term Fix:

  • Consider disabling Service Worker in development mode
  • Only enable for production PWA functionality
  • Add development check: if (process.env.NODE_ENV === 'production')

Lesson

Service Workers are powerful but can complicate development. Always provide a way to bypass or disable them during development.


2. CLI Command Integration Testing

Problem

Integrated CLI commands without testing actual command syntax, leading to 500 errors in production.

What Happened

  • MCP routes used claude mcp list -s user syntax
  • Claude CLI didn't recognize -s user flag
  • All MCP API calls failed with 500 errors
  • Error was silent except in server logs

Solution

  • Test CLI commands directly before integration
  • Remove invalid flags: claude mcp list (without -s user)
  • Add proper error handling and logging

Lesson

Always test external CLI commands in isolation before integrating them into your application. Document the exact syntax that works.


3. GitHub Repository Migration

Problem

Needed to migrate from original repository to new branded repository while maintaining functionality.

What Happened

  • Version checking was hardcoded to original repo (siteboon/claudecodeui)
  • GitHub API returned 404 errors for non-existent releases
  • Had to update multiple references throughout codebase

Solution

# Update git remote
git remote remove origin
git remote add origin https://github.com/wapdat/sasha-studio.git

# Update code references
# Change: useVersionCheck('siteboon', 'claudecodeui')
# To: useVersionCheck('wapdat', 'sasha-studio')

Lesson

Make repository references configurable through environment variables or config files to ease migration and white-labeling.


4. Port Management with Multiple Services

Problem

Running both backend (Express) and frontend (Vite) servers requires careful port management.

What Happened

  • Backend runs on port 3005
  • Frontend (Vite) runs on port 5175
  • Port conflicts when trying to restart services
  • "EADDRINUSE" errors when ports already in use

Solution

  • Use separate commands: npm run server and npm run client
  • Kill existing processes before restarting: pkill -f "node server/index.js"
  • Configure ports in .env file for easy management

Lesson

Document which services run on which ports. Provide scripts to cleanly stop and restart services.


5. Version Checking Without Releases

Problem

Version checking system expects GitHub releases to exist but none were created initially.

What Happened

  • API calls to /repos/owner/repo/releases/latest returned 404
  • Version check gracefully handled the error but logged console warnings
  • Version tab showed "Unknown" for current version

Solution

  • System handles missing releases gracefully
  • Create GitHub releases to enable version checking
  • Use semantic versioning (e.g., v1.0.0)

Lesson

Version checking systems should gracefully handle the absence of releases, especially for new repositories.


6. UI Component Removal Strategy

Problem

Removing developer-focused features while maintaining system stability.

What Happened

  • Needed to remove Shell, Git tabs, and technical labels
  • Had to preserve underlying functionality for potential future use
  • Some components had deep integrations

Solution

  • Remove UI elements but keep backend code
  • Document removed features for potential restoration
  • Use feature flags for easy toggling

Lesson

When transforming products, remove UI elements first while keeping backend functionality intact. This allows for easy restoration if needed.


7. Configuration Management

Problem

Hardcoded labels and branding throughout the codebase made customization difficult.

What Happened

  • "Claude Code UI" references scattered across multiple files
  • Each label change required finding and updating multiple locations
  • Risk of missing references during rebranding

Solution

Created centralized configuration:

// src/config/appConfig.js
const appConfig = {
  appName: process.env.VITE_APP_NAME || 'Sasha Studio',
  aiName: process.env.VITE_AI_NAME || 'Sasha',
  // ... all other configurable strings
};

Lesson

Always centralize configuration and branding elements from the start. This makes white-labeling and customization much easier.


8. Development vs Production Considerations

Problem

Features that work well in production can hinder development.

Examples Encountered

  1. Service Workers: Great for offline functionality, problematic during development
  2. Caching: Improves performance but complicates testing changes
  3. Authentication: Necessary for production but slows development

Solution

  • Use environment checks: if (process.env.NODE_ENV === 'development')
  • Provide bypass mechanisms for development
  • Clear documentation on how to disable production features

Lesson

Design systems with both development and production modes in mind from the beginning.


9. React Component Structure and Conditional Rendering

Problem

Tab content not displaying despite being present in the code.

What Happened

  • Version tab in Settings modal was completely blank
  • The tab button appeared but clicking it showed nothing
  • Component had all the correct props and logic
  • Console showed no errors

Root Cause

The Version tab content was placed OUTSIDE the main scrollable content container:

// WRONG - Outside the content container
<div className="p-4 md:p-6">
  {activeTab === 'tools' && (...)}
  {activeTab === 'appearance' && (...)}
</div>  <!-- Container closes here -->

{/* Version tab wrongly placed outside */}
{activeTab === 'version' && (...)}

Solution

Moved the Version tab content INSIDE the main content container:

// CORRECT - Inside the content container
<div className="p-4 md:p-6">
  {activeTab === 'tools' && (...)}
  {activeTab === 'appearance' && (...)}
  {activeTab === 'version' && (...)}  <!-- Now inside -->
</div>

Lesson

When components don't render despite correct logic:

  1. Check the component hierarchy and nesting
  2. Verify content is within the correct parent containers
  3. Look for misplaced closing tags
  4. Use React DevTools to inspect component tree
  5. Be careful with conditional rendering placement

This is especially important in modal and tab components where content areas are strictly defined.


Key Takeaways

  1. Test External Dependencies: Always test CLI commands and external APIs in isolation first
  2. Centralize Configuration: Keep all configurable elements in one place
  3. Plan for Migration: Make repository and service references configurable
  4. Document Everything: Especially removal of features and workarounds
  5. Development Experience Matters: Provide tools and scripts to make development easier
  6. Graceful Degradation: Systems should handle missing dependencies gracefully
  7. Version Control: Commit after every significant change for easy rollback
  8. Clear Error Messages: Log detailed errors server-side for debugging

Future Improvements

  1. Add feature flags system for easier feature toggling
  2. Create development mode that bypasses Service Workers
  3. Add health check endpoints for all services
  4. Implement proper logging system with log levels
  5. Create automated tests for CLI integrations
  6. Add pre-commit hooks to check for hardcoded values
  7. Build configuration validation on startup
  8. Create migration scripts for repository changes

4. Dynamic Content Loading - localStorage Token Mismatch

Problem

API endpoints returning 403 Forbidden errors despite user being logged in, causing personas and guides panels to crash.

What Happened

  • Login process saved token as localStorage.setItem('auth-token', token)
  • New components tried to read token as localStorage.getItem('token')
  • Missing token resulted in 403 errors from protected API endpoints
  • Frontend crashed with "personas.map is not a function" when API returned error object instead of array

Solution

Immediate Fix:

  1. Added proper error handling to check response status and validate data types
  2. Fixed token key mismatch by using consistent 'auth-token' key
  3. Added fallback data for when API fails

Code Fix:

// Wrong - inconsistent key
localStorage.getItem('token')

// Correct - matches login process
localStorage.getItem('auth-token')

Lesson

  • Always verify localStorage key names match between write and read operations
  • Add robust error handling for API responses - validate both HTTP status and data structure
  • Include debug logging during development to quickly identify authentication issues
  • Use TypeScript or constants for localStorage keys to prevent typos

Best Practice for Future

// Define constants for localStorage keys
const STORAGE_KEYS = {
  AUTH_TOKEN: 'auth-token',
  USER_DATA: 'user-data'
};

// Use consistently
localStorage.setItem(STORAGE_KEYS.AUTH_TOKEN, token);
localStorage.getItem(STORAGE_KEYS.AUTH_TOKEN);

10. Context Injection System Design

Challenge

Designing a system to inject guide and persona markdown content into chat sessions without disrupting user experience.

Design Considerations

  • Personas: Should persist across messages as they define the AI's behavior/perspective
  • Guides: Should apply once as they provide specific instructions or frameworks
  • Visibility: Users need to know what context is active
  • Flexibility: Should support using both, either, or neither

Solution Architecture

  1. Dual Injection Methods:

    • Personas: Persistent context included with every message
    • Guides: One-time application for current conversation
  2. State Management:

    • App-level state for activePersona and appliedGuides
    • Pass context through props to ChatInterface
    • Include context in WebSocket message payload
  3. Visual Feedback:

    • Badge in chat header showing active persona
    • Toast notifications when guides are applied
    • Clear indicators of what context is active

Lesson

When designing context injection systems:

  • Consider persistence needs (session vs message)
  • Provide clear visual feedback
  • Make it easy to clear/change context
  • Don't clutter the chat interface
  • Keep the implementation flexible for future enhancements

Last Updated: 2025-08-09
Maintained by: Knowcode Team