Skip to content

Releases: Promptly-Technologies-LLC/fastapi-jinja2-postgres-webapp

v0.1.19

18 Mar 22:54

Choose a tag to compare

Summary

  • Toast migration: Replaced the custom showToast() JS function and client-side flash cookie reader with server-side rendering via htmx-ext-remove-me for auto-dismiss, HTMX responseHandling config for error-status OOB swaps, and a flash cookie middleware for full-page-load toasts.
  • Avatar update fix: Replaced HX-Refresh: true on 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 toast
    • test_avatar_update_toast_appears — avatar update shows toast
    • test_avatar_update_no_full_reload — avatar update uses OOB swaps, no page reload
    • test_htmx_error_toast_appears — error responses show toast via OOB
    • test_flash_cookie_toast_appears — flash cookies render server-side on load
    • test_toast_auto_dismisses — toasts auto-dismiss after 5s via remove-me
    • test_toast_close_button — manual close button works

🤖 Generated with Claude Code

v0.1.18

18 Mar 20:10

Choose a tag to compare

Summary

Closes #175

  • Clear the "Add email" form field after successful submission using HTMX's hx-on::after-request event, with an HX-Trigger header 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

18 Mar 14:31

Choose a tag to compare

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.cookies from mangling commas (\054) and breaking client-side JSON.parse().
  • NeedsNewTokens query string preservation: The token-refresh redirect now uses str(request.url) instead of request.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

14 Mar 20:19

Choose a tag to compare

Summary

  • Add RefreshToken model with JTI tracking in the private schema 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

14 Mar 16:46

Choose a tag to compare

  • 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.py now has an example/illustrative OrganizationResource data model, and this data model is automatically imported and set up with the rest of the DB

v0.1.14

14 Mar 04:45

Choose a tag to compare

Summary

  • Adds a GitHub Actions workflow that automatically merges main into modal and hetzner deployment 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 modal and hetzner branches receive the latest main changes
  • 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

14 Mar 04:36

Choose a tag to compare

Enforces that:

  • Templates contain no syntax errors
  • Templates use url_for instead of hardcoded routes for all onsite links
  • Routes pass all required context variables when rendering templates
  • url_for calls all point at valid FastAPI routes

v0.1.12

14 Mar 03:21

Choose a tag to compare

Summary

  • Add require_unauthenticated_client dependency that wraps get_optional_user and redirects authenticated users to the dashboard via a new AlreadyAuthenticatedError exception handler
  • Add get_verified_account dependency that wraps get_authenticated_account with 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

14 Mar 02:09

Choose a tag to compare

Release v0.1.11

v0.1.10

14 Mar 02:08

Choose a tag to compare

Summary

  • Enable Open Graph and Twitter Card meta tags via _quarto.yml for rich link previews on social media
  • Add site-url for canonical URLs and automatic sitemap generation
  • Add description frontmatter to all .qmd pages 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, and twitter: tags
  • Confirm sitemap.xml is generated in _docs/

🤖 Generated with Claude Code