feat(shared): cross-cutting plumbing and pure domain layer

Typed pydantic-settings config, structlog JSON logging with request/trace id
propagation and redaction of phone numbers, tokens and face keys, the unified
response envelope and error-code table from 架构文档 §9.2, async SQLAlchemy
session management, ORM models for the eight foundation tables, and the
OpenTelemetry/Prometheus wiring.

packages/domain stays pure logic -- snowflake ids, the quota three-phase
protocol and the tk_task state machine -- so it can be tested without a
database and is held to mypy strict.
This commit is contained in:
xsl
2026-08-14 00:26:39 +08:00
parent da0314fd08
commit 12583e9739
24 changed files with 1717 additions and 0 deletions
+76
View File
@@ -0,0 +1,76 @@
"""JWT access tokens (架构文档 §9.1: Bearer JWT, 15 分钟).
The revocable refresh-token half (`id_session`) is FR-ACC-05 and is deliberately
NOT implemented in this scaffold — see packages/identity/README.md.
"""
from __future__ import annotations
import time
from dataclasses import dataclass
from typing import Any
import jwt
from packages.shared.errors import AppError, ErrorCode
@dataclass(frozen=True, slots=True)
class AccessTokenClaims:
user_id: int
issued_at: int
expires_at: int
issuer: str
def create_access_token(
*,
user_id: int,
secret: str,
algorithm: str = "HS256",
ttl_seconds: int = 900,
issuer: str = "meida",
now: int | None = None,
) -> str:
issued_at = int(now if now is not None else time.time())
payload: dict[str, Any] = {
"sub": str(user_id),
"iat": issued_at,
"exp": issued_at + ttl_seconds,
"iss": issuer,
"typ": "access",
}
return jwt.encode(payload, secret, algorithm=algorithm)
def decode_access_token(
token: str,
*,
secret: str,
algorithm: str = "HS256",
issuer: str = "meida",
) -> AccessTokenClaims:
try:
payload = jwt.decode(
token,
secret,
algorithms=[algorithm],
issuer=issuer,
options={"require": ["exp", "iat", "sub"]},
)
except jwt.ExpiredSignatureError as exc:
raise AppError(ErrorCode.TOKEN_EXPIRED) from exc
except jwt.InvalidTokenError as exc:
raise AppError(ErrorCode.TOKEN_INVALID) from exc
try:
user_id = int(payload["sub"])
except (KeyError, TypeError, ValueError) as exc:
raise AppError(ErrorCode.TOKEN_INVALID) from exc
return AccessTokenClaims(
user_id=user_id,
issued_at=int(payload["iat"]),
expires_at=int(payload["exp"]),
issuer=str(payload.get("iss", issuer)),
)