Changelog
This changelog is generated automatically from GitHub Releases.
v1.1.7
2026-07-06 · GitHub
What’s Changed
- add frontend tests by @rafizamankhan in https://github.com/Promptly-Technologies-LLC/fastapi-jinja2-postgres-webapp/pull/225
Full Changelog: https://github.com/Promptly-Technologies-LLC/fastapi-jinja2-postgres-webapp/compare/v1.1.6…v1.1.7
v1.1.6
2026-07-02 · GitHub
What’s Changed
- fix: add Postgres-backed rate limiter for multi-worker deployments by @chriscarrollsmith in https://github.com/Promptly-Technologies-LLC/fastapi-jinja2-postgres-webapp/pull/222
Full Changelog: https://github.com/Promptly-Technologies-LLC/fastapi-jinja2-postgres-webapp/compare/v1.1.5…v1.1.6
v1.1.5
2026-07-02 · GitHub
What’s Changed
- fix: enforce avatar upload size limit before buffering body by @chriscarrollsmith in https://github.com/Promptly-Technologies-LLC/fastapi-jinja2-postgres-webapp/pull/220
Full Changelog: https://github.com/Promptly-Technologies-LLC/fastapi-jinja2-postgres-webapp/compare/v1.1.4…v1.1.5
v1.1.4
2026-07-02 · GitHub
What’s Changed
- fix: honor X-Forwarded-For for rate limits behind trusted proxies by @chriscarrollsmith in https://github.com/Promptly-Technologies-LLC/fastapi-jinja2-postgres-webapp/pull/221
Full Changelog: https://github.com/Promptly-Technologies-LLC/fastapi-jinja2-postgres-webapp/compare/v1.1.3…v1.1.4
v1.1.3
2026-07-02 · GitHub
What’s Changed
- fix: add CSRF tokens and convert account recovery to POST by @chriscarrollsmith in https://github.com/Promptly-Technologies-LLC/fastapi-jinja2-postgres-webapp/pull/223
Full Changelog: https://github.com/Promptly-Technologies-LLC/fastapi-jinja2-postgres-webapp/compare/v1.1.2…v1.1.3
v1.1.2
2026-07-02 · GitHub
What’s Changed
- fix: revoke sessions on password reset by @chriscarrollsmith in https://github.com/Promptly-Technologies-LLC/fastapi-jinja2-postgres-webapp/pull/215
Full Changelog: https://github.com/Promptly-Technologies-LLC/fastapi-jinja2-postgres-webapp/compare/v1.1.1…v1.1.2
v1.1.1
2026-07-01 · GitHub
What’s Changed
- Fix broken screenshot link in docs by @chriscarrollsmith in https://github.com/Promptly-Technologies-LLC/fastapi-jinja2-postgres-webapp/pull/213
Full Changelog: https://github.com/Promptly-Technologies-LLC/fastapi-jinja2-postgres-webapp/compare/v1.1.0…v1.1.1
v1.1.0
2026-07-01 · GitHub
What’s Changed
- docs: migrate documentation from raw Quarto to Great Docs by @chriscarrollsmith in https://github.com/Promptly-Technologies-LLC/fastapi-jinja2-postgres-webapp/pull/211
- New frontend theme by @chriscarrollsmith in https://github.com/Promptly-Technologies-LLC/fastapi-jinja2-postgres-webapp/pull/212
Full Changelog: https://github.com/Promptly-Technologies-LLC/fastapi-jinja2-postgres-webapp/compare/v1.0.2…v1.1.0
v1.0.2
2026-06-30 · GitHub
What’s Changed
- Fix ownership cascades during account deletion by @chriscarrollsmith in https://github.com/Promptly-Technologies-LLC/fastapi-jinja2-postgres-webapp/pull/210
Full Changelog: https://github.com/Promptly-Technologies-LLC/fastapi-jinja2-postgres-webapp/compare/v1.0.1…v1.0.2
v1.0.1
2026-06-30 · GitHub
What’s Changed
- Fix mobile layout by @rafizamankhan in https://github.com/Promptly-Technologies-LLC/fastapi-jinja2-postgres-webapp/pull/207
- Fix invalid token for logged-in users by @rafizamankhan in https://github.com/Promptly-Technologies-LLC/fastapi-jinja2-postgres-webapp/pull/208
Full Changelog: https://github.com/Promptly-Technologies-LLC/fastapi-jinja2-postgres-webapp/compare/v1.0.0…v1.0.1
v1.0.0
2026-06-23 · GitHub
What’s Changed
- ci: add semantic-release workflow and conventional commit enforcement by @chriscarrollsmith in https://github.com/Promptly-Technologies-LLC/fastapi-jinja2-postgres-webapp/pull/203
Full Changelog: https://github.com/Promptly-Technologies-LLC/fastapi-jinja2-postgres-webapp/compare/v0.1.30…v1.0.0
v0.1.30
2026-06-23 · GitHub
Summary
- Add
InstrumentedAttribute[Any]casts on allselectinloadchains inutils/core/organizations.pyper the SQLModel typing rule. - Introduce
clear_all_rate_limiters()and a session-wide autouse fixture intests/conftest.pythat resets limiters before and after every test. - Remove duplicate module-local rate limiter reset fixtures from
tests/test_htmx.pyandtests/routers/core/test_account.py.
Closes #201
Test plan
Made with Cursor
v0.1.29
2026-06-23 · GitHub
Summary
Resolves #196 by upgrading the full dependency lockfile to latest resolved versions, addressing Dependabot security alerts across runtime, dev, and transitive packages.
Key runtime upgrades: - fastapi 0.136.1 → 0.138.0 (starlette 1.0.0 → 1.3.1) - pyjwt 2.12.1 → 2.13.0 - python-multipart 0.0.29 → 0.0.32
Key dev/tooling upgrades: - pytest 8.4.2 → 9.1.1 (widened constraint from <9.0.0 to >=8.3.3) - pytest-jinja-check 1.0.2 → 1.1.0 (Starlette 1.x _IncludedRouter route discovery) - jupyter-server 2.18.2 → 2.20.0 - tornado 6.5.5 → 6.5.7 - bleach 6.3.0 → 6.4.0
Test plan
Made with Cursor
v0.1.28
2026-06-23 · GitHub
Summary
Two small, related cleanups to the communication-preferences feature added in #195:
Restore the confirm-password autocomplete regression test. #195 accidentally deleted the
defline fortest_register_page_confirm_password_has_autocomplete, collapsing its body intotest_register_page_shows_password_requirementsand demoting its docstring to a no-op string statement. The issue #156 autocomplete check is restored as its own test. The comm-preference assertions remain intest_register_page_shows_password_requirements, where they correctly verify the register page renders the new fields.Drop the
syncSubPreferenceshelper. Incommunication_preferences_fields.htmlthe helper was only ever called from the master checkbox’schangehandler (disable branch) and never on init — initial visibility is already set server-side via the Jinjastyle="display: none;"guard. Inlining it removes the indirection and the enable/disable asymmetry. Behavior is preserved exactly: enabling reveals the sub-preferences and checkscomm_updates; disabling hides them and clears both sub-preferences.
Test plan
v0.1.27
2026-06-23 · GitHub
Invalidates old invitation when prompted to send one to the same member within or after expiry without requiring cron jobs supporting cleanup.
Resolves #192
v0.1.26
2026-06-23 · GitHub
Added a cancel button to delete pending invitations.
Resolves #190
v0.1.25
2026-06-07 · GitHub
Wires the login “Remember Me” checkbox into auth cookie lifetime: unchecked logins get session cookies with a 12-hour refresh token, while checked logins get persistent cookies aligned to the existing 30-day refresh TTL. Cookie handling is centralized in set_auth_cookies() / clear_auth_cookies(), and the persistent flag is preserved through token rotation on /refresh and silent refresh via NeedsNewTokens. All auth paths keep httponly, secure, and samesite settings unchanged.
Resolves #187
v0.1.24
2026-06-04 · GitHub
Summary
- Adds a modal-only conflict resolver to the propagate workflow for
pyproject.tomlanduv.lockconflicts. - Preserves the Modal branch dependency overlay, regenerates
uv.lock, and pushes the merge when only those known files conflict. - Keeps the fallback PR path for all other conflicts.
Test plan
- Simulated the current
origin/mainintoorigin/modalmerge locally. - Verified the resolver clears
pyproject.tomlanduv.lockconflicts. - Verified the resolved
pyproject.tomlkeepsmodal>=0.73.162anduv.lockstill contains themodalpackage.
Made with Cursor
v0.1.23
2026-06-04 · GitHub
Summary
- Disables matrix fail-fast for the propagate workflow so a conflict or fallback failure on one deployment branch does not cancel the other branch’s propagation job.
- Leaves the existing GitHub App token flow in place; the app now has PR read/write permissions for fallback PR creation.
Test plan
- Not run; workflow-only change.
Made with Cursor
v0.1.22
2026-06-04 · GitHub
Confirm field re-validates against the current password; error clears when they match.
Resolves #182
v0.1.21
2026-05-20 · GitHub
Create Role Modal used to retain information from input and after role creation. Now the modal information is reset on cancel and after role creation.
Resolves #180
v0.1.20
2026-05-20 · GitHub
Fixed the modalDismiss handler in app.js to call bootstrap.Modal.hide() on any open modals before cleaning up backdrops, so the dialog properly closes after HTMX swaps the roles table.
Resolves #178
v0.1.19
2026-03-18 · GitHub
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
-
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
2026-03-18 · GitHub
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
🤖 Generated with Claude Code
v0.1.17
2026-03-18 · GitHub
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
-
- Note: “Add email” field/button should clear/disable after submission
Promote a secondary email to primary
-
- Note: Primary email should move to top row rather than just swapping labels
Remove a secondary email
Account recovery (after primary swap)
Account recovery (after email removal)
Recovery edge cases
Standard password reset (regression check)
Flash toast visibility (regression check)
🤖 Generated with Claude Code
v0.1.16
2026-03-14 · GitHub
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
Closes #81
🤖 Generated with Claude Code
v0.1.15
2026-03-14 · GitHub
- 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
2026-03-14 · GitHub
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
Closes #169
🤖 Generated with Claude Code
v0.1.13
2026-03-14 · GitHub
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
2026-03-14 · GitHub
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
🤖 Generated with Claude Code
v0.1.11
2026-03-14 · GitHub
Release v0.1.11
v0.1.10
2026-03-14 · GitHub
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
🤖 Generated with Claude Code
v0.1.9
2026-03-13 · GitHub
v0.1.8
2026-03-13 · GitHub
Resequenced deployment documentation to clarify that Modal requires separate Postgres deployment, but Hetzner does not.
- Digital Ocean PostgreSQL deployment is nested under Modal
- Removed a Supabase-related example since Supabase is not an explicit deployment target (yet)
v0.1.7
2026-03-13 · GitHub
Template changes (templates/base/partials/header.html): 1. Added a mobile-onlyv0.1.6
2026-03-13 · GitHub
- The Register page now clearly states the requirements for passwords
- The error toast, if the user submits an invalid password, restates the requirements
- Using a suggested password on Chrome now auto-populates both password fields, not just one.
v0.1.5
2026-03-12 · GitHub
- Add Hetzner Cloud deployment docs and deployment branch note
- Add hcloud CLI installation to devcontainer setup
- Update all dependencies and pin dev postgres to v17
- Replace mypy with ty type checker and fix ruff lint issues
- chore: release v0.1.2 [skip ci]
- Error messaging standardization
- Type checks and lints
- Bugfixes for modal cleanup
v0.1.4
2026-03-12 · GitHub
OOB Toast (HTMX error handlers)
These all fire through the exception handlers in main.py.
-
- Go to /account/login
- Enter a valid email format but wrong credentials
- Submit — toast renders: “Invalid email or password”
-
- Go to /account/login
- Leave both fields blank, submit
- Toast is rendered with validation messages
-
- Go to /account/register
- Fill in name/email, enter a weak password like abc, different confirm password
- Submit — toast renders: “The passwords you entered do not match”
-
- Go to /account/login
- Submit wrong credentials rapidly ~6 times (depends on your limiter config)
- Eventually toast renders: “Too many attempts…” with Retry-After
-
- Log in, go to an org page
- Try to create a role with a name that already exists (e.g. “Owner”)
- Toast: “A role with that name already exists”
-
- Harder to trigger naturally. You can use browser devtools to fire an HTMX request to a non-existent route:
htmx.ajax('GET', '/nonexistent', {target: 'body', headers: {'HX-Request': 'true'}})
- Harder to trigger naturally. You can use browser devtools to fire an HTMX request to a non-existent route:
OOB Toasts (HTMX success — append_toast)
These return the partial content + an appended toast in the same response.
-
- Log in, go to /user/profile
- Click Edit, change your name, Save
- Toast: “Profile updated successfully.”
-
- Go to an org page where you’re Owner
- Create a new role — toast: “Role created successfully.”
- Edit that role’s name — toast: “Role updated successfully.”
- Delete that role — toast: “Role deleted successfully.”
[] User role update
- On the org page, edit a member’s roles (check/uncheck roles)
- Save — toast: “User role updated successfully.”
[] Remove member
- On the org page, remove a non-owner member
- Toast: “User removed from organization.”
[] Send invitation
- On the org page, invite a new email address
- Toast: “Invitation sent successfully.”
-
- On /user/profile, enter a new email in the Update Email form
- Submit — toast: “Confirmation email sent. Check your inbox.”
Flash Cookie (PRG redirects — full page load)
These set a flash_message cookie that the JS in base.html reads on the next page load.
-
- Trigger an email update from profile
- Click the confirmation link from the email
- You’ll be redirected to /user/profile — toast: “Your email address has been successfully updated.”
[] Forgot password
- Go to /account/forgot_password (or use the Change Password section on profile)
- Submit your email
- Redirected to ?show_form=false — toast: “If an account exists with this email, a password reset link will be sent.”
-
- On the org page, edit the org name and save
- Page redirects via HX-Redirect — toast: “Organization updated successfully.”
-
- On the org page, delete the organization
- Redirected to /user/profile — toast: “Organization deleted successfully.”
JS showToast() (client-side validation)
-
- Go to /user/profile, click Edit
- Try uploading a file that’s too large — toast: “File size must be less than X MB”
- Try uploading a .txt file — toast: “File format must be one of: …”
- Try a very small image (e.g. 1x1 px) — toast: “Image dimensions must be at least …”
Quick checklist
┌────────────────┬─────────────────────────────────────────────┬────────────────────────────────┐ │ Mechanism │ Trigger │ Where to look │ ├────────────────┼─────────────────────────────────────────────┼────────────────────────────────┤ │ toast_response │ Any HTMX error (login, register, │ Bottom-right toast │ │ │ validation) │ │ ├────────────────┼─────────────────────────────────────────────┼────────────────────────────────┤ │ append_toast │ Any HTMX success mutation (profile, roles, │ Bottom-right toast alongside │ │ │ members, invitations) │ updated partial │ ├────────────────┼─────────────────────────────────────────────┼────────────────────────────────┤ │ Flash cookie │ PRG redirects (email confirm, forgot │ Bottom-right toast after page │ │ │ password, org update/delete) │ load │ ├────────────────┼─────────────────────────────────────────────┼────────────────────────────────┤ │ showToast() JS │ Avatar file picker validation │ Bottom-right toast, no network │ │ │ │ request │ └────────────────┴─────────────────────────────────────────────┴────────────────────────────────┘
v0.1.3
2026-03-12 · GitHub
Summary
- Set
follow_redirects=Falseon allTestClientinstances inconftest.pyinstead of passing it per API call - Removed ~90 redundant
follow_redirects=Falsearguments from individual test calls - Added redirect location assertions (
response.headers["location"]) to all tests that check 3xx status codes but previously didn’t verify the redirect target - Fixed
InsecureKeyLengthWarningby using a testSECRET_KEYlonger than 32 bytes
Closes #101
Test plan
🤖 Generated with Claude Code
v0.1.2
2026-03-12 · GitHub
Summary
- Add Hetzner Cloud deployment documentation to deployment.qmd with instructions for provisioning, DNS setup, configuration, and management
- Add callout note explaining that deployment artifacts live on per-target branches (
modal,hetzner) - Add
DOMAINenv var to.env.examplefor Caddy TLS configuration - Install
hcloudCLI in devcontainer setup
Closes #151
🤖 Generated with Claude Code
v0.1.1
2026-03-11 · GitHub
Summary
- Adds a new
.github/workflows/release.ymlthat runs on pushes tomain - Automatically bumps the patch version in
pyproject.toml, syncsuv.lock, creates a GitHub release with PR body as release notes, and commits the version bump back tomain - Uses
[skip ci]in the version bump commit to prevent infinite workflow loops
Closes #111
Test plan
🤖 Generated with Claude Code