Add system email notifications and password recovery#178
Add system email notifications and password recovery#178Atlas-SZ wants to merge 5 commits intodataelement:mainfrom
Conversation
|
PR 178 评审意见:
建议 (LGTM):
|
Address PR dataelement#178 review follow-ups by making system SMTP timeout configurable and clarifying PUBLIC_BASE_URL expectations for production reset links.\n\nConstraint: Keep SMTP env-driven and avoid introducing queue infrastructure or behavior changes to auth responses\nRejected: Leaving SMTP timeout hardcoded at 15s | blocks operator tuning for slow providers\nConfidence: high\nScope-risk: narrow\nReversibility: clean\nDirective: Keep reset-link generation on PUBLIC_BASE_URL/public_base_url and avoid localhost values in production\nTested: backend/.venv/bin/python -m pytest tests/test_password_reset_and_notifications.py\nTested: backend/.venv/bin/python -m ruff check app/config.py app/services/system_email_service.py app/services/password_reset_service.py tests/test_password_reset_and_notifications.py\nNot-tested: live SMTP provider behavior under high latency
|
已根据建议完成两项改进并推送:
验证:
|
|
Thanks for this comprehensive PR! The password recovery flow and system email service are exactly what we need. However, this PR currently bundles two independent features together:
Since the WeCom org sync is already covered separately in #183, could you please split this PR into two?
This way we can review and merge each feature independently without risk of conflicts. Additionally, since you've already built the SMTP infrastructure and email verification token pattern, it would be great if you could also add email verification during registration in the same PR (or a follow-up):
This would complete the email lifecycle: registration verification + password recovery + broadcast notifications. Looking forward to the updated PR! |
|
很抱歉造成了混淆,应该是我本地代码提交导致的混乱,我将彻底拆分两个独立功能分别对应不同 issues 进行提交。 |
This change adds a platform-owned SMTP delivery path and wires it into forgot-password plus optional enterprise broadcast email delivery. The reset flow now issues single-use database-backed tokens, exposes public reset endpoints, and adds frontend pages for requesting and consuming reset links. The README and env example now document the required SMTP and public URL configuration for local and production setups. Constraint: SMTP configuration must come from environment variables rather than admin-managed secrets Constraint: Forgot-password responses must not reveal whether an email address exists Rejected: Reusing per-agent email tooling | wrong trust boundary for system-owned auth mail Rejected: Stateless reset JWTs | harder to revoke and audit than DB-backed single-use tokens Confidence: high Scope-risk: moderate Reversibility: clean Directive: Do not move reset-link generation away from PUBLIC_BASE_URL without verifying frontend route compatibility Tested: backend pytest tests/test_password_reset_and_notifications.py Tested: frontend npm run build Tested: manual local validation of forgot-password, reset-password, and SMTP delivery with Docker PostgreSQL/Redis Not-tested: full end-to-end browser automation for clicking the emailed reset link
This change removes English-only fallback text from the new password recovery flow and broadcast email controls so the feature matches the existing bilingual frontend behavior. The new auth pages now read from i18n, and both English and Simplified Chinese dictionaries include the new strings. Constraint: New user-facing copy must follow the existing frontend i18n structure instead of introducing page-local string tables Rejected: Leaving default English fallbacks in component code | inconsistent with the rest of the localized UI Confidence: high Scope-risk: narrow Reversibility: clean Directive: Add future auth and enterprise UI copy to locale files at the same time as the component change Tested: frontend npm run build Tested: manual browser check of /forgot-password Chinese rendering Not-tested: full language-switch regression across all newly added strings
This change moves system email delivery off the main request path for forgot-password and broadcast email sends. Password recovery now queues email delivery after persisting the reset token, and broadcast email sends are isolated per recipient so one SMTP failure does not abort the entire operation. Constraint: Keep the current env-driven SMTP configuration and avoid adding queue infrastructure Constraint: Requests must remain responsive even when SMTP is slow or misconfigured Rejected: Leave SMTP on the request path | risks slow or stalled user-facing requests Rejected: Add a durable mail queue now | too much scope for a targeted hardening pass Confidence: high Scope-risk: narrow Reversibility: clean Directive: Treat emails_sent in broadcast responses as queued recipients, not guaranteed SMTP success Tested: backend pytest tests/test_password_reset_and_notifications.py Tested: backend ruff check app/api/auth.py app/api/notification.py app/services/system_email_service.py tests/test_password_reset_and_notifications.py Tested: manual browser E2E reset-password -> login flow after the hardening change Not-tested: process-crash behavior between response return and background email completion
Address PR dataelement#178 review follow-ups by making system SMTP timeout configurable and clarifying PUBLIC_BASE_URL expectations for production reset links.\n\nConstraint: Keep SMTP env-driven and avoid introducing queue infrastructure or behavior changes to auth responses\nRejected: Leaving SMTP timeout hardcoded at 15s | blocks operator tuning for slow providers\nConfidence: high\nScope-risk: narrow\nReversibility: clean\nDirective: Keep reset-link generation on PUBLIC_BASE_URL/public_base_url and avoid localhost values in production\nTested: backend/.venv/bin/python -m pytest tests/test_password_reset_and_notifications.py\nTested: backend/.venv/bin/python -m ruff check app/config.py app/services/system_email_service.py app/services/password_reset_service.py tests/test_password_reset_and_notifications.py\nNot-tested: live SMTP provider behavior under high latency
The password reset migration was anchored to an older branch point, which created a second Alembic head alongside add_daily_token_usage. Reattach it to the current mainline so upgrades remain linear for PR dataelement#178.\n\nConstraint: Preserve the password reset schema change without introducing a merge migration in this PR\nRejected: Add a separate Alembic merge revision | extra migration noise for a single isolated table addition\nConfidence: high\nScope-risk: narrow\nReversibility: clean\nDirective: New migrations in feature PRs must be rebased onto the current Alembic head before review\nTested: cd backend && .venv/bin/alembic heads\nTested: cd backend && .venv/bin/python -m pytest tests/test_password_reset_and_notifications.py\nNot-tested: full backend migration upgrade/downgrade cycle on a populated database
|
本次提交只涉及“忘记密码” 功能,不再涉及其他功能。 |
Summary
This PR adds platform-owned email delivery for password recovery and optional company broadcast emails.
What Changed
Validation
cd backend && .venv/bin/python -m pytest tests/test_password_reset_and_notifications.pycd backend && .venv/bin/python -m ruff check app/api/auth.py app/api/notification.py app/services/system_email_service.py tests/test_password_reset_and_notifications.pycd frontend && npm run buildNotes
emails_sentin broadcast responses now means queued recipients, not guaranteed final SMTP successRisk