- Activity log: import_log DB table, GET /activity endpoint, collapsible
panel in Update Data tab showing who changed what score and when
- Sync logging: Box syncs now also write to import_log with before/after scores
- Multilingual: ES, PT, IT, PL UI strings in i18n/ui.js; content translations
(pillars, scoring labels, About tab) in clients/adeo/config.json; language
switcher upgraded from EN/FR toggle to 6-language dropdown
- cfg() and pillarDisplayName() generalised to support any language (not just FR)
- import_file.py: reads 'Final QA ...' column first (falls back to Score) so
QA-updated XLSX files produce the correct overall score on import
- convert_data.py/docker-compose: use ADEO_DATA_ROOT env var for Box path
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Move Focus Areas from a collapsible panel into its own dedicated tab
- Fix text overflow and badge sizing in question rows
- Translate all Focus Areas strings (pillar performance, questions section)
- Fix About tab: summary, pillar names, scoring labels now switch to FR
- Fix question modal: pillar name now shows translated name
- Fix stat labels (Questions/Pillars/Markets) in About section
- Fix import toast to use translated scoring label
- Add translations block to /api/clients summary response
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
index.html references /i18n/ui.js (added in 8d0a618 for the EN/FR
toggle) but the Dockerfile only copies index.html, script.js, server/,
and *.py. Without this, the browser 404s on /adeo-maturity/i18n/ui.js
and the language toggle silently fails.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Working state before improvements branch:
- Language toggle (EN/FR) for ADEO
- 59 question topics translated to French
- About tab translated and toggle visible on home screen
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
These were added in 5eac433 (the About-tab commit) and got dropped
during the auth rewrite. The About tab uses them to render the
Maturity Levels, How To Use, and Pillars sections; without them
the page rendered empty fallbacks.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previously the script only ran port resolution when no compose
containers were already running, on the assumption that running
containers meant the persisted port was still ours. On the shared
optical-dev server that's wrong: another app can grab a port
between our deploys, leaving us with a stale .env value that fails
to bind.
Now find_free_port treats a port as "available for us" if either
nothing is listening, or one of our own compose containers is
publishing it (so re-deploys don't shuffle). Other-app listeners
trigger a re-pick and a warning.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a Postgres-backed user store with bcrypt + JWT cookie sessions,
login screen, role-gated UI, and Microsoft SSO scaffolding ready to
fill in.
Backend
- New `db` service (Postgres 16-alpine) in compose, healthcheck-gated
app startup, free-port autodetect (5435-5499) like other apps.
- `server/db.js` runs versioned `.sql` migrations on boot.
- `server/auth.js`: bcrypt + JWT cookie (httpOnly, sameSite=strict,
path-scoped to /adeo-maturity), rate-limited login (10/15min),
dummy bcrypt-compare on missing users to defeat timing oracles.
- `requireAdmin` on all writes (POST/import/sync); `authenticate`
on all reads. /api/health stays public.
- Microsoft SSO endpoints stubbed at /api/auth/msft/{login,callback}
(return 501); DB has azure_oid column ready; comments document
exactly how to wire @azure/msal-node.
Frontend
- Login screen with email/password + greyed-out "Sign in with
Microsoft" button; init() checks /api/auth/me first.
- Logout button + user badge in header.
- body.role-user CSS hides .admin-only elements (Update tab, New
Client cards). Server enforces regardless.
Deploy
- deploy.sh generates DB_PASSWORD and AUTH_SECRET on first run and
persists to .env, then runs `seed-users.js seed-defaults` to
create admin@oliver.agency + user@oliver.agency with random
passwords printed once. Subsequent deploys skip seeding unless
--reseed is passed.
- node server/seed-users.js set-password <email> <pw> for ad-hoc
resets later.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
config.json had "logo": "logo.png" but the file on disk is Logo.png.
Works on macOS (case-insensitive FS) and 404s on Linux (case-sensitive).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three <img src="/clients/..."> tags were using absolute paths, so the
browser fetched them from the host root rather than under the app's
URL prefix — broken images when the app is mounted at a sub-path.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Subpath-aware deploy for /adeo-maturity/ behind the shared optical-dev
vhost. Auto-picks a free host port (prefers 3102, scans 3102-3199) and
persists it to .env so re-deploys are idempotent. Renders the Apache
conf from a template on each run.
- script.js: detect URL prefix at load time and prepend it to all /api/
calls, so the same code works at the root locally and under a
sub-path behind Apache.
- Dockerfile: fix broken package.json copy (lives at repo root, not
server/) and install python3 + reportlab + openpyxl for the sync/
import/PDF endpoints that shell out.
- docker-compose: pin top-level name (per global docker policy),
configurable host port, bind 127.0.0.1 only.
- deploy/: new deploy.sh + apache-adeo.conf.tmpl. Old root deploy.sh
removed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Heatmap matrix: pillar × market colour-coded table in Compare tab
- Radar/spider chart: pure SVG chart in entity detail view
- Sort controls: sort by overall score, pillar, or group on Markets tab
- Group toggle: cluster entity cards by group (Leroy Merlin / Obramat etc.)
- About tab: home screen tab explaining scoring levels, pillars, and features
- /api/clients now returns pillars, scoring, about for About tab rendering
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Highlights markets with missing scores, rationale, gap analysis,
or stale sync data. Also adds per-entity synced date to data.json
and cache-busts script.js.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Matches loreal-spec-tool deploy pattern. Runs on port 3102.
clients/ dir mounted as volume so data.json persists across deploys.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Multi-client maturity dashboard (Express/vanilla JS, port 3102).
ADEO client: 8 markets, 7 pillars, 59 questions.
Includes data converter, universal PDF summary generator, and
new-client wizard for adding future clients.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>