|
| 1 | +# Assessment: CLI Studio Express Integration |
| 2 | + |
| 3 | +## Current State Analysis |
| 4 | + |
| 5 | +### How CLI Currently Handles Studio-UI |
| 6 | + |
| 7 | +The CLI's `studio` command currently: |
| 8 | + |
| 9 | +1. **Bundled Static Assets**: Studio-UI is built as a static Vue.js app and bundled into the CLI package |
| 10 | + - Built via `npm run build:studio-ui` in CLI build process |
| 11 | + - Assets copied to `dist/studio-ui-assets/` via `embed:studio-ui` script |
| 12 | + - Served via Node.js `serve-static` middleware with dynamic config injection |
| 13 | + |
| 14 | +2. **Process Management**: CLI manages processes directly in Node.js |
| 15 | + - **CouchDB**: Uses `CouchDBManager` class to spawn Docker containers |
| 16 | + - **Studio-UI Server**: Creates HTTP server using Node.js `http` module |
| 17 | + - **Process Lifecycle**: Handles graceful shutdown via SIGINT/SIGTERM handlers |
| 18 | + |
| 19 | +3. **Configuration Injection**: Dynamic config injection for studio-ui |
| 20 | + - Injects CouchDB connection details into `window.STUDIO_CONFIG` |
| 21 | + - Modifies `index.html` at runtime with database connection info |
| 22 | + - Uses SPA fallback routing for client-side routing |
| 23 | + |
| 24 | +### Express Backend Architecture |
| 25 | + |
| 26 | +The Express backend (`@vue-skuilder/express`) is: |
| 27 | + |
| 28 | +1. **Standalone Service**: Designed as independent Node.js/Express application |
| 29 | + - Main entry: `src/app.ts` |
| 30 | + - Hardcoded port: 3000 |
| 31 | + - Manages own CouchDB connections via `nano` client |
| 32 | + - Handles authentication, course management, classroom operations |
| 33 | + |
| 34 | +2. **External Dependencies**: Requires external CouchDB instance |
| 35 | + - Connects to CouchDB via environment configuration |
| 36 | + - Manages multiple databases (courses, classrooms, users) |
| 37 | + - Includes its own initialization and setup logic |
| 38 | + |
| 39 | +3. **Heavyweight Service**: Full-featured API server |
| 40 | + - Authentication middleware |
| 41 | + - File upload processing |
| 42 | + - Complex business logic for course/classroom management |
| 43 | + - Logging and error handling |
| 44 | + |
| 45 | +## Integration Options Analysis |
| 46 | + |
| 47 | +### Option A: Bundle Express and Run as Subprocess |
| 48 | + |
| 49 | +**Approach**: Bundle express into CLI and spawn it as a child process |
| 50 | + |
| 51 | +**Pros**: |
| 52 | +- Clean separation of concerns |
| 53 | +- Express runs in its own process space |
| 54 | +- Can leverage existing Express configuration |
| 55 | +- Easy to manage process lifecycle (start/stop) |
| 56 | +- Familiar process management pattern (similar to CouchDB) |
| 57 | + |
| 58 | +**Cons**: |
| 59 | +- Requires bundling entire Express app with CLI |
| 60 | +- Multiple Node.js processes running |
| 61 | +- More complex communication between CLI and Express |
| 62 | +- Harder to pass configuration dynamically |
| 63 | +- Potential port conflicts |
| 64 | + |
| 65 | +**Technical Implementation**: |
| 66 | +```typescript |
| 67 | +// Similar to how CLI spawns CouchDB |
| 68 | +const expressProcess = spawn('node', [expressDistPath], { |
| 69 | + env: { ...process.env, COUCHDB_URL: couchUrl } |
| 70 | +}); |
| 71 | +``` |
| 72 | + |
| 73 | +### Option B: Import Express Directly (Same Process) |
| 74 | + |
| 75 | +**Approach**: Import Express app and run it in the same Node.js process as CLI |
| 76 | + |
| 77 | +**Pros**: |
| 78 | +- Single process - more efficient resource usage |
| 79 | +- Direct communication between CLI and Express |
| 80 | +- Easy to pass configuration objects |
| 81 | +- Simpler deployment (single Node.js process) |
| 82 | +- Can share CouchDB connection instances |
| 83 | + |
| 84 | +**Cons**: |
| 85 | +- Tight coupling between CLI and Express |
| 86 | +- Harder to isolate Express errors from CLI |
| 87 | +- Express initialization could block CLI startup |
| 88 | +- More complex to handle Express-specific configuration |
| 89 | +- Potential conflicts with CLI's HTTP server |
| 90 | + |
| 91 | +**Technical Implementation**: |
| 92 | +```typescript |
| 93 | +// Import Express app and configure it |
| 94 | +import { createExpressApp } from '@vue-skuilder/express'; |
| 95 | +const expressApp = createExpressApp(couchConfig); |
| 96 | +expressApp.listen(3000); |
| 97 | +``` |
| 98 | + |
| 99 | +### Option C: Expect Express Running Separately |
| 100 | + |
| 101 | +**Approach**: CLI expects Express to be running as separate service |
| 102 | + |
| 103 | +**Pros**: |
| 104 | +- Complete separation of concerns |
| 105 | +- Express can be managed independently |
| 106 | +- No changes needed to CLI architecture |
| 107 | +- Easy to scale Express separately |
| 108 | +- Clear service boundaries |
| 109 | + |
| 110 | +**Cons**: |
| 111 | +- Additional setup complexity for users |
| 112 | +- Need to coordinate between multiple services |
| 113 | +- User must manage Express lifecycle manually |
| 114 | +- Harder to provide "one-command" studio experience |
| 115 | +- Complex error handling when Express is down |
| 116 | + |
| 117 | +**Technical Implementation**: |
| 118 | +```typescript |
| 119 | +// CLI just checks if Express is available |
| 120 | +const expressHealthCheck = await fetch('http://localhost:3000/health'); |
| 121 | +if (!expressHealthCheck.ok) { |
| 122 | + throw new Error('Express server not running'); |
| 123 | +} |
| 124 | +``` |
| 125 | + |
| 126 | +### Option D: Hybrid Approach - Express Module |
| 127 | + |
| 128 | +**Approach**: Refactor Express into a configurable module that CLI can import and control |
| 129 | + |
| 130 | +**Pros**: |
| 131 | +- Best of both worlds - modularity with integration |
| 132 | +- CLI maintains control over process lifecycle |
| 133 | +- Express can be configured per CLI session |
| 134 | +- Clean API boundaries |
| 135 | +- Reusable Express module |
| 136 | + |
| 137 | +**Cons**: |
| 138 | +- Requires significant refactoring of Express package |
| 139 | +- Breaking changes to Express architecture |
| 140 | +- More complex implementation |
| 141 | +- Need to maintain backward compatibility |
| 142 | + |
| 143 | +**Technical Implementation**: |
| 144 | +```typescript |
| 145 | +// Express as configurable module |
| 146 | +import { ExpressService } from '@vue-skuilder/express'; |
| 147 | +const expressService = new ExpressService({ |
| 148 | + port: 3001, |
| 149 | + couchdb: couchConfig, |
| 150 | + logger: cliLogger |
| 151 | +}); |
| 152 | +await expressService.start(); |
| 153 | +``` |
| 154 | + |
| 155 | +## Key Considerations |
| 156 | + |
| 157 | +### 1. **Process Management Consistency** |
| 158 | +- CLI already manages CouchDB via subprocess (Docker) |
| 159 | +- Studio-UI runs as HTTP server within CLI process |
| 160 | +- Express subprocess would follow CouchDB pattern |
| 161 | + |
| 162 | +### 2. **Configuration Management** |
| 163 | +- CLI injects config into Studio-UI at runtime |
| 164 | +- Express needs CouchDB connection details |
| 165 | +- Studio-UI needs to know Express endpoint |
| 166 | + |
| 167 | +### 3. **Port Management** |
| 168 | +- CLI finds available ports dynamically (Studio-UI: 7174+) |
| 169 | +- Express hardcoded to port 3000 |
| 170 | +- Need to avoid port conflicts |
| 171 | + |
| 172 | +### 4. **Error Handling & Lifecycle** |
| 173 | +- CLI handles graceful shutdown for all services |
| 174 | +- Express needs to integrate with CLI's process management |
| 175 | +- Studio-UI depends on both CouchDB and Express |
| 176 | + |
| 177 | +### 5. **User Experience** |
| 178 | +- Current: Single `skuilder studio` command starts everything |
| 179 | +- Goal: Maintain single-command simplicity |
| 180 | +- Express adds complexity but provides powerful features |
| 181 | + |
| 182 | +## Recommendation |
| 183 | + |
| 184 | +**Option A: Bundle Express and Run as Subprocess** is the best approach because: |
| 185 | + |
| 186 | +1. **Architectural Consistency**: Matches existing CouchDB subprocess pattern |
| 187 | +2. **Clean Separation**: Express runs independently but managed by CLI |
| 188 | +3. **Minimal Changes**: Can reuse existing Express code with minimal refactoring |
| 189 | +4. **Process Management**: Leverages CLI's existing process lifecycle handling |
| 190 | +5. **Configuration**: Can pass config via environment variables (established pattern) |
| 191 | + |
| 192 | +### Implementation Plan |
| 193 | + |
| 194 | +1. **Express Modifications**: |
| 195 | + - Make port configurable via environment variable |
| 196 | + - Add health check endpoint |
| 197 | + - Ensure clean shutdown on SIGTERM/SIGINT |
| 198 | + |
| 199 | +2. **CLI Integration**: |
| 200 | + - Add Express process management (similar to CouchDB) |
| 201 | + - Bundle Express dist in CLI build process |
| 202 | + - Dynamic port allocation for Express |
| 203 | + - Update Studio-UI config injection to include Express endpoint |
| 204 | + |
| 205 | +3. **Process Orchestration**: |
| 206 | + - Start CouchDB first (as currently done) |
| 207 | + - Start Express with CouchDB connection details |
| 208 | + - Start Studio-UI with both CouchDB and Express endpoints |
| 209 | + - Coordinate shutdown of all services |
| 210 | + |
| 211 | +This approach maintains the current architecture's clarity while adding the powerful Express backend capabilities that users need for full studio functionality. |
0 commit comments