UIGen API Explorer¶
UIGen auto-generates a React UI from the backend's OpenAPI spec. It gives you tables, forms, pagination, and a built-in API proxy — so you can browse and interact with every endpoint without writing any frontend code.
UIGen is a deployed service accessible at its own subdomain in every environment. The Admin button in the portfolio nav opens it.
| Environment | URL | Auth |
|---|---|---|
| Production | admin.sven-relijveld.com | Public — guest read-only, admin token for writes |
| Dev | admin.dev.sven-relijveld.com | AAD login required (EasyAuth) |
| Local | localhost:4400 | Same guest/admin token flow |
Auth model¶
UIGen uses two parallel auth paths depending on the environment:
Guest / admin token (all environments)¶
- Guest — issued automatically with no credentials. Grants read-only access to all GET endpoints plus contact and CV download.
- Admin — issued by presenting the
API_ADMIN_TOKENbearer token toGET /api/uigen-token. Grants full write access to all endpoints.
The Admin button in the portfolio nav opens a modal where you can continue as a guest or enter the admin token. The backend issues a scoped token which is then written to sessionStorage on the UIGen origin via the shim proxy's /auth endpoint.
OAuth PKCE flow (UIGen native login)¶
UIGen also supports a native OAuth PKCE login flow against Entra ID. This is the primary path for the feature-flags override panel:
- UIGen redirects to Entra ID authorize endpoint
- User authenticates and consents
- Entra redirects back to
/auth/callbackwith an authorization code - UIGen exchanges the code for an access token
- UIGen calls
GET /auth/me(the backend's session validation endpoint) with the access token as a Bearer token - Backend validates the token via PyJWT + JWKS and returns
{id, email, name, role} - UIGen stores the token in
sessionStorageand considers the session authenticated
The /auth/token and /auth/callback paths are excluded from UIGen's EasyAuth gate on dev so the PKCE exchange can complete. The backend registers the auth router at both /api/auth and /auth so UIGen's proxy can reach /auth/me without the /api prefix.
In dev, EasyAuth still protects the UIGen root — AAD login is required to reach UIGen at all. Only the specific OAuth callback paths bypass EasyAuth.
Starting UIGen locally¶
UIGen is available at http://localhost:4400 once the backend healthcheck passes (~15–30 seconds on first run while the image builds).
How it works¶
Browser → http://localhost:4400 (shim proxy)
│
├─ GET /auth?token=<t>
│ writes sessionStorage["uigen_auth"]
│ redirects to /
│
└─ everything else → UIGen on :4401
│
├─ Serves React SPA (generated from OpenAPI)
└─ Built-in proxy: /api/* → BACKEND_URL
- The portfolio nav opens
<VITE_UIGEN_URL>/auth?token=<scoped-token> - The shim proxy writes the token to
sessionStorage["uigen_auth"]on the UIGen origin and redirects to/ - UIGen reads the token and sends it as
Authorization: Bearer <token>on every API call - UIGen's built-in proxy forwards calls to the backend, stripping the
/apiprefix
The shim also injects portfolio pink CSS (--primary: #ff33cc) into all HTML responses so UIGen matches the portfolio's theme.
Detected resources¶
After startup you will see all backend resources in the sidebar. UIGen derives resource groups from the x-uigen-id annotations on each endpoint in the OpenAPI spec.
| Resource | Key endpoints | Access |
|---|---|---|
| Projects | GET /api/projects, POST /api/projects, PUT/PATCH/DELETE /api/projects/{slug} | Read: guest; Write: admin |
| Experience | GET /api/experience, POST /api/experience, PUT/PATCH/DELETE /api/experience/{id} | Read: guest; Write: admin |
| Skills | GET /api/skills, POST/PUT/PATCH/DELETE /api/skills/categories/{id} | Read: guest; Write: admin |
| Awards | GET /api/awards | Guest |
| Certifications | GET /api/certifications | Guest |
| Contact | POST /api/contact | Guest |
| Download CV | GET /api/download-cv, PATCH /api/download-cv | Guest |
| Feature Flags | GET /api/feature-flags, PATCH /api/feature-flags | Read: guest; Write: admin |
| CV Status | GET /api/cv/status | Guest |
| CV Generate | PATCH /api/cv/generate | Guest (feature-flagged) |
| Health | GET /api/health | Guest |
Feature Flags Override Panel¶
UIGen includes a built-in feature-flags management panel implemented in .uigen/src/feature-flags.tsx. It is injected into the UIGen shim as an additional React component.
The panel:
- Reads current flag state from
GET /api/feature-flagson load - Renders toggles for each flag (
cvGeneration,portfolioContentApi) - Writes changes via
PATCH /api/feature-flags(requires admin auth) - The backend TTL cache is explicitly busted after a successful write so the next
GETreflects the new value immediately
The panel is available at the UIGen admin portal and requires the user to be authenticated as admin. On dev, this means completing the EasyAuth + OAuth PKCE flow. On prod, it requires a valid Entra token from the portfolio-admins group.
docker-compose — the backend service receives FEATURE_* env vars for local flag overrides:
Frontend nav button¶
The Admin button in the top navigation bar opens the Admin modal. It is only rendered when VITE_UIGEN_URL is set to a non-empty value (baked in at build time).
| Context | VITE_UIGEN_URL value |
Button visible |
|---|---|---|
| Local docker-compose | http://localhost:4400 |
✅ Yes |
| Prod build (CI) | https://admin.sven-relijveld.com |
✅ Yes |
| Dev build (CI) | https://admin.dev.sven-relijveld.com |
✅ Yes |
| Build without env var | `` (empty) | ❌ No |
docker-compose service¶
UIGen is built from Dockerfile.uigen which installs the UIGen packages at image build time:
Key design decisions:
Dockerfile.uigen: packages are installed at build time (not runtime), so the container starts immediately with no install step127.0.0.1binding: port is only accessible on localhost, not all network interfacesBACKEND_URLenv var: the container fetches the OpenAPI spec from this URL at startup and patches it so UIGen's proxy targets the backend correctly
Azure deployment¶
UIGen runs as a Container App (ca-ui) alongside the frontend and backend:
- Image:
portfolio-uigenpushed to ACR, built fromDockerfile.uigen - Managed Identity: own user-assigned identity with AcrPull + (on dev) Key Vault Secrets User
- Custom domain:
admin.sven-relijveld.com(prod) /admin.dev.sven-relijveld.com(dev) with managed TLS cert - Scale: 0–1 replicas (scale-to-zero; UIGen is on-demand)
- Dev auth: EasyAuth with
unauthenticatedClientAction: RedirectToLoginPage BACKEND_URL: set to the backend Container App FQDN at deploy time
Troubleshooting¶
Admin button not visible — VITE_UIGEN_URL was empty at build time. Rebuild with the env var set.
/auth redirect loop — UIGen probing /api/uigen-token in the OpenAPI spec can cause a 401 loop. The endpoint uses include_in_schema=False to hide it from UIGen. If this reappears, check the spec.
API calls return errors — check the backend is healthy:
CSS theme not applied — the shim proxy must be running and buffering HTML. Check shim logs:
UIGen login loop / never reaches dashboard — a chain of issues was fixed across PRs #443–#451. If you see a redirect loop after Entra login:
- Verify
sessionValidationEndpointin.uigen/config.yamlis set to/auth/me(no/apiprefix — the shim proxy handles it) - Verify the shim injects the Bearer token from
sessionStorageinto/api/auth/merequests - Verify the Entra app registration has
requestedAccessTokenVersion: 2in the manifest - Verify the localhost redirect URI is on the SPA platform (not Web) in the Entra app registration
Feature flags panel shows no flags / PATCH fails 403 — the backend MI needs App Configuration Data Owner (not just Data Reader) on the App Configuration store. Check RBAC assignments.
See Also¶
- Local Setup — full docker-compose stack
- API Endpoints — all available routes
- Backend Architecture — FastAPI internals
Page history
| Field | Value |
|---|---|
| Last updated | 2026-05-19 |
Changelog
| Date | PRs | Summary |
|---|---|---|
| 2026-04-18 | #205 | Initial UIGen API Explorer page |
| 2026-04-18 | #207 | UIGen promoted to deployed service; admin.sven-relijveld.com; auth model; Dockerfile; updated flow |
| 2026-05-03 | #358, #362 | Update detected resources table to reflect removal of /admin/ prefix, addition of awards/certifications, PATCH cv/generate, and portfolioContentApi flag Stale resource table listing /admin/* groupings |
| 2026-05-19 | #438, #439, #443, #444, #446, #447, #448, #451, #452, #455 | Add Feature Flags Override Panel section; update Auth model to document OAuth PKCE flow and /auth/me endpoint; add UIGen OAuth login loop fix notes to troubleshooting; update EasyAuth note |