diff --git a/backend/app/main.py b/backend/app/main.py
index e64ac93..4bbb0c2 100644
--- a/backend/app/main.py
+++ b/backend/app/main.py
@@ -62,11 +62,16 @@ app = FastAPI(
lifespan=lifespan
)
-# Configure CORS
+# Configure CORS. The frontend normally talks to the backend through the
+# nginx (prod) or vite (dev) proxy, so requests are same-origin and never
+# trip CORS. The wildcard here is a fallback for the rare case where a
+# user / script hits the backend directly from a browser at some other
+# origin (LAN IP, reverse proxy under a different host, etc.). This is a
+# single-user homelab tool, so a permissive CORS policy is fine.
app.add_middleware(
CORSMiddleware,
- allow_origins=["http://localhost:3000", "http://localhost:5173"], # Frontend URLs
- allow_credentials=True,
+ allow_origins=["*"],
+ allow_credentials=False,
allow_methods=["*"],
allow_headers=["*"],
)
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 5c9b54a..29900fb 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -53,9 +53,6 @@ function App() {
return (
-
-
-
{/* Left Sidebar */}
@@ -67,9 +64,15 @@ function App() {
- {/* Main Content - Timeline */}
-
-
+ {/* Main column — filter bar, discard bar, timeline. Lives to the
+ * right of the left sidebar so the filter row doesn't bleed
+ * across the sidebar. */}
+
{/* Right Sidebar */}
@@ -82,6 +85,10 @@ function App() {
+ {/* Floating keyboard hints — pinned bottom-center, glassy. Sits
+ * above the timeline and below the toast layer. */}
+
+
{/* Scan Progress Indicator */}
diff --git a/frontend/src/components/KeyboardHints.tsx b/frontend/src/components/KeyboardHints.tsx
index 2dbe667..e011ca0 100644
--- a/frontend/src/components/KeyboardHints.tsx
+++ b/frontend/src/components/KeyboardHints.tsx
@@ -25,22 +25,22 @@ export function KeyboardHints() {
]
return (
-
-
+
+
{hints.map((hint, i) => (
-
+
{hint.key}
{hint.action}
{i < hints.length - 1 && (
- •
+ •
)}
))}
{selectedCount > 0 && (
<>
-
•
+
•
{selectedCount} selected
diff --git a/frontend/src/components/filter/FilterBar.tsx b/frontend/src/components/filter/FilterBar.tsx
index ce6c4c1..d719892 100644
--- a/frontend/src/components/filter/FilterBar.tsx
+++ b/frontend/src/components/filter/FilterBar.tsx
@@ -93,7 +93,7 @@ export function FilterBar() {
const anyActive = hasActiveFilters(filterState)
return (
-
+
{/* Date */}
Clear all
diff --git a/frontend/src/services/api.ts b/frontend/src/services/api.ts
index d9d8464..75d6afa 100644
--- a/frontend/src/services/api.ts
+++ b/frontend/src/services/api.ts
@@ -1,6 +1,11 @@
import axios from 'axios'
-const API_BASE_URL = 'http://localhost:8001/api/v1'
+// Relative API base. In production the nginx in front of the SPA proxies
+// /api/ to the backend container; in dev the vite server has the same
+// proxy in vite.config.ts. Using a relative URL means requests are
+// always same-origin, so the app works whether you hit it from
+// localhost, a LAN IP, or a reverse proxy without any CORS dance.
+const API_BASE_URL = '/api/v1'
const api = axios.create({
baseURL: API_BASE_URL,