- Center 'Delete All Forms' button and add bottom padding
- Search shortcut: Shift+K -> Ctrl/Cmd+K
- Form navigation: Ctrl/Cmd+J/K -> Shift+J/K (frees Ctrl/Cmd+K for search)
- Keep navbar title centered when preview actions appear
- Add dark backdrop that blocks background clicks when form preview is open
- Center close + form action icons inside their icon buttons
- update_readme_metrics.py: fall back to existing README values instead of
overwriting with "N/A (MongoDB not connected)" when metrics are unavailable
- measure_perf.py: fix uploaded_id extraction — ParsedForm.id is top-level,
not nested under a "form" key, so delete timing now actually runs
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Root README now has: one-liner description, live links, screenshot
placeholders, CI-updated perf table, stack summary, short contributing.
backend/README.md: full API reference, file format, DB schema, testing.
frontend/README.md: setup, runtime config, structure, features, testing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- scripts/measure_perf.py — times validation, parsing, upload, delete
against the live Render deployment; saves perf_results.json
- scripts/update_readme_metrics.py — reads results and rewrites the
Performance Metrics Table in README.md with live numbers + timestamp
- ci.yml — new perf-metrics job (push to main only) runs after
backend-tests pass, commits updated README back to the repo
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
During server-side rendering main.ts never runs, so loadRuntimeConfig()
is never called and apiUrl falls back to localhost:8000. The failed HTTP
call triggers the error snackbar during client hydration. Guard loadForms
with isPlatformBrowser so it only runs in the browser where the config
is correctly loaded.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The fallback middleware was calling call_next first, so OPTIONS hit the
router (no handler → 400) before headers could be injected. Intercept
OPTIONS early and return 200 with CORS headers directly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
pandas 3.0+ requires openpyxl 3.1.5+. The pinned 3.1.2 caused all
Excel file reads to fail with a version error.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
CORSMiddleware only fires when Origin header reaches the app. Cloudflare or
proxy layers can strip it before the middleware sees it. The fallback http
middleware ensures the header is always present when Origin is in the request.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
allow_credentials=True + allow_origins=["*"] is invalid per the CORS spec.
Starlette drops the Access-Control-Allow-Origin header in this case.
The API uses no cookies so credentials are not needed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
angular.json assets glob covers public/ not src/assets/, so config.json
was never copied to the build output and the runtime fetch was falling
back to localhost:8000.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Without this file the frontend fell back to localhost:8000, causing CORS
failures on the deployed Vercel app.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
tlsCAFile=certifi.where() is the correct pymongo parameter to supply the
Mozilla CA bundle, resolving TLSV1_ALERT_INTERNAL_ERROR on both Python
3.11 and 3.14 when connecting to Atlas over TLS.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Blocking startup_event on connect_to_mongo() prevented the server from
opening its port when Atlas was slow or unreachable, causing Render to
wait indefinitely. Connection now runs as a background task.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
pymongo does not accept ssl_context as a constructor argument. Python 3.11
(now enforced via .python-version) handles Atlas TLS fine without it.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
OpenSSL 3.x defaults to security level 2 which drops cipher suites Atlas needs.
Create an explicit SSL context at SECLEVEL=1 so TLS negotiation succeeds on any
Python version. Also add .python-version to steer Render toward Python 3.11.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Python 3.14 on Render has OpenSSL incompatibilities causing TLSV1_ALERT_INTERNAL_ERROR
when connecting to MongoDB Atlas. Pinning to 3.11.9 resolves the SSL negotiation issue.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add vercel.json with Angular build config and SPA rewrites
- Increase Angular bundle budgets to unblock production build
- Fix TS strict null error in runtime-config.ts (return _config ?? {})
- Load API_URL from /assets/config.json at bootstrap via prebuild script
- Wire getRuntimeConfig() into FormService instead of hardcoded localhost
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>