SLICE-2: identity — email + one-time-code sign-up, sessions, Landing/Sign-in (SD-0001 §7.2) #6

Merged
ben.stull merged 10 commits from slice-2-identity into main 2026-06-10 17:51:19 +00:00
Showing only changes of commit cfc28d7002 - Show all commits
+20
View File
@@ -8,6 +8,8 @@ storefronts domain (SLICE-3) replaces the _storefront_for seam.
"""
from __future__ import annotations
import logging
import sys
from contextlib import asynccontextmanager
from typing import Any
@@ -47,6 +49,23 @@ def _storefront_for(conn: psycopg.Connection, account: accounts.Account) -> dict
return None
def _ensure_app_logging() -> None:
"""Surface the app's own `ecomm.*` INFO logs on stderr (idempotent).
uvicorn configures only its own loggers, leaving the root with no INFO handler — so
without this the `ecomm.mailer` line (PUC-10's local dev channel: the one-time code in
the backend log) would be swallowed. A dedicated handler with propagate=False keeps it
out of uvicorn's stream and avoids double-logging.
"""
lg = logging.getLogger("ecomm")
if not lg.handlers:
handler = logging.StreamHandler(sys.stderr)
handler.setFormatter(logging.Formatter("%(levelname)s:%(name)s: %(message)s"))
lg.addHandler(handler)
lg.setLevel(logging.INFO)
lg.propagate = False
def _set_session_cookie(response: Response, account: accounts.Account) -> None:
token = session_mod.sign({"account_id": account.id, "email": account.email}, config.session_secret())
response.set_cookie(
@@ -60,6 +79,7 @@ def _set_session_cookie(response: Response, account: accounts.Account) -> None:
def create_app(database_url: str | None = None) -> FastAPI:
_ensure_app_logging()
dsn = database_url or config.database_url()
@asynccontextmanager