chore: lock runtime log output paths and ignore local logs
This commit is contained in:
@@ -285,8 +285,10 @@ infra/cloud/volcano/env/*.env
|
||||
*.swp
|
||||
.buildlog/
|
||||
.history
|
||||
/logs/
|
||||
# Docker volumes (local data)
|
||||
docker/supabase/volumes/db/data/
|
||||
infra/docker/volumes/db/data/
|
||||
|
||||
# OpenCode local config
|
||||
.opencode/
|
||||
|
||||
@@ -4,7 +4,7 @@ from pathlib import Path
|
||||
from typing import ClassVar, Literal
|
||||
from urllib.parse import quote
|
||||
|
||||
from pydantic import BaseModel, Field, computed_field
|
||||
from pydantic import BaseModel, Field, computed_field, field_validator
|
||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
|
||||
|
||||
@@ -37,6 +37,26 @@ class RuntimeSettings(BaseModel):
|
||||
)
|
||||
sql_log_queries: bool = False
|
||||
|
||||
@field_validator("log_dir", mode="before")
|
||||
@classmethod
|
||||
def lock_log_dir(cls, _: object) -> str:
|
||||
return "logs"
|
||||
|
||||
@field_validator("log_error_dir", mode="before")
|
||||
@classmethod
|
||||
def lock_log_error_dir(cls, _: object) -> str:
|
||||
return "logs/errors"
|
||||
|
||||
@field_validator("log_file_name", mode="before")
|
||||
@classmethod
|
||||
def lock_log_file_name(cls, _: object) -> str:
|
||||
return "app.log"
|
||||
|
||||
@field_validator("log_error_file_name", mode="before")
|
||||
@classmethod
|
||||
def lock_log_error_file_name(cls, _: object) -> str:
|
||||
return "error.log"
|
||||
|
||||
|
||||
class CelerySettings(BaseModel):
|
||||
broker_url: str | None = None
|
||||
|
||||
@@ -24,12 +24,16 @@ def test_runtime_settings_defaults() -> None:
|
||||
def test_runtime_settings_env_override(monkeypatch: MonkeyPatch) -> None:
|
||||
monkeypatch.setenv("SOCIAL_RUNTIME__LOG_DIR", "var/logs")
|
||||
monkeypatch.setenv("SOCIAL_RUNTIME__LOG_ERROR_DIR", "var/logs/errors")
|
||||
monkeypatch.setenv("SOCIAL_RUNTIME__LOG_FILE_NAME", "custom.log")
|
||||
monkeypatch.setenv("SOCIAL_RUNTIME__LOG_ERROR_FILE_NAME", "custom-error.log")
|
||||
monkeypatch.setenv("SOCIAL_RUNTIME__LOG_ROTATION", "size")
|
||||
monkeypatch.setenv("SOCIAL_RUNTIME__LOG_ROTATION_MAX_BYTES", "2048")
|
||||
|
||||
settings = Settings()
|
||||
|
||||
assert settings.runtime.log_dir == "var/logs"
|
||||
assert settings.runtime.log_error_dir == "var/logs/errors"
|
||||
assert settings.runtime.log_dir == "logs"
|
||||
assert settings.runtime.log_error_dir == "logs/errors"
|
||||
assert settings.runtime.log_file_name == "app.log"
|
||||
assert settings.runtime.log_error_file_name == "error.log"
|
||||
assert settings.runtime.log_rotation == "size"
|
||||
assert settings.runtime.log_rotation_max_bytes == 2048
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
# Auth Profile Enhancement Implementation Plan
|
||||
|
||||
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
||||
|
||||
**Goal:** 基于 Supabase 能力补齐注册/登录/按邮箱查用户/更新 profile 的一致化实现,并移除 profiles.display_name。
|
||||
|
||||
**Architecture:** 认证流程继续走 Supabase Auth(signup/login/refresh/logout),后端仅做薄封装与输入校验。profiles 通过 auth.users 触发器自动创建并绑定同一 id,profile 资料更新仍走业务接口。新增按邮箱查用户接口走 service_role 的 Admin API。
|
||||
|
||||
**Tech Stack:** FastAPI, Supabase Python SDK, SQLAlchemy, Alembic, PostgreSQL
|
||||
|
||||
---
|
||||
|
||||
### Task 1: 调整 profiles 数据模型与迁移
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/src/models/profile.py`
|
||||
- Create: `backend/alembic/versions/20260224_drop_profile_display_name_and_trigger_username.py`
|
||||
|
||||
**Step 1: Write the failing test**
|
||||
|
||||
- 新增迁移验证脚本测试:断言 `profiles` 不含 `display_name` 且触发器使用 metadata.username。
|
||||
|
||||
**Step 2: Run test to verify it fails**
|
||||
|
||||
Run: `PYTHONPATH=src uv run python -m pytest tests/integration -k profile_migration -q`
|
||||
Expected: FAIL(旧结构仍有 display_name 或触发器逻辑不匹配)
|
||||
|
||||
**Step 3: Write minimal implementation**
|
||||
|
||||
- model 删除 `display_name`
|
||||
- 迁移删除列并重建触发器函数:`profiles.username = NEW.raw_user_meta_data->>'username'`
|
||||
|
||||
**Step 4: Run test to verify it passes**
|
||||
|
||||
Run: `PYTHONPATH=src uv run python -m pytest tests/integration -k profile_migration -q`
|
||||
Expected: PASS
|
||||
|
||||
### Task 2: 注册接口改为 username+email+password
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/src/v1/auth/schemas.py`
|
||||
- Modify: `backend/src/v1/auth/service.py`
|
||||
|
||||
**Step 1: Write the failing test**
|
||||
|
||||
- 测试 signup 缺 username 返回 422
|
||||
- 测试 signup 将 `data.username` 传递给 Supabase gateway
|
||||
|
||||
**Step 2: Run test to verify it fails**
|
||||
|
||||
Run: `PYTHONPATH=src uv run python -m pytest tests/unit -k auth_signup -q`
|
||||
Expected: FAIL
|
||||
|
||||
**Step 3: Write minimal implementation**
|
||||
|
||||
- `SignupRequest` 添加必填 `username`
|
||||
- `SupabaseAuthGateway.signup` payload 增加 `data.username`
|
||||
|
||||
**Step 4: Run test to verify it passes**
|
||||
|
||||
Run: `PYTHONPATH=src uv run python -m pytest tests/unit -k auth_signup -q`
|
||||
Expected: PASS
|
||||
|
||||
### Task 3: 新增按邮箱查询 auth 用户接口
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/src/v1/auth/router.py`
|
||||
- Modify: `backend/src/v1/auth/service.py`
|
||||
- Modify: `backend/src/v1/auth/schemas.py`
|
||||
|
||||
**Step 1: Write the failing test**
|
||||
|
||||
- 测试 `GET /auth/users/by-email` 命中返回用户最小字段
|
||||
- 测试未命中返回 404
|
||||
|
||||
**Step 2: Run test to verify it fails**
|
||||
|
||||
Run: `PYTHONPATH=src uv run python -m pytest tests/unit -k auth_by_email -q`
|
||||
Expected: FAIL
|
||||
|
||||
**Step 3: Write minimal implementation**
|
||||
|
||||
- service 新增 `get_user_by_email`
|
||||
- gateway 用 service_role client 调用 Supabase Admin 查询
|
||||
- router 暴露 `GET /auth/users/by-email`
|
||||
|
||||
**Step 4: Run test to verify it passes**
|
||||
|
||||
Run: `PYTHONPATH=src uv run python -m pytest tests/unit -k auth_by_email -q`
|
||||
Expected: PASS
|
||||
|
||||
### Task 4: profile 更新协议去除 display_name
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/src/v1/profile/schemas.py`
|
||||
- Modify: `backend/src/v1/profile/service.py`
|
||||
- Modify: `backend/src/v1/profile/router.py`
|
||||
|
||||
**Step 1: Write the failing test**
|
||||
|
||||
- 测试 `PATCH /profile/me` 仅允许 `username/avatar_url/bio`
|
||||
|
||||
**Step 2: Run test to verify it fails**
|
||||
|
||||
Run: `PYTHONPATH=src uv run python -m pytest tests/unit -k profile_update -q`
|
||||
Expected: FAIL
|
||||
|
||||
**Step 3: Write minimal implementation**
|
||||
|
||||
- 移除 display_name 字段与映射
|
||||
- 保留原有更新路径和事务边界
|
||||
|
||||
**Step 4: Run test to verify it passes**
|
||||
|
||||
Run: `PYTHONPATH=src uv run python -m pytest tests/unit -k profile_update -q`
|
||||
Expected: PASS
|
||||
|
||||
### Task 5: 集成验证
|
||||
|
||||
**Files:**
|
||||
- Modify: `docs/runtime/runtime-runbook.md`
|
||||
|
||||
**Step 1: 运行关键验证**
|
||||
|
||||
Run: `docker compose --env-file .env -f infra/docker/docker-compose.yml --profile job run --rm init-job`
|
||||
Expected: 迁移成功
|
||||
|
||||
Run: `PYTHONPATH=src uv run python -m pytest tests -q`
|
||||
Expected: 全部通过
|
||||
|
||||
**Step 2: 手工 API 验证**
|
||||
|
||||
- signup(username,email,password) 成功
|
||||
- login(email,password) 成功
|
||||
- by-email 查询命中
|
||||
- patch profile 更新成功
|
||||
Reference in New Issue
Block a user