Login previously bailed out with "No API key found" unless a key from a
prior signup already happened to be sitting in this browser's localStorage
— meaning login was completely broken on any new device, browser, or after
clearing storage, regardless of a correct password. /api/login now issues
a real usable key on every successful login; the frontend just saves it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Renames all user-facing branding to match the new getodoomcp.com domain:
page title/meta, navbar, landing hero/footer, all auth pages, dashboard
sidebar, contact email, package.json name. Also updates a stale hardcoded
old-domain URL in the landing hero's MCP endpoint mockup, and the
VITE_API_URL fallback defaults in DashboardHome/Endpoints to the new
api.getodoomcp.com backend domain.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
A trailing slash on the API base URL produced requests like
".com//api/signup" that 404'd, since every call site concatenates a
leading-slash path directly onto BASE. Now stripped defensively
regardless of how the env var is set. Also updated the fallback default
to the current api.getodoomcp.com domain.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
When creating a key, pick "All connections (unscoped)" or lock it to one
specific Odoo connection — matches the new per-key instance_name scoping
on the backend. The keys table now shows each key's scope (or "All
connections" for unscoped keys).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
req()'s fetch init merged headers as { headers: {Content-Type, ...opts.headers}, ...opts }
— spreading ...opts LAST meant opts.headers (e.g. just Authorization) fully
overwrote the merged headers object, silently dropping Content-Type:
application/json from every call that also passed custom headers (i.e.
every authenticated request: addCredential, deleteCredential, createApiKey,
revokeApiKey, regenKey, all adminApi mutations).
Confirmed via direct reproduction against production: without Content-Type,
the request body arrived at the backend re-wrapped as a JSON string instead
of parsed as an object, producing "Input should be a valid dictionary or
object to extract fields from" on every POST/PATCH/DELETE with a body.
Reordered the spread so headers merge correctly.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
FastAPI's `detail` field is a plain string for handler-raised errors, but
an array of {loc, msg, type} objects for its own automatic 422 request
validation errors. new Error(detail) silently stringified that array into
"[object Object]", hiding the actual validation failure from the user
(e.g. when adding an Odoo connection). Normalizes both shapes into one
readable message, and also guards against non-JSON error responses.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The Codex tab previously showed "coming soon" for every client except
Claude. Codex uses a simpler config format than Claude's JSON — the API
key goes directly in the URL as a query param under [mcp_servers.<name>]
in ~/.codex/config.toml, no separate headers section. Generates the block
with the logged-in user's real MCP URL and API key, matching the pattern
already used for the Claude tab.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Dashboard home was hardcoding fake numbers (2,431/10,000 requests, fake
"Pro Plan", fake activity log, fake random bar chart) despite the real
analytics/logs/keys endpoints already existing and being used correctly
elsewhere (Usage, Logs, Tokens pages). A fresh account with zero real
activity was showing 24% "used" from nobody's data.
Rewired every stat card, the usage chart, and the activity table to real
/api/analytics/*, /api/logs, and /api/keys data. Every Quick Action now
does something real (navigate to the real page, or call a real endpoint)
instead of being a no-op or hardcoded button.
Also removed 5 sidebar/footer links (AI Setup Guides, Tools & Permissions,
Billing, Team, Settings, Support) that pointed at nonexistent routes or
pages with no backend feature behind them at all — no team/multi-user
system, no per-tool permission toggles, no real subscription/billing
system exist in the backend yet. Documented what's needed to build each
one for real in FUTURE_FEATURES.md rather than shipping more fake UI.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
react-router-dom's Link intercepts hash-only navigation for client-side
routing and never triggers the browser's native scroll-to-anchor behavior.
Also half the nav items (Use Cases, Docs, Security) pointed at section ids
that were never built. Switched hash links to plain anchor tags (real
same-page scrolling), added a real #contact target in the footer, and
trimmed the nav/footer to only link sections that actually exist.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Full technology change: Next.js App Router replaced with Vite +
react-router-dom v6. All 21 pages and 5 landing components converted
(next/link -> Link, next/navigation -> react-router-dom hooks, next/font
-> @fontsource/inter, process.env -> import.meta.env). Dropped the unused
Stripe API routes, which can't run in a client-only Vite build anyway and
were never wired to any page.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>