feat(perf+security): per-request backend cache, DB indexes, CSRF, pro… - #27
Merged
Merged
Conversation
…d-secret checks
## Perf — per-request backend waste
- AuthMiddleware caches resolved UserContext in the signed session cookie;
subsequent requests skip the SELECT User + selectinload(roles) round-trip.
Trade-off: role / disable changes apply on the affected user's next login.
- InertiaLayoutDataMiddleware omits i18n.messages on Inertia XHR visits unless
the session-tracked last locale differs; full page loads still ship the
dict. Frontend i18n.ts guards updateI18n on messages presence.
- MenuRegistry memoizes the sorted items list; invalidated on add/add_many.
- UsersModule.on_startup warms a RoleSummary cache on app.state; admin views
read from the cache (with async lazy fallback) instead of re-querying
users_role per render.
- I18nRegistry.messages() returns a MappingProxyType view — no per-call dict
copy; Translator._lookup uses it directly.
## Perf — DB schema
- New migration b7e1af4c9d02 adds:
* ix_users_user_email_lower — functional index on lower(email) so fastapi-
users get_by_email stops seq-scanning on Postgres
* ix_users_access_token_user_id, ix_users_user_role_role_id — FK indexes
(Postgres does not auto-index FKs)
* ix_products_product_is_deleted — supports soft-delete filtering
* drops ix_products_product_is_active — low-cardinality boolean costs
writes without helping the planner
- All create/drop wrapped in autocommit_block with postgresql_concurrently
and if_not_exists / if_exists for re-runnable zero-downtime deploys.
- ProductService.get_all now filters is_deleted=False — fixes a correctness
bug where soft-deleted + still-active rows leaked into public listings.
- DB engine gets pool_size / max_overflow / pool_pre_ping / pool_recycle
knobs driven by new SM_DB_POOL_* settings (Postgres only; SQLite ignores).
## Security — CSRF + hardening
- New CSRFMiddleware validates an X-CSRF-Token header against a session-
scoped token for every unsafe (POST/PUT/PATCH/DELETE) request. Token is
minted once per session and exposed via Inertia shared props; frontend
packages/ui/src/lib/csrf.ts stores it and fetchWithCsrf echoes it back.
- SecurityHeadersMiddleware gains configurable CSP and HSTS (pass None to
suppress in dev / non-TLS loopbacks).
- Settings rejects the placeholder SM_SECRET_KEY in production environments
(new framework/core/simple_module_core/environments.py defines the
non-prod allowlist).
- Dev-only seeded credentials on the login page are now gated on both
is_development AND the bootstrap env vars being set.
## Tooling
- rollup-plugin-visualizer (dev dep) gated behind ANALYZE=1 npm run build;
writes host/static/dist/stats.html.
- pytest addopts gets --durations=20 so the slowest tests surface on every
run without a flag.
## Tests / support
- framework/testing/simple_module_testing/session_cookie.py — shared helper
for forging signed session cookies; used by integration + users tests.
- New framework/hosting/tests/test_csrf_middleware.py and
test_settings_secrets.py cover the security additions.
- Existing suite (558 Python + 8 JS tests) updated where needed and all
passing. ty + ruff + biome + tsc clean.
- framework/hosting/simple_module_hosting/_observability.py — extracted
CorrelationIdMiddleware + RequestLoggingMiddleware. middleware.py keeps
security / tenant / Inertia-layout concerns; re-exports the observability
middlewares for back-compat.
- modules/users/users/endpoints/api_admin.py — split the 6 admin REST
endpoints into their own router with the RequiresPermission("users.manage")
dep applied once at the APIRouter level instead of per-route. api.py
mounts it via include_router.
No behavior change. ci-check-file-size now passes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
…d-secret checks
Perf — per-request backend waste
Perf — DB schema
Security — CSRF + hardening
Tooling
Tests / support