diff --git a/.gitignore b/.gitignore index bc5d5e6..66aea94 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,10 @@ frontend/dist # NOTE: `frontend/src` was previously listed here, which silently excluded the entire frontend # source tree from new commits. The existing files stayed tracked only because they were added # before the rule. Removed deliberately — see CHANGELOG. + +# Playwright MCP session cache -- console logs + page snapshots regenerated on every +# browser-automation run, never project content. +.playwright-mcp/ + +# macOS Finder metadata. +.DS_Store diff --git a/.playwright-mcp/console-2026-09-06T16-25-54-975Z.log b/.playwright-mcp/console-2026-09-06T16-25-54-975Z.log deleted file mode 100644 index 5cd64ef..0000000 --- a/.playwright-mcp/console-2026-09-06T16-25-54-975Z.log +++ /dev/null @@ -1,4 +0,0 @@ -[ 1167ms] [INFO] %cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold @ http://localhost:5173/node_modules/.vite/deps/react-dom_client.js?v=b492bb20:14335 -[ 1372ms] [ERROR] Failed to load resource: the server responded with a status of 401 (UNAUTHORIZED) @ http://localhost:5173/api/v1/auth/session:0 -[ 1375ms] [ERROR] Failed to load resource: the server responded with a status of 404 (Not Found) @ http://localhost:5173/favicon.ico:0 -[ 1530ms] [ERROR] Failed to load resource: the server responded with a status of 401 (UNAUTHORIZED) @ http://localhost:5173/api/v1/auth/session:0 diff --git a/.playwright-mcp/console-2026-09-06T16-26-36-860Z.log b/.playwright-mcp/console-2026-09-06T16-26-36-860Z.log deleted file mode 100644 index 0b3f8c8..0000000 --- a/.playwright-mcp/console-2026-09-06T16-26-36-860Z.log +++ /dev/null @@ -1 +0,0 @@ -[ 288ms] [INFO] %cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold @ http://localhost:5173/node_modules/.vite/deps/react-dom_client.js?v=b492bb20:14335 diff --git a/.playwright-mcp/console-2026-09-06T16-29-13-176Z.log b/.playwright-mcp/console-2026-09-06T16-29-13-176Z.log deleted file mode 100644 index b0b0866..0000000 --- a/.playwright-mcp/console-2026-09-06T16-29-13-176Z.log +++ /dev/null @@ -1,3 +0,0 @@ -[ 3057ms] [INFO] %cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold @ http://localhost:5173/node_modules/.vite/deps/react-dom_client.js?v=b492bb20:14335 -[ 3897ms] [ERROR] Failed to load resource: the server responded with a status of 401 (UNAUTHORIZED) @ http://localhost:5173/api/v1/auth/session:0 -[ 3985ms] [ERROR] Failed to load resource: the server responded with a status of 401 (UNAUTHORIZED) @ http://localhost:5173/api/v1/auth/session:0 diff --git a/.playwright-mcp/console-2026-09-06T16-30-37-945Z.log b/.playwright-mcp/console-2026-09-06T16-30-37-945Z.log deleted file mode 100644 index cf77473..0000000 --- a/.playwright-mcp/console-2026-09-06T16-30-37-945Z.log +++ /dev/null @@ -1,3 +0,0 @@ -[ 2327ms] [INFO] %cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold @ http://localhost:5173/node_modules/.vite/deps/react-dom_client.js?v=b492bb20:14335 -[ 2843ms] [ERROR] Failed to load resource: the server responded with a status of 401 (UNAUTHORIZED) @ http://localhost:5173/api/v1/auth/session:0 -[ 2852ms] [ERROR] Failed to load resource: the server responded with a status of 401 (UNAUTHORIZED) @ http://localhost:5173/api/v1/auth/session:0 diff --git a/.playwright-mcp/console-2026-09-06T16-44-21-999Z.log b/.playwright-mcp/console-2026-09-06T16-44-21-999Z.log deleted file mode 100644 index 07d51ae..0000000 --- a/.playwright-mcp/console-2026-09-06T16-44-21-999Z.log +++ /dev/null @@ -1 +0,0 @@ -[ 568ms] [INFO] %cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold @ http://localhost:5173/node_modules/.vite/deps/react-dom_client.js?v=b492bb20:14335 diff --git a/.playwright-mcp/page-2026-09-06T16-25-56-687Z.yml b/.playwright-mcp/page-2026-09-06T16-25-56-687Z.yml deleted file mode 100644 index 79b929e..0000000 --- a/.playwright-mcp/page-2026-09-06T16-25-56-687Z.yml +++ /dev/null @@ -1,26 +0,0 @@ -- generic [ref=e2]: - - generic [ref=e4]: - - heading "Create your account" [level=1] [ref=e5] - - generic [ref=e6]: - - generic [ref=e7]: Email - - textbox "Email" [ref=e8] - - generic [ref=e9]: - - generic [ref=e10]: - - generic [ref=e11]: Password - - textbox "Password" [ref=e12] - - list [ref=e13]: - - listitem [ref=e14]: - - text: At least 8 characters - - generic [ref=e17]: — not met - - listitem [ref=e18]: - - text: "12+ characters, or a mix of 3+ of: lowercase, uppercase, number, symbol" - - generic [ref=e21]: — not met - - generic [ref=e22]: - - generic [ref=e23]: Confirm password - - textbox "Confirm password" [ref=e24] - - button "Create account" [ref=e25] [cursor=pointer] - - paragraph [ref=e27]: - - text: Already have an account? - - link "Log in" [ref=e28] [cursor=pointer]: - - /url: /login - - region "Notifications" \ No newline at end of file diff --git a/.playwright-mcp/page-2026-09-06T16-26-11-791Z.yml b/.playwright-mcp/page-2026-09-06T16-26-11-791Z.yml deleted file mode 100644 index 6fee254..0000000 --- a/.playwright-mcp/page-2026-09-06T16-26-11-791Z.yml +++ /dev/null @@ -1,21 +0,0 @@ -- generic [ref=e2]: - - generic [ref=e30]: - - heading "Log in" [level=1] [ref=e31] - - generic [ref=e32]: - - generic [ref=e33]: Email - - textbox "Email" [ref=e34] - - generic [ref=e35]: - - generic [ref=e36]: Password - - textbox "Password" [ref=e37] - - generic [ref=e38]: - - checkbox "Remember me" [ref=e39] - - text: Remember me - - button "Log in" [ref=e40] [cursor=pointer] - - paragraph [ref=e42]: - - text: Don't have an account? - - link "Register" [ref=e43] [cursor=pointer]: - - /url: /register - - region "Notifications" [ref=e44]: - - status [ref=e45]: - - generic [ref=e46]: Account created — log in to continue. - - button "Dismiss notification" [ref=e47] [cursor=pointer]: ✕ \ No newline at end of file diff --git a/.playwright-mcp/page-2026-09-06T16-26-24-613Z.yml b/.playwright-mcp/page-2026-09-06T16-26-24-613Z.yml deleted file mode 100644 index 394c96f..0000000 --- a/.playwright-mcp/page-2026-09-06T16-26-24-613Z.yml +++ /dev/null @@ -1,29 +0,0 @@ -- generic [ref=e2]: - - generic [ref=e48]: - - banner [ref=e49]: - - generic [ref=e50]: - - link "Trueup, go to home" [ref=e51] [cursor=pointer]: - - /url: /dashboard - - text: Trueup - - navigation "Primary" [ref=e52]: - - link "Onboarding" [ref=e54] [cursor=pointer]: - - /url: /onboarding - - button "Account menu, signed in as uidiag001@example.com" [ref=e57] [cursor=pointer]: - - generic [aria-hidden] [ref=e58]: UI - - main [ref=e61]: - - generic [ref=e62]: - - generic [ref=e63]: - - heading "Identity and funding status" [level=1] [ref=e64] - - button "Refresh status" [ref=e65] [cursor=pointer] - - generic [ref=e68]: - - generic [ref=e69]: - - generic [ref=e70]: Identity verification - - generic [ref=e71]: Pending - - generic [ref=e73]: - - generic [ref=e74]: Account approval - - generic [ref=e75]: Pending - - generic [ref=e78]: - - heading "Verify your identity" [level=2] [ref=e79] - - paragraph [ref=e80]: We use Stripe Identity to confirm who you are — you'll need a government-issued photo ID. - - button "Start identity verification" [ref=e81] [cursor=pointer] - - region "Notifications" \ No newline at end of file diff --git a/.playwright-mcp/page-2026-09-06T16-26-37-243Z.yml b/.playwright-mcp/page-2026-09-06T16-26-37-243Z.yml deleted file mode 100644 index 25d2704..0000000 --- a/.playwright-mcp/page-2026-09-06T16-26-37-243Z.yml +++ /dev/null @@ -1,2 +0,0 @@ -- generic [ref=f3e2]: - - region "Notifications" \ No newline at end of file diff --git a/.playwright-mcp/page-2026-09-06T16-27-25-675Z.yml b/.playwright-mcp/page-2026-09-06T16-27-25-675Z.yml deleted file mode 100644 index cd0aea3..0000000 --- a/.playwright-mcp/page-2026-09-06T16-27-25-675Z.yml +++ /dev/null @@ -1,33 +0,0 @@ -- generic [ref=f3e2]: - - generic [ref=f3e3]: - - banner [ref=f3e4]: - - generic [ref=f3e5]: - - link "Trueup, go to home" [ref=f3e6] [cursor=pointer]: - - /url: /dashboard - - text: Trueup - - navigation "Primary" [ref=f3e7]: - - link "Onboarding" [ref=f3e9] [cursor=pointer]: - - /url: /onboarding - - generic [ref=f3e11]: - - button "Account menu, signed in as uidiag001@example.com" [expanded] [ref=f3e12] [cursor=pointer]: - - generic [aria-hidden] [ref=f3e13]: UI - - generic [ref=f3e38]: - - paragraph [ref=f3e39]: uidiag001@example.com - - button "Log out" [active] [ref=f3e40] [cursor=pointer] - - main [ref=f3e16]: - - generic [ref=f3e17]: - - generic [ref=f3e18]: - - heading "Identity and funding status" [level=1] [ref=f3e19] - - button "Refresh status" [ref=f3e20] [cursor=pointer] - - generic [ref=f3e23]: - - generic [ref=f3e24]: - - generic [ref=f3e25]: Identity verification - - generic [ref=f3e26]: Pending - - generic [ref=f3e28]: - - generic [ref=f3e29]: Account approval - - generic [ref=f3e30]: Pending - - generic [ref=f3e33]: - - heading "Verify your identity" [level=2] [ref=f3e34] - - paragraph [ref=f3e35]: We use Stripe Identity to confirm who you are — you'll need a government-issued photo ID. - - button "Start identity verification" [ref=f3e36] [cursor=pointer] - - region "Notifications" \ No newline at end of file diff --git a/.playwright-mcp/page-2026-09-06T16-27-43-136Z.yml b/.playwright-mcp/page-2026-09-06T16-27-43-136Z.yml deleted file mode 100644 index 7bb35c9..0000000 --- a/.playwright-mcp/page-2026-09-06T16-27-43-136Z.yml +++ /dev/null @@ -1,18 +0,0 @@ -- generic [ref=f3e2]: - - generic [ref=f3e43]: - - heading "Log in" [level=1] [ref=f3e44] - - generic [ref=f3e45]: - - generic [ref=f3e46]: Email - - textbox "Email" [ref=f3e47] - - generic [ref=f3e48]: - - generic [ref=f3e49]: Password - - textbox "Password" [ref=f3e50] - - generic [ref=f3e51]: - - checkbox "Remember me" [ref=f3e52] - - text: Remember me - - button "Log in" [ref=f3e53] [cursor=pointer] - - paragraph [ref=f3e55]: - - text: Don't have an account? - - link "Register" [ref=f3e56] [cursor=pointer]: - - /url: /register - - region "Notifications" \ No newline at end of file diff --git a/.playwright-mcp/page-2026-09-06T16-29-17-030Z.yml b/.playwright-mcp/page-2026-09-06T16-29-17-030Z.yml deleted file mode 100644 index e99458a..0000000 --- a/.playwright-mcp/page-2026-09-06T16-29-17-030Z.yml +++ /dev/null @@ -1,2 +0,0 @@ -- generic [ref=f6e2]: - - region "Notifications" \ No newline at end of file diff --git a/.playwright-mcp/page-2026-09-06T16-30-40-682Z.yml b/.playwright-mcp/page-2026-09-06T16-30-40-682Z.yml deleted file mode 100644 index 26d3f68..0000000 --- a/.playwright-mcp/page-2026-09-06T16-30-40-682Z.yml +++ /dev/null @@ -1,2 +0,0 @@ -- generic [ref=e2]: - - region "Notifications" \ No newline at end of file diff --git a/.playwright-mcp/page-2026-09-06T16-31-08-410Z.yml b/.playwright-mcp/page-2026-09-06T16-31-08-410Z.yml deleted file mode 100644 index 54d25a3..0000000 --- a/.playwright-mcp/page-2026-09-06T16-31-08-410Z.yml +++ /dev/null @@ -1,47 +0,0 @@ -- generic [ref=e2]: - - generic [ref=e3]: - - banner [ref=e4]: - - generic [ref=e5]: - - link "Trueup, go to home" [ref=e6] [cursor=pointer]: - - /url: /dashboard - - text: Trueup - - navigation "Primary" [ref=e7]: - - generic [ref=e8]: - - link "Dashboard" [ref=e9] [cursor=pointer]: - - /url: /dashboard - - link "Portfolio" [ref=e10] [cursor=pointer]: - - /url: /portfolio - - link "Orders" [ref=e11] [cursor=pointer]: - - /url: /orders - - generic [ref=e13]: - - link "Transactions" [ref=e14] [cursor=pointer]: - - /url: /transactions - - link "Funding" [ref=e15] [cursor=pointer]: - - /url: /funding - - link "Tax lots" [ref=e16] [cursor=pointer]: - - /url: /lots - - link "Statements" [ref=e17] [cursor=pointer]: - - /url: /statements - - link "Fees" [ref=e18] [cursor=pointer]: - - /url: /fees - - link "Ask Trueup" [ref=e21] [cursor=pointer]: - - /url: /chat - - button "Account menu, signed in as uidiag001@example.com" [ref=e24] [cursor=pointer]: - - generic [aria-hidden] [ref=e25]: UI - - main [ref=e28]: - - generic [ref=e29]: - - heading "Dashboard" [level=1] [ref=e30] - - generic [ref=e31]: - - generic [ref=e32]: - - generic [ref=e33]: Account balance - - generic [ref=e34]: $0.00 - - generic [ref=e35]: As of Sep 6, 2026 - - generic [ref=e36]: - - generic [ref=e37]: Month-to-date return - - generic [ref=e38]: +0.00% - - generic [ref=e39]: - - heading "Target allocation" [level=2] [ref=e40] - - generic [ref=e41]: - - paragraph [ref=e45]: No model assigned yet - - paragraph [ref=e46]: Choose a model on the Portfolio page to see your target allocation here. - - region "Notifications" \ No newline at end of file diff --git a/.playwright-mcp/page-2026-09-06T16-44-22-809Z.yml b/.playwright-mcp/page-2026-09-06T16-44-22-809Z.yml deleted file mode 100644 index 26d3f68..0000000 --- a/.playwright-mcp/page-2026-09-06T16-44-22-809Z.yml +++ /dev/null @@ -1,2 +0,0 @@ -- generic [ref=e2]: - - region "Notifications" \ No newline at end of file diff --git a/.playwright-mcp/page-2026-09-06T16-44-32-784Z.yml b/.playwright-mcp/page-2026-09-06T16-44-32-784Z.yml deleted file mode 100644 index 005b8d2..0000000 --- a/.playwright-mcp/page-2026-09-06T16-44-32-784Z.yml +++ /dev/null @@ -1,50 +0,0 @@ -- generic [ref=e2]: - - generic [ref=e3]: - - banner [ref=e4]: - - generic [ref=e5]: - - link "Trueup, go to home" [ref=e6] [cursor=pointer]: - - /url: /dashboard - - text: Trueup - - navigation "Primary" [ref=e7]: - - generic [ref=e8]: - - link "Dashboard" [ref=e9] [cursor=pointer]: - - /url: /dashboard - - link "Portfolio" [ref=e10] [cursor=pointer]: - - /url: /portfolio - - link "Orders" [ref=e11] [cursor=pointer]: - - /url: /orders - - generic [ref=e13]: - - link "Transactions" [ref=e14] [cursor=pointer]: - - /url: /transactions - - link "Funding" [ref=e15] [cursor=pointer]: - - /url: /funding - - link "Tax lots" [ref=e16] [cursor=pointer]: - - /url: /lots - - link "Statements" [ref=e17] [cursor=pointer]: - - /url: /statements - - link "Fees" [ref=e18] [cursor=pointer]: - - /url: /fees - - generic [ref=e20]: - - link "Ask Trueup" [ref=e21] [cursor=pointer]: - - /url: /chat - - link "Onboarding" [ref=e22] [cursor=pointer]: - - /url: /onboarding - - button "Account menu, signed in as ui-capture-1788711863@example.com" [ref=e25] [cursor=pointer]: - - generic [aria-hidden] [ref=e26]: UC - - main [ref=e29]: - - generic [ref=e30]: - - generic [ref=e31]: - - heading "Identity and funding status" [level=1] [ref=e32] - - button "Refresh status" [ref=e33] [cursor=pointer] - - generic [ref=e36]: - - generic [ref=e37]: - - generic [ref=e38]: Identity verification - - generic [ref=e39]: Pending - - generic [ref=e41]: - - generic [ref=e42]: Account approval - - generic [ref=e43]: Pending - - generic [ref=e46]: - - heading "Verify your identity" [level=2] [ref=e47] - - paragraph [ref=e48]: We use Stripe Identity to confirm who you are — you'll need a government-issued photo ID. - - button "Start identity verification" [ref=e49] [cursor=pointer] - - region "Notifications" \ No newline at end of file diff --git a/backend/app/services/identity/auth.py b/backend/app/services/identity/auth.py index 73e5da2..6431efa 100644 --- a/backend/app/services/identity/auth.py +++ b/backend/app/services/identity/auth.py @@ -70,4 +70,11 @@ def totp_provisioning_uri(secret: str, email: str) -> str: def verify_totp(secret: str, code: str) -> bool: - return pyotp.TOTP(secret).verify(code) + """`valid_window=1` accepts the current 30-second window plus one on either side (RFC 6238's + recommended tolerance for clock drift and network latency) -- the library's own default, + `valid_window=0`, has zero tolerance and rejects a genuinely correct code whenever the + login-then-verify round trip crosses a window boundary. Real network jitter can trigger that, + which is what surfaced as a nondeterministic CI failure in + `test_mfa_enroll_reset_rejects_the_wrong_password` (passed on the identical code an hour + earlier).""" + return pyotp.TOTP(secret).verify(code, valid_window=1) diff --git a/frontend/vite.config.js b/frontend/vite.config.js index 8207e71..8e81c77 100644 --- a/frontend/vite.config.js +++ b/frontend/vite.config.js @@ -7,11 +7,11 @@ export default defineConfig({ server: { proxy: { '/api': { - target: 'http://localhost:5001', + target: 'http://localhost:5000', changeOrigin: true, }, '/health': { - target: 'http://localhost:5001', + target: 'http://localhost:5000', changeOrigin: true, }, },