Appearance
v1.3 Merchant Login UX
Shipped: 2026-04-07 | Phases: 3 (24–26) | Plans: 13 | Git: 25 commits, 46 files, +10,254 lines
The shortest code milestone by phase count, but arguably the most important product decision: merchants need traditional email login, not wallet-first authentication. This was validated when Playwright E2E tests caught real UX issues with wallet-only login blocking email setup.
What Shipped
Phase 24: Email-First Auth
The foundation of merchant authentication.
- Better Auth email/password provider — Native D1/Drizzle adapter, Hono middleware
- Resend email transport — Transactional emails for verification, password reset
- Session identity refactor — Shifted from
walletAddress-primary touserId-primary identity model - Login page rewrite — Email/password form with forgot/reset/verify flows
- Migration banner — For wallet-only merchants who need to add an email address
Phase 25: Google SSO + Wallet Linking + Team/Org Management
Social login and organizational structure.
- Google OAuth — With auto account linking to existing email accounts
- SIWS repurposed as wallet-link verification — Wallets are linked post-login, not used for login itself
- Org model — 1 org = 1 merchant entity, auto-created on signup
- Invite-by-email — Team members invited with role-based access
- Roles — Owner, admin, and viewer with route-level gating
Phase 26: Security + Migration Polish
Hardening the auth system.
- Auth endpoint rate limiting — 5 requests/minute/IP via Better Auth middleware
- Geolocated session management UI — See active sessions with location info
- TOTP 2FA — QR enrollment with backup codes, inline 2FA challenge during login
- Legacy wallet-to-email migration — End-to-end migration path verified with Playwright E2E tests
What Worked
Better Auth as Auth Framework
Native D1/Drizzle adapter, Hono middleware, 2FA plugin, social providers — all worked out of the box. Zero custom auth infrastructure needed. This confirmed Better Auth as the right choice over Auth.js (Next.js-centric) and Clerk/Auth0 (vendor lock-in, usage-based pricing).
Milestone Audit Before Completion
Running the milestone audit before archival caught:
- Planning drift (root roadmap still marked v1.3 in progress)
- Missing verification artifacts for Phases 25 and 26
- Integration bugs (invite acceptance conflicting with fresh personal org creation)
- Session serialization gaps (primary wallet changes not propagating)
- Security gaps (2FA endpoints not rate-limited)
All fixed before shipping. This established the "audit before archive" rule that persisted through all subsequent milestones.
Playwright E2E for Auth Flows
End-to-end tests for the wallet-to-email migration path caught real UX issues:
- Forced redirects making the migration UI unreachable
- SIWS-only login blocking email setup for legacy users
- Wallet access restoration needed as migration-only path (not general login)
Without Playwright, these would have been production issues.
Centralized Redirect Handling
auth-redirect.ts eliminated duplicated route logic across login, setup-email, and protected-route handoffs. Single source of truth for auth flow navigation.
What Was Inefficient
UI Drift Detected Late
Login redirect/error context, wallet migration discoverability, destructive session revoke UX, and accessible status messaging all had gaps that required audit-driven fixes. Future: run UI audit earlier in the milestone.
Integration Bugs from Parallel Execution
Invite acceptance conflicting with fresh personal org creation, primary wallet changes not propagating to session state — these surfaced during audit, not during plan execution. Wave testing should include cross-plan integration checks.
Rate Limiting Applied Late
Better Auth 2FA verification endpoints weren't rate-limited until the audit caught it. Security middleware should be applied as part of the feature plan, not a separate security phase.
Patterns Established
Email-Primary, Wallet-Secondary
Merchants authenticate with email/password or Google SSO. Wallets are linked post-login for treasury operations only. SIWS is a wallet ownership verification tool, not a login method. This reversed the v1.0 design (wallet-first) and was validated by real UX testing.
Org = Merchant Entity
Every merchant signup auto-creates a personal org. Team members are org members with roles. All billing operations are scoped to org, not individual user. This model carried forward into v1.5 checkout and portal.
Migration-Only SIWS Login
Legacy wallet-only merchants can still use SIWS to access a forced /setup-email flow. SIWS is not available as a general login path. This preserves backward compatibility without compromising the email-first model.
Auth Redirect Preservation
?redirect= param preserved across login → setup-email → verification flows via centralized helper. Prevents users from losing their intended destination during multi-step auth flows.
Key Decision: Email over Wallet-first
This was the pivotal product decision of v1.3. The reasoning:
- Merchants are business users — They expect email login, not wallet management
- Wallets are treasury tools — Connected after login for signing transactions
- Team access — Email-based invites and roles don't map to wallet addresses
- Recovery — Email reset flows are familiar; wallet loss is catastrophic without email backup
- Validated by testing — Playwright caught that wallet-only login blocked email setup, confirming the decision
Final Validation
All checks passed after remediation:
| Command | Result |
|---|---|
cd vela-dashboard && bun run tsc --noEmit | PASS |
cd vela-dashboard && bun run build | PASS |
cd vela-dashboard && bun test | PASS |
cd vela-dashboard && bunx playwright test tests/e2e/email-first-auth.e2e.ts | PASS |
Key Lessons
- Run milestone audit mid-milestone, not at completion — The v1.3 audit found 6 categories of gaps. Catching these earlier would have avoided the remediation pass.
- Security middleware belongs in feature plans — Rate limiting, CSRF, 2FA enforcement should be applied when building the feature, not in a separate security phase.
- Cross-plan integration testing needed — Individual plans passed their own tests, but interactions between org creation + invite acceptance + session serialization had bugs only visible at integration level.
- Better Auth plugin ecosystem is production-ready — 2FA, social login, session management all worked with minimal custom code. Good framework choice confirmed.