Two blockers found while wiring OpenPanel for real:
- frontend/Dockerfile declared ARG for VITE_OPENPANEL_URL/CLIENT_ID/SENTRY_DSN but not
VITE_OPENPANEL_SCRIPT_URL, so passing it as a build arg was silently ignored and the
loader compiled out (import.meta.env value undefined).
- backend/app/services/analytics.py posted a flat {type, event, properties} body; the
Track API expects {type, payload:{event, properties, profileId}} (verified against the
SDK source in packages/sdks/sdk). The API answered 400 and the module swallows every
error by design, so all server-side events were being dropped without a trace.
Verified after deploy: the bundle carries the client id + op1.js URL + the queueing shim,
op1.js serves 200, and a track event posted with the real envelope lands in OpenPanel.
- redesigned /login (Tailwind, RTL): centered username/password/organization
form posting to POST /api/v1/auth/login — session starts without leaving
the page; PM lands on the inventory panel, others on the procurement office
- Developer Mode button fixed top-left opens a role/project test panel
(admin role added) gated by VITE_ENABLE_DEV_LOGIN (DEV_LOGIN_ENABLED build
arg in Docker, default enabled)
- removed the old Casdoor redirect button, the PKCE ?code= callback, and the
public casdoor-config.js — the client secret is no longer shipped to the
browser; backend mediates the password grant instead