Skip to content

feat(auth): redesign login ux with password toggle and autofill - #993

Open
d-oit wants to merge 13 commits into
mainfrom
feature/login-ux-redesign
Open

feat(auth): redesign login ux with password toggle and autofill#993
d-oit wants to merge 13 commits into
mainfrom
feature/login-ux-redesign

Conversation

@d-oit

@d-oit d-oit commented Aug 17, 2026

Copy link
Copy Markdown
Owner

Summary

feat(auth): redesign login ux with password toggle and autofill

Stacked on #991 (demo login + help entry points). The 11 GOAP-244 commits below also appear in #991; merge #991 first, then rebase this branch onto main. The unique work here is 6ae89c6 + ef043d1.

What this PR adds (ADR-245 / GOAP-246)

  • WCAG 3.3.8 password toggle on all auth password fields (reader login, admin credentials, admin MFA recovery): eye icon + localized label at sm+, icon-only with aria-label below sm so long-locale labels (fr/ru/de) cannot overflow the input.
  • Dual-action demo: "Try the demo" one-click + "Fill demo credentials" autofill (refs on the uncontrolled reader form, state on admin). Replaces the plaintext demo info line; /help still lists credentials.
  • Rich app info: desktop feature-hero (4 reader / 3 admin value props, how-access-works note, help link) + compact mobile info card below lg on both screens.
  • Pre-existing fixes: AdminLoginPage 521 → ~438 lines (MFA forms extracted), duplicate login test suite deleted.
  • i18n: +17/−4 keys across all 13 catalogs with real translations.
  • Docs: ADR-245 (supersedes ADR-244 Amendment C decision 2), GOAP-246, ADR-INDEX rows, LEARNINGS entry (Tier 2 fix(skills): add version field to all SKILL.md files #12 satisfied in-PR).

Changes

  • ef043d1 fix(auth): markdown lint and toggle overflow for long locales
  • 6ae89c6 feat(auth): redesign login ux with password toggle and autofill
  • a852674 fix(seed+web): provision demo book and same-origin API base so demo reader sign-in works
  • 5f8fd8f feat(demo): document demo user passwords and sign in via normal forms (GOAP-244 Amendment C)
  • d61281d fix(web): help link + demo info render without any VITE_* vars (GOAP-244 Amendment B)
  • ec81249 feat(web): add in-app help page and same-origin help URL (GOAP-244 Amendment B)
  • ad09e99 refactor(auth): extract login forms into sub-components to reduce component complexity (GOAP-244)
  • b766193 feat(web): full auth-page visibility, demo info panel, prominent help (GOAP-244 Amendment A)
  • 54b74af fix: address PR review findings for demo login (GOAP-244)
  • 64852a8 test(e2e): add demo login + help link coverage across viewports (GOAP-244)
  • 8650183 docs(plans): normalize trailing newline in ADR-244/GOAP-244 docs
  • 5f9485c docs(plans): accept ADR-244 and record GOAP-244 completion
  • 382685a feat: add demo login entry points and help links (GOAP-244)

Related

  • ADR: plans/245-adr-login-ux-redesign.md
  • Plan: plans/246-goap-login-ux-redesign.md
  • Learnings: agents-docs/LEARNINGS.md § GOAP 246

Type

feat

Checklist

  • Quality gate passed
  • All tests pass
  • No secrets in code
  • Conventional commit format

d-oit added 12 commits August 15, 2026 12:53
Implement ADR-244: server-minted demo sessions for the reserved demo
reader/admin accounts plus a validated help/how-to-use link on both auth
screens. Add POST /api/demo/reader-login and /api/demo/admin-login with
fail-closed gates (server flag, production-env detection, created_by_demo,
disabled/compromised, role/book/grant checks). Frontend demo buttons only
render when VITE_DEMO_LOGIN_ENABLED=1; the Worker gate stays authoritative.

Also relax check-adr-index.mjs to treat GOAP execution records sharing a
number with an ADR as siblings per ADR-083 s2 (GOAP-244 + ADR-244), with a
focused test.
Finalize GOAP-244 as COMPLETED and ADR-244 as Accepted in the ADR index,
and mark the plan documents accordingly.
…-244)

Add Playwright specs for the ADR-244 demo entry points (reader demo,
admin demo, help links) with the full viewport matrix (chromium, firefox,
webkit, iphone, pixel, pwa-chromium). Mock the /api/demo/reader-login and
/api/demo/admin-login endpoints in E2E fixtures and wire the demo reader
response through mockReaderApi's loginResponse chain.

Tests are gated on E2E_DEMO_LOGIN=1 so the scheduled CI e2e build (which
does not set VITE_DEMO_LOGIN_ENABLED) skips them cleanly; demo-only build
runs the full 550-test matrix green.
Security:
- createAdminDemoSession now refuses to mint a password-assurance session
  when the demo admin is MFA-enrolled (mfa_method=passkey), closing the
  ADR-234 second-factor bypass. Demo route returns DEMO_DISABLED.
- Demo reader login no longer depends on the operator-supplied reader
  password hash: it looks up the demo book + live grant directly instead of
  validateGrant (which required the password and broke demo login in
  deployments that set DEMO_READER_PASSWORD). Server-minted, password-free.

Quality:
- Memoize resolveHelpUrl() so it is not called on every render (both auth pages).
- Align DEMO_READER_RESPONSE E2E fixture with the real API DTO (visibility,
  coverImageUrl).
- Use the idiomatic 'extends JsonRow' for DemoUserRow instead of a manual
  index signature; fix JSDoc gate numbering and add the missing blank line
  before the new admin-middleware function.

Config/docs:
- Document DEMO_ACCOUNTS_PROD_ALLOWLIST in wrangler.jsonc and .dev.vars.example.
- Wire E2E_DEMO_LOGIN and demo-enabling build vars into the scheduled CI
  e2e-full job so the demo E2E specs actually run in CI.

Tests:
- Add worker tests: password-protected demo grant still mints a reader
  session; missing demo grant returns 403; MFA-enrolled demo admin returns 403.
… (GOAP-244 Amendment A)

Layout:
- Anchor auth screens to the top with pb-8 instead of vertical centering so
  the full login card is scrolled into view — no more clipped admin
  description or help link below the fold on smaller viewports.
- Move the 'Are you an author or manager?' admin/reader description inside
  the card so it renders alongside the form.

Demo info:
- Show the reserved demo email (and reader book slug) under the demo button
  when demo login is enabled, explaining it signs in without a password.
- New i18n keys login.demoInfo / admin.login.demoInfo across all 13 catalogs.

Help link:
- Render the help link inside the card footer at text-sm font-medium so it is
  discoverable without scrolling on both auth screens.

Tests:
- Web: demo info panel visibility (shown/hidden by flag).
- E2E: assert the demo info panel email text on reader and admin login.

Docs: ADR-244 + GOAP-244 Amendment A (full-page visibility + demo info).
…ponent complexity (GOAP-244)

Addresses OwlWatch review: LoginPage (333 lines, complexity 19) and
AdminLoginPage (400 lines) were long, branching components. Extract the
login/recovery/demo forms, token views, header, and the demo-login hook
into small focused sub-components:
- LoginForm / RecoveryForm / RecoverySuccessView / DemoLoginBlock /
  LoginCardHeader / TokenVerifyingView / TokenErrorView
- useDemoLogin + toAuthStorePayload (shared session->store mapping)
- AdminCredentialsForm / AdminRecoveryForm / MfaFactorChooser /
  AdminDemoBlock / AdminLoginHeader + useAdminDemoLogin
- Merge duplicate LoginSubmitButton/RecoverySubmitButton into SubmitButton

Behavior unchanged: same DOM, same accessible labels, same actions. 1294
web tests + 20 demo E2E tests pass.
…endment B)

The deployed previews never set an absolute VITE_HELP_URL, so the auth
screen 'Help / how to use' link never rendered. Research into 2025-26
login/demo UX (Authgear, SaaSUI, MicroFounder, Rajiv Pant) confirms the
leading pattern is a password-free one-click demo plus an in-product
'what this app does / how to use' page — not credentials on the login.

- New public /help route (lazy + suspense): app intro, reader vs admin
  roles, and the reserved demo accounts (emails + book slug). No demo
  password is ever rendered (ADR-233/244).
- resolveHelpUrl accepts a same-origin /help path instead of requiring
  an absolute external URL, so the link works on localhost, previews,
  and production without baking a hostname.
- VITE_HELP_URL=/help wired into .env.local.example, the Cloudflare
  Pages preview build (lighthouse.yml), and the E2E demo build (ci.yml).
- Demo buttons stay local/E2E-only in deployments (ADR-233/244).
- i18n help.* keys added across all 13 locale catalogs.
- Web tests: HelpPage render/gating/back-link + resolveHelpUrl relative,
  external, invalid branches; E2E help-link assertions now expect /help.
- Plan ADR-244 + GOAP-244 Amendment B.
…244 Amendment B)

The Cloudflare Pages GitHub integration builds with a plain `pnpm build`
and no environment variables, so resolveHelpUrl() returned null and the
isDemoLoginEnabled() gate hid the demo emails — the original complaint
persisted on the exact preview users see.

- resolveHelpUrl() now defaults to { href: '/help', isExternal: false }
  when VITE_HELP_URL is unset or invalid; the /help route ships in every
  deployment, so the auth-screen help link renders regardless of env.
- HelpPage demo section is no longer gated on isDemoLoginEnabled() — the
  reserved demo emails + book slug are documented/public per ADR-233 and
  safe to show on the info page even when one-click buttons are off.
- Tests updated: resolveHelpUrl default/fallback branches; HelpPage always
  shows demo accounts.
… (GOAP-244 Amendment C)

Product decision (user-directed, overrides ADR-244 decision 7 for the demo
accounts only): the reserved demo reader and admin users now have documented
public passwords and sign in through the normal email+password login forms.
Production fail-closed behavior is unchanged — the seed and Worker still
refuse production-like environments and the demo admin stays disabled
outside local unless explicitly allowlisted.

Seed:
- Default both demo passwords to documented values (demo-reader-password /
  demo-admin-password), hash with Argon2id, and always provision the reader
  grant as password_protected. Operator env vars still override.
- Remove the now-redundant DEMO_ADMIN_PASSWORD-required guard; export the
  documented password constants; keep production fail-closed guards.

Frontend:
- demo-config exports DEMO_READER_EMAIL/PASSWORD, DEMO_ADMIN_EMAIL/PASSWORD,
  DEMO_BOOK_SLUG (env-driven with documented defaults) as a single source of
  truth.
- Login demo info panels (reader + admin) and the help page now show email +
  password + book slug.
- Env typing + .env.local.example / .dev.vars.example document the values.

i18n: login.demoInfo, admin.login.demoInfo, help.demo* updated in all 13
catalogs to include the password credential.

E2E: new tests sign in as the demo reader and demo admin via the standard
email+password forms and assert navigation; fixtures gain demo credential
constants and an admin-login mock option.

Tests: seed unit tests updated (default passwords, hashed, password_protected
grant); web suite + seed tests + quality gate pass.
…eader sign-in works

Demo reader sign-in failed on fresh/seeded deployments for two reasons:
- The seed only created a reader grant if a 'demo' book already existed and
  never provisioned one, so the grant was silently skipped (GOAP-244 demo
  accounts were not sign-in-ready). The seed now inserts a placeholder demo
  book (ON CONFLICT DO NOTHING) and always attaches the reader grant.
- Web baked 'http://localhost:8787' as the API base when VITE_API_BASE_URL
  was unset (a banned pattern per docs/banned-patterns.md), so built
  deployments pointed at the browser's own localhost and every sign-in
  request failed in the console with 'Failed to fetch'. Built deployments now
  default to the same origin; local dev keeps the Wrangler fallback.

Verified: seed unit tests 16/16; web suite 120 files / 1298 tests pass.
ADR-245 / GOAP-246: wire WCAG 3.3.8 eye-icon password toggle into all auth forms, replace the plaintext demo info line with a dual-action panel (one-click + autofill credentials), and add a rich feature-hero with mobile variant to both reader and admin login screens. Extracts subcomponents to fix a pre-existing 521-line violation on AdminLoginPage.tsx and deletes the duplicate login test suite.
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 17, 2026

Copy link
Copy Markdown

Deploying do-epub-studio with  Cloudflare Pages  Cloudflare Pages

Latest commit: ef043d1
Status: ✅  Deploy successful!
Preview URL: https://8d59024b.do-epub-studio.pages.dev
Branch Preview URL: https://feature-login-ux-redesign.do-epub-studio.pages.dev

View logs

@github-actions

github-actions Bot commented Aug 17, 2026

Copy link
Copy Markdown

🚀 Performance Report

🛠️ CI & Workflow

Metric Value Limit Trend Status
Total CI Duration 5.23 min 15.00 min -
Pnpm Cache Hit Hit - -

⚡ Turbo Task Performance

Task Duration (s) Cache Status Trend Status
@do-epub-studio/reader-core#build 0.00 MISS - 🔄
@do-epub-studio/schema#build 0.00 MISS - 🔄
@do-epub-studio/shared#build 0.00 MISS - 🔄
@do-epub-studio/testkit#build 0.00 MISS - 🔄
@do-epub-studio/ui#build 0.00 MISS - 🔄
@do-epub-studio/web#build 0.00 MISS - 🔄
@do-epub-studio/worker#build 0.00 MISS - 🔄

Cache Hit Ratio: 0% (0/7 tasks)

🧪 Test Stability

Metric Value Trend Status
Total Tests 0 - -
Failed Tests 0 -
Flaky Rate 0.00% -

@codacy-production

codacy-production Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 164 complexity · 76 duplication

Metric Results
Complexity 164
Duplication 76

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

Codacy/pre-commit MD038: remove leading spaces inside code spans in GOAP-246 and LEARNINGS. Password toggle: icon-only below sm with aria-label carrying the accessible name; localized text at sm+ so long labels (fr/ru/de) cannot overflow the pr-12 reservation.
@repowise-bot

repowise-bot Bot commented Aug 17, 2026

Copy link
Copy Markdown

✅ Health of changed files: 5.2 → 5.7 (+0.5)
🚨 Change risk: high, riskier than 99% of this repo's commits.

📋 At a glance
5 files changed health · 5 hotspots touched · 6 new findings introduced · 1 co-change pair left out · 5 files with recent fix history · 7 dead-code findings.

Files & modules (3)
  • apps (11 files)
    • apps/tests/login-and-book-load.spec.ts
    • .../auth/LoginPage.tsx
    • .../__tests__/app-identity-parity.test.tsx
    • .../i18n/ru.ts
    • .../lib/env.ts
    • .../auth/LoginPage.test.tsx
    • .../i18n/de.ts
    • .../i18n/fr.ts
    • .../i18n/en.ts
    • .../auth/admin-middleware.ts
    • .../api/core.ts
  • packages (1 file)
    • .../__tests__/Input.test.tsx
  • scripts (2 files)
    • scripts/seed-demo-accounts.mjs
    • scripts/check-adr-index.mjs

✅ Health gate: passed

📌 Before you merge

  • Run apps/tests/a11y-advanced.spec.ts, apps/tests/accessibility-audit.spec.ts, apps/tests/catalog-admin-flows.spec.ts, apps/tests/edge-cases.spec.ts (+17 more): they import the changed files
  • .../reader/ReaderPage.tsx changed together with .../i18n/de.ts in 15 past commits and isn't in this PR

🎯 Blast radius (symbols whose signature this PR changed, and who calls them)

  • mockAdminApi in apps/tests/fixtures.ts signature changed. Called by 5 symbols outside this PR: apps/tests/a11y-advanced.spec.ts::__module__, apps/tests/accessibility-audit.spec.ts::__module__, apps/tests/catalog-search.spec.ts::__module__ (+2 more)
🔎 More signals (4)

🗺️ Change map

flowchart LR
  subgraph PR ["Changed in this PR (2 modules)"]
    m_apps["apps (21 files)"]:::changed
    m_packages["packages (2 files)"]:::changed
  end
  classDef changed fill:#dbeafe,stroke:#1d4ed8,color:#1e3a5f
  classDef warn fill:#fef3c7,stroke:#b45309,color:#78350f
  classDef guard fill:#dcfce7,stroke:#15803d,color:#14532d
Loading

Solid arrows: code that imports the changed files (67 direct dependents, from the last indexed snapshot). Dashed: history/tests.

🔥 Hotspots touched (5)

  • .../i18n/ru.ts: 16 commits/90d, 15 dependents
  • .../lib/env.ts: 5 commits/90d, 58 dependents
  • scripts/check-adr-index.mjs: 1 commits/90d, 0 dependents
2 more
  • apps/tests/login-and-book-load.spec.ts: 10 commits/90d, 2 dependents
  • .../auth/LoginPage.test.tsx: 3 commits/90d, 0 dependents

🔗 Hidden coupling (3 files)

  • .../i18n/de.ts co-changes with .../reader/ReaderPage.tsx (15×, 🟡 notable), not in this PR.
  • .../i18n/fr.ts co-changes with .../reader/ReaderPage.tsx (15×, 🟡 notable), not in this PR.
  • .../i18n/en.ts co-changes with .../reader/ReaderPage.tsx (15×, 🟡 notable), not in this PR.

💀 Dead code (7 findings)

  • 💀 scripts/check-adr-index.mjs errors (confidence 0.65)
  • 💀 scripts/check-adr-index.mjs numbers (confidence 0.65)
  • 💀 .../auth/admin-middleware.ts ADMIN_SESSION_TOKEN_BYTES (confidence 0.65)
4 more
  • 💀 .../auth/admin-middleware.ts ADMIN_SESSION_TTL_HOURS (confidence 0.65)
  • 💀 .../api/core.ts DEFAULT_TIMEOUT_MS (confidence 0.65)
  • 💀 .../api/core.ts MAX_RETRIES (confidence 0.65)
  • 💀 .../api/core.ts INITIAL_BACKOFF_MS (confidence 0.65)

📊 See the full report for this PR
Your repo map with this PR's blast radius lit up, every caller of the contracts it changes, and health before and after. No sign-in. · ⭐ Star Repowise · 📥 Install bot · Silence on a single PR with [skip repowise] in the title · Per-repo toggle on repowise.dev/settings?tab=bot · Updated 2026-08-17 11:47 UTC

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant