Quellcode durchsuchen

refactor: move UI to /ui subpath and add root JSON endpoint

Move the web UI from root path to /ui subpath while keeping all API
routes under /api. The root path now returns an empty JSON response.

Changes:
- Update server.ts:
  - Add GET / endpoint that returns empty JSON {}
  - Move static file serving from / to /ui
  - Update catch-all handler to serve UI only for /ui/* routes
  - API routes at /api/* remain unchanged

- Update vite.config.ts:
  - Set base path to '/ui/' for proper asset loading

- Update Router.ts (web UI):
  - Strip /ui prefix from pathname for internal routing
  - Prepend /ui to paths in navigate() for browser URL
  - Maintain backward compatible internal routing logic

- Update index.ts:
  - Update startup log to show UI at /ui path

Route structure:
- GET /          -> Empty JSON response {}
- GET /ui        -> Web UI application
- GET /ui/*      -> Web UI SPA routing
- GET /api/*     -> API endpoints (unchanged)
- GET /health    -> Health check (unchanged)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Fszontagh vor 8 Monaten
Ursprung
Commit
143a529a0a
4 geänderte Dateien mit 19 neuen und 13 gelöschten Zeilen
  1. 9 10
      src/api/server.ts
  2. 1 1
      src/index.ts
  3. 8 2
      web/src/app/Router.ts
  4. 1 0
      web/vite.config.ts

+ 9 - 10
src/api/server.ts

@@ -22,22 +22,21 @@ export function createServer(apiKey: string, jobQueue: JobQueue, db?: ShopDataba
     next();
   });
 
-  // Serve static files from web UI (must come before catch-all)
+  // Root path - return empty JSON
+  app.get('/', (req, res) => {
+    res.json({});
+  });
+
+  // Serve static files from web UI at /ui
   const webUIPath = path.join(__dirname, '../../dist/web');
-  app.use(express.static(webUIPath));
+  app.use('/ui', express.static(webUIPath));
 
   // API routes (authentication handled per endpoint based on documentation)
   const router = createRouter(jobQueue, apiKey, db, config);
   app.use('/', router);
 
-  // Catch all handler for SPA - serve index.html for all non-API routes
-  app.get('*', (req, res) => {
-    // Don't serve index.html for API routes that don't exist
-    if (req.path.startsWith('/api/')) {
-      return res.status(404).json({ error: 'Not found' });
-    }
-
-    // Serve index.html for all other routes (SPA routing)
+  // Catch all handler for SPA - serve index.html for /ui/* routes
+  app.get('/ui/*', (req, res) => {
     const indexPath = path.join(webUIPath, 'index.html');
     res.sendFile(indexPath, (err) => {
       if (err) {

+ 1 - 1
src/index.ts

@@ -142,7 +142,7 @@ async function main() {
       logger.info(`  GET    /api/shops/:id   - Get shop details and analytics`);
       logger.info(`  GET    /health          - Health check`);
       logger.info('');
-      logger.info(`Web UI available at: http://${config.host === '0.0.0.0' ? 'localhost' : config.host}:${config.port}`);
+      logger.info(`Web UI available at: http://${config.host === '0.0.0.0' ? 'localhost' : config.host}:${config.port}/ui`);
       logger.info('Authentication: Bearer token required for /api/* endpoints');
     });
 

+ 8 - 2
web/src/app/Router.ts

@@ -35,14 +35,20 @@ export class Router {
     if (this.currentRoute === path) return;
 
     this.currentRoute = path;
-    window.history.pushState({}, '', path);
+    // Prepend /ui to the path for the actual browser URL
+    const fullPath = '/ui' + (path.startsWith('/') ? path : '/' + path);
+    window.history.pushState({}, '', fullPath);
     this.handleRouteChange();
   }
 
   handleRouteChange(): void {
     if (!this.container) return;
 
-    const path = window.location.pathname;
+    // Strip /ui prefix from pathname for routing
+    let path = window.location.pathname;
+    if (path.startsWith('/ui')) {
+      path = path.substring(3) || '/';
+    }
     this.currentRoute = path;
 
     // Cleanup previous component

+ 1 - 0
web/vite.config.ts

@@ -1,6 +1,7 @@
 import { defineConfig } from 'vite';
 
 export default defineConfig({
+  base: '/ui/',
   build: {
     outDir: '../dist/web',
     emptyOutDir: true