docs: add YAML configuration implementation plan

Add detailed step-by-step implementation plan for migrating
from .env to YAML configuration using pydantic-yaml.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Misaka_Company
2026-05-12 09:26:26 +08:00
parent 01423ccccc
commit 71d261af26

View File

@@ -0,0 +1,511 @@
# YAML Configuration Implementation Plan
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** Migrate FastAPI configuration from .env to YAML using pydantic-yaml
**Architecture:** Create new `config/` module with YAML-based settings using `pydantic-yaml`, preserving type validation and improving readability through nested configuration structure.
**Tech Stack:** pydantic-yaml, pyyaml, pytest
---
## Task 1: Add pydantic-yaml Dependency
**Files:**
- Modify: `requirements.txt`
**Step 1: Add pydantic-yaml to requirements.txt**
Add this line to `requirements.txt`:
```txt
pydantic-yaml>=0.12.0
```
**Step 2: Install the dependency**
Run: `.venv/Scripts/pip install pydantic-yaml`
Expected: Successfully installs pydantic-yaml and its dependencies
**Step 3: Verify installation**
Run: `.venv/Scripts/python -c "import pydantic_yaml; print(pydantic_yaml.__version__)"`
Expected: Prints version number without errors
**Step 4: Commit**
```bash
git add requirements.txt
git commit -m "deps: add pydantic-yaml for YAML configuration support"
```
---
## Task 2: Create config Directory Structure
**Files:**
- Create: `config/__init__.py`
- Create: `config/settings.py`
- Create: `config/settings.yaml`
**Step 1: Create config directory**
Run: `mkdir config`
**Step 2: Create config/__init__.py**
```python
from config.settings import settings, Settings, load_settings
__all__ = ["settings", "Settings", "load_settings"]
```
**Step 3: Create config/settings.py with configuration classes**
```python
from pathlib import Path
from sqlalchemy.engine import URL
from pydantic import BaseModel
from pydantic_yaml import YamlModel
class SqlServerConfig(BaseModel):
"""SQL Server 连接配置"""
host: str
port: int = 1433
database: str
username: str
password: str
driver: str = "{ODBC Driver 18 for SQL Server}"
trust_server_certificate: str = "yes"
class Settings(YamlModel):
"""应用配置"""
database: SqlServerConfig
@property
def database_url(self) -> URL:
"""构建数据库连接 URL"""
conf = self.database.sql_server
return URL.create(
"mssql+pyodbc",
username=conf.username,
password=conf.password,
host=conf.host,
port=conf.port,
database=conf.database,
query={
"driver": conf.driver.strip("{}"),
"TrustServerCertificate": conf.trust_server_certificate,
},
)
def load_settings(config_path: str = "config/settings.yaml") -> Settings:
"""加载 YAML 配置文件"""
path = Path(config_path)
if not path.exists():
raise FileNotFoundError(
f"配置文件不存在: {config_path}\n"
f"请确保文件存在于项目根目录或指定正确路径"
)
return Settings.parse_yaml_file(path)
# 全局配置单例
settings = load_settings()
```
**Step 4: Create config/settings.yaml with current configuration**
```yaml
# 数据库配置
database:
sql_server:
host: 192.168.110.114
port: 1433
database: CompanyDB
username: peng
password: Cqbld123456.
driver: "{ODBC Driver 18 for SQL Server}"
trust_server_certificate: yes
```
**Step 5: Commit**
```bash
git add config/
git commit -m "feat: add YAML configuration module with pydantic-yaml"
```
---
## Task 3: Write Configuration Loading Tests
**Files:**
- Create: `tests/test_config.py`
- Create: `tests/fixtures/test_config.yaml`
**Step 1: Create tests/fixtures directory**
Run: `mkdir tests/fixtures`
**Step 2: Create tests/fixtures/test_config.yaml**
```yaml
# 测试配置
database:
sql_server:
host: localhost
port: 1433
database: TestDB
username: test_user
password: test_pass
driver: "{ODBC Driver 18 for SQL Server}"
trust_server_certificate: yes
```
**Step 3: Write the failing test for settings loading**
Create `tests/test_config.py`:
```python
import pytest
from config.settings import load_settings
def test_load_settings_success():
"""测试成功加载配置文件"""
settings = load_settings("tests/fixtures/test_config.yaml")
assert settings.database.sql_server.port == 1433
assert settings.database.sql_server.host == "localhost"
assert settings.database.sql_server.database == "TestDB"
def test_load_settings_file_not_found():
"""测试配置文件不存在时抛出异常"""
with pytest.raises(FileNotFoundError):
load_settings("nonexistent.yaml")
def test_database_url_property():
"""测试 database_url 属性生成"""
settings = load_settings("tests/fixtures/test_config.yaml")
url = settings.database_url
assert "mssql+pyodbc" in str(url)
assert "test_user" in str(url)
assert "TestDB" in str(url)
```
**Step 4: Run tests to verify they pass**
Run: `.venv/Scripts/pytest tests/test_config.py -v`
Expected: All tests PASS
**Step 5: Commit**
```bash
git add tests/test_config.py tests/fixtures/test_config.yaml
git commit -m "test: add configuration loading tests"
```
---
## Task 4: Update database.py to Use New Config
**Files:**
- Modify: `app/core/database.py`
**Step 1: Read current database.py to understand usage**
Check the current import and usage of settings
**Step 2: Update import statement**
Change:
```python
from app.core.config import settings
```
To:
```python
from config.settings import settings
```
**Step 3: Verify the rest of the code works unchanged**
The database_url property should work exactly as before
**Step 4: Run existing tests to ensure no breakage**
Run: `.venv/Scripts/pytest tests/ -v`
Expected: All existing tests still PASS
**Step 5: Commit**
```bash
git add app/core/database.py
git commit -m "refactor: update database.py to use new config module"
```
---
## Task 5: Update API Module Imports
**Files:**
- Modify: `app/api/v1/box.py`
- Modify: `app/api/v1/location.py`
- Modify: `app/services/box_service.py`
- Modify: `app/services/location_service.py`
**Step 1: Check all files that import from app.core.config**
Run: `grep -r "from app.core.config import" app/`
**Step 2: Update each file's import**
Change:
```python
from app.core.config import settings
```
To:
```python
from config.settings import settings
```
**Step 3: Run tests after each file change**
Run: `.venv/Scripts/pytest tests/ -v`
Expected: All tests PASS
**Step 4: Commit all import changes**
```bash
git add app/api/v1/box.py app/api/v1/location.py app/services/
git commit -m "refactor: update all imports to use new config module"
```
---
## Task 6: Update Test Fixtures
**Files:**
- Modify: `tests/conftest.py`
**Step 1: Read current conftest.py**
Check for any references to app.core.config
**Step 2: Update imports in conftest.py**
Change any:
```python
from app.core.config import settings
```
To:
```python
from config.settings import settings
```
**Step 3: Run tests**
Run: `.venv/Scripts/pytest tests/ -v`
Expected: All tests PASS
**Step 4: Commit**
```bash
git add tests/conftest.py
git commit -m "test: update conftest imports"
```
---
## Task 7: Update Main Application Entry Point
**Files:**
- Modify: `app/main.py`
**Step 1: Read current main.py**
Check for any config-related initialization
**Step 2: Add error handling for configuration loading**
Add at the top of main.py or update existing initialization:
```python
import sys
from config.settings import load_settings
try:
settings = load_settings()
except FileNotFoundError as e:
print(f"配置文件错误: {e}")
sys.exit(1)
except Exception as e:
print(f"加载配置失败: {e}")
sys.exit(1)
```
**Step 3: Test application startup**
Run: `.venv/Scripts/python -m app.main`
Expected: Application starts without errors
**Step 4: Commit**
```bash
git add app/main.py
git commit -m "feat: add config error handling on startup"
```
---
## Task 8: Remove Old Configuration Files
**Files:**
- Delete: `app/core/config.py`
- Delete: `.env`
**Step 1: Verify no remaining imports of old config**
Run: `grep -r "from app.core.config import" .`
Expected: No results (or only in .git directory)
**Step 2: Remove old config.py file**
Run: `rm app/core/config.py`
**Step 3: Remove .env file**
Run: `rm .env`
**Step 4: Add .env to .gitignore if not already present**
Ensure `.env` is in `.gitignore`
**Step 5: Run final test suite**
Run: `.venv/Scripts/pytest tests/ -v`
Expected: All tests PASS
**Step 6: Run application to verify**
Run: `.venv/Scripts/python -m app.main`
Expected: Application starts successfully
**Step 7: Commit cleanup**
```bash
git add app/core/config.py .env .gitignore
git commit -m "refactor: remove old .env and config.py files"
```
---
## Task 9: Update .gitignore for YAML Config
**Files:**
- Modify: `.gitignore` (if it exists, otherwise create)
**Step 1: Check if .gitignore exists**
Run: `ls -la .gitignore`
**Step 2: Add or verify config/settings.local.yaml is ignored**
Add to `.gitignore`:
```gitignore
# Local configuration overrides
config/settings.local.yaml
```
This allows developers to have local overrides without committing them
**Step 3: Commit**
```bash
git add .gitignore
git commit -m "chore: ignore local YAML config overrides"
```
---
## Task 10: Final Verification and Documentation
**Files:**
- Update: `README.md` (if exists)
**Step 1: Run complete test suite**
Run: `.venv/Scripts/pytest tests/ -v --cov=app --cov-report=term-missing`
Expected: All tests pass, coverage maintained
**Step 2: Start application and verify database connection**
Run: `.venv/Scripts/python -m app.main`
Expected: Application connects to database successfully
**Step 3: Update README.md with configuration instructions**
Add to README.md:
```markdown
## Configuration
Configuration is managed via YAML files in the `config/` directory.
### Configuration File
Edit `config/settings.yaml` to configure your environment:
```yaml
database:
sql_server:
host: your-host
port: 1433
database: your-database
username: your-username
password: your-password
```
### Local Overrides
For local development, create `config/settings.local.yaml` to override specific values without committing them.
```
**Step 4: Final commit**
```bash
git add README.md
git commit -m "docs: update README with YAML configuration instructions"
```
---
## Verification Checklist
After completing all tasks:
- [ ] All tests pass: `pytest tests/ -v`
- [ ] Application starts successfully
- [ ] Database connection works
- [ ] No references to `app.core.config` remain
- [ ] `.env` file removed
- [ ] YAML config file exists and is valid
- [ ] README updated with configuration instructions