Releases: Promptly-Technologies-LLC/fastapi-jinja2-postgres-webapp
Releases · Promptly-Technologies-LLC/fastapi-jinja2-postgres-webapp
v0.1.19
Summary
- Toast migration: Replaced the custom
showToast()JS function and client-side flash cookie reader with server-side rendering viahtmx-ext-remove-mefor auto-dismiss, HTMXresponseHandlingconfig for error-status OOB swaps, and a flash cookie middleware for full-page-load toasts. - Avatar update fix: Replaced
HX-Refresh: trueon avatar upload with OOB swaps for both the profile display and navbar avatar. This eliminates the visible flicker from full page reloads and ensures the "Profile updated successfully" toast always appears (previously lost during refresh). - Navbar avatar partial: Extracted the navbar avatar into a reusable partial (
navbar_avatar.html) with an OOB variant (navbar_avatar_oob.html) for HTMX responses.
Test plan
- All 362 non-browser unit/integration tests pass
- All 7 Playwright browser tests pass, including:
test_htmx_success_toast_appears— name-only profile update shows toasttest_avatar_update_toast_appears— avatar update shows toasttest_avatar_update_no_full_reload— avatar update uses OOB swaps, no page reloadtest_htmx_error_toast_appears— error responses show toast via OOBtest_flash_cookie_toast_appears— flash cookies render server-side on loadtest_toast_auto_dismisses— toasts auto-dismiss after 5s via remove-metest_toast_close_button— manual close button works
🤖 Generated with Claude Code
v0.1.18
Summary
Closes #175
- Clear the "Add email" form field after successful submission using HTMX's
hx-on::after-requestevent, with anHX-Triggerheader from the server to signal success - Order email addresses on the profile page with primary first via
ORDER BY is_primary DESC, so the newly-promoted email always moves to the top row
Test plan
-
test_add_email_htmx_triggers_form_reset— verifies HX-Trigger header is returned on HTMX add-email requests -
test_profile_emails_ordered_primary_first— primary email with a higher row ID still renders before secondary -
test_profile_emails_ordered_primary_first_after_promote— newly promoted email appears first after swap - Full test suite passes (358 tests)
🤖 Generated with Claude Code
v0.1.17
Summary
- Multi-email system: Users can add a secondary email (max 2), verify it via an emailed link, promote it to primary, or remove it. The old single-email update flow (
EmailUpdateToken,/request_email_update,/confirm_email_update) has been removed. - Account recovery: When a sensitive email change occurs (primary swap or email removal), the affected email receives a notification with a tokenized recovery link. Clicking it restores the victim's email as primary, purges attacker emails, revokes all sessions, and forces a password reset.
- Password reset auto-login: After resetting a password, the user is automatically logged in and redirected to the dashboard — no redundant login step.
- Flash cookie encoding fix: URL-encode the JSON cookie value before setting it, preventing Python's
http.cookiesfrom mangling commas (\054) and breaking client-sideJSON.parse(). - NeedsNewTokens query string preservation: The token-refresh redirect now uses
str(request.url)instead ofrequest.url.path, preserving query parameters for GET routes.
QA checklist
Add and verify a secondary email
- Log in and navigate to profile page
- Add a secondary email address via the form
- Verify a "Verification email sent" toast appears
- Note: "Add email" field/button should clear/disable after submission
- Check the secondary email inbox to verify verification link was sent
- Click the verification link
- Verify redirect to login page with success toast
- After login, verify the new email appears on the profile page as verified (non-primary)
- Verify the primary email received a "New email added" notification
Promote a secondary email to primary
- From profile page, click "Make Primary" on the verified secondary email
- Verify a "Primary email updated" toast appears
- Verify the profile page now shows the new primary email
- Note: Primary email should move to top row rather than just swapping labels
- Check the OLD primary email inbox for a "Primary Email Changed" notification
- Verify the notification contains a "Recover Your Account" button/link (not just "change your password")
Remove a secondary email
- Add and verify a secondary email, then click "Remove"
- Verify a "Email address removed" toast appears
- Check the REMOVED email inbox for an "Email Address Removed" notification
- Verify the notification contains a "Recover Your Account" button/link
Account recovery (after primary swap)
- With a promoted secondary email as primary, click the recovery link sent to the old primary
- Verify redirect to the password reset page with "Account recovered. Please set a new password." toast
- Submit a new password
- Verify auto-login: redirected to dashboard with "Password reset successfully." toast (no manual login required)
- Navigate to profile and verify the original email is restored as the sole primary email
- Verify the attacker's email has been removed from the account
Account recovery (after email removal)
- Remove a secondary email, then click the recovery link sent to that email
- Verify the same recovery flow as above works (redirect to reset, auto-login, email restored)
Recovery edge cases
- Click an expired recovery link (>7 days) — should see an error, not a crash
- Click a used recovery link — should see an error
- Click a recovery link with a bogus token — should see an error
Standard password reset (regression check)
- Use "Forgot Password" flow to reset password
- Verify auto-login after reset (redirect to dashboard, not login page)
- Verify "Password reset successfully." toast appears on the dashboard
Flash toast visibility (regression check)
- Verify toasts appear on all redirect flows above (not silently swallowed)
- Specifically test with both fresh sessions and expired sessions
🤖 Generated with Claude Code
v0.1.16
Summary
- Add
RefreshTokenmodel with JTI tracking in theprivateschema for server-side refresh token validation - Implement token rotation: each refresh token use revokes the old token and issues a new one
- Add reuse detection: replaying a revoked token revokes ALL tokens for that account (signals theft)
- Logout now revokes the refresh token server-side, not just deleting the cookie
- Email update flow revokes all old refresh tokens before issuing new ones
- Legacy tokens without JTI (pre-migration) are gracefully rejected, forcing re-login
- Fix misleading "new email address" text in email update form to correctly say "current email address"
Test plan
- 7 new integration tests covering all security flows (register/login token creation, logout revocation, token rotation, reuse detection, legacy rejection, automatic dependency refresh)
- Updated existing unit tests for new JTI-aware token API
- All 298 tests pass (291 existing + 7 new)
- Manual testing of register, login, logout, and email update flows
Closes #81
🤖 Generated with Claude Code
v0.1.15
- The dashboard now has a dropdown that lets you select an organization (so you can interact only with the resources for that organization)
utils/app/models.pynow has an example/illustrativeOrganizationResourcedata model, and this data model is automatically imported and set up with the rest of the DB
v0.1.14
Summary
- Adds a GitHub Actions workflow that automatically merges
mainintomodalandhetznerdeployment branches on every push - If merge conflicts arise, opens a PR instead so they can be resolved manually
- Uses the existing GitHub App token for authentication
Test plan
- Merge this PR and verify the propagate workflow runs
- Confirm both
modalandhetznerbranches receive the latestmainchanges - Optionally introduce a deliberate conflict on a deployment branch to verify the fallback PR creation works
Closes #169
🤖 Generated with Claude Code
v0.1.13
Enforces that:
- Templates contain no syntax errors
- Templates use
url_forinstead of hardcoded routes for all onsite links - Routes pass all required context variables when rendering templates
url_forcalls all point at valid FastAPI routes
v0.1.12
Summary
- Add
require_unauthenticated_clientdependency that wrapsget_optional_userand redirects authenticated users to the dashboard via a newAlreadyAuthenticatedErrorexception handler - Add
get_verified_accountdependency that wrapsget_authenticated_accountwith email/password re-verification for sensitive operations like account deletion - Update routes (
read_home,read_login,read_register,read_forgot_password,delete_account) to use the new dependencies, removing duplicated check-and-redirect logic from route bodies
Closes #108
Test plan
- Added unit tests for
require_unauthenticated_client(authenticated raises, unauthenticated passes) - Added unit tests for
get_verified_account(email mismatch, wrong password, success) - All 383 existing tests pass
🤖 Generated with Claude Code
v0.1.11
Release v0.1.11
v0.1.10
Summary
- Enable Open Graph and Twitter Card meta tags via
_quarto.ymlfor rich link previews on social media - Add
site-urlfor canonical URLs and automatic sitemap generation - Add
descriptionfrontmatter to all.qmdpages for<meta name="description">tags - Improve alt text on homepage screenshot image
Closes #37
Test plan
- Verify Quarto renders successfully with
quarto render - Inspect generated HTML for
<meta name="description">,og:tags, andtwitter:tags - Confirm
sitemap.xmlis generated in_docs/
🤖 Generated with Claude Code