Owner accounts: auth, password reset, CRM dashboard visibility #19
Notifications
Due Date
No due date set.
Blocks
Depends on
#22 Per-client ICS calendar feed
BPPP/smb-online
#24 New-client onboarding automation update
BPPP/smb-online
#15 Booking schema + tenancy-safe data access layer
BPPP/smb-online
Reference: BPPP/smb-online#19
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Parent
#14
What to build
Business-owner identity: a real login scoped to a single client, password reset both self-service
and operator-triggered, and visibility into owner accounts from the existing CRM dashboard.
users.password_hash(standard Flask session,werkzeug password hashing — no new auth framework). A logged-in session is scoped to exactly one
client_id; every subsequent owner route (tickets 6/7/8) must resolveclient_idfrom thissession, never from a request parameter.
password_reset_tokensrow (single-use, expiring).sends the same reset email on the operator's behalf.
Credentials, etc.) listing each client's owner user(s).
Acceptance criteria
client_id.is enforced by ticket 1's data-access layer, but this ticket is what actually resolves
client_idfrom session rather than trusting a request param).dashboard.
Blocked by
Implemented in
59c35ce(pushed tomain)./owner/login, Flask-session-backed, scoped to exactly oneclient_id(never a request param) via a newlogin_requireddecorator inowner_auth.py— the foundation tickets 6/7/8 will build the real dashboard on top of./owner/forgot-password+/owner/reset-password/<token>, using the existing single-use/expiringpassword_reset_tokensrow from #15. Enumeration-safe (same response whether or not the email matched a user).POST /api/owner_users/<user_id>/reset-password, gated by the CRM token, sends the same reset email.GET /api/owner_users) listing owner accounts across all clients with a "Reset-Link senden" button per row.owner_mail.pyreuses the #18mailer.py/booking_mail.pysender-resolution pattern for the reset email.SESSION_SECRET_KEYenv var for the session cookie, kept separate fromCRM_API_TOKEN/BOOKING_TOKEN_SECRET(added to.env.exampleanddocker-compose.yml).test_owner_auth.py+ additions totest_booking_db.py), all passing against a real throwaway Postgres per #14's testing convention. Full suite: 97/97 passing.All acceptance criteria met.