feat: service scaffold, k8s test infra, health
FastAPI + SQLAlchemy async + Alembic scaffold, src-layout (mirrors the
sowai-fiscal lib's own convention), pyproject wired to sowai-fiscal@v0.1.0
via git+https (uv.lock pins the commit). Makefile mirrors auto/Makefile's
k8s-test workflow: syncs into /app/fiscal-svc in the SAME auto-tests pod,
against a dedicated fiscal_svc_test database on the shared Postgres
sidecar, serialized by the SAME lock file the auto uses on purpose so the
two repos' test runs never race in the pod. Dockerfile installs git (the
git+https dependency needs it at uv sync time) and splits the dependency
layer from the project's own editable install for build caching.
GET /v1/health -> {"status": "ok"}, verified green via `make k8s-test`.
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
"""Ported from `auto/backend/app/core/config.py` (Task 1). Same shape:
|
||||
`pydantic-settings` reading `.env` + env vars, `extra="ignore"` so a
|
||||
product-specific env var set alongside this service's own (e.g. in a
|
||||
shared k8s namespace) never trips validation.
|
||||
|
||||
Adaptation per the porte table (2026-07-17-fiscal-svc-f2-servico.md):
|
||||
this service has NO JWT auth of its own (`require_product` in Task 2
|
||||
reads a bcrypt-hashed API key straight from the `products` table, not a
|
||||
JWT keypair) -- so the `jwt_private_key_path`/`jwt_public_key_path`/
|
||||
`access_token_expire_minutes`/`refresh_token_expire_days` fields the
|
||||
auto's `Settings` carries have no equivalent here and are deliberately
|
||||
NOT ported. `FISCAL_CERT_ENCRYPTION_KEY` (Task 4's Fernet key for
|
||||
certificate ciphertext) is likewise read straight from `os.environ` at
|
||||
the point of use, never through this class -- same "secrets don't live
|
||||
in Settings" convention as the auto's own
|
||||
`FISCAL_CERT_ENCRYPTION_KEY`/`INTEGRACOES_ENCRYPTION_KEY` (see the auto's
|
||||
`app.core.config.Settings` module comment)."""
|
||||
|
||||
model_config = SettingsConfigDict(env_file=".env", extra="ignore")
|
||||
|
||||
app_name: str = "sowai-fiscal-svc"
|
||||
database_url: str = (
|
||||
"postgresql+asyncpg://postgres:postgres@localhost:5432/fiscal_svc_dev"
|
||||
)
|
||||
test_database_url: str = (
|
||||
"postgresql+asyncpg://postgres:postgres@localhost:5432/fiscal_svc_test"
|
||||
)
|
||||
|
||||
|
||||
settings = Settings()
|
||||
@@ -0,0 +1,19 @@
|
||||
from collections.abc import AsyncGenerator
|
||||
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
||||
from sqlalchemy.orm import DeclarativeBase
|
||||
|
||||
from fiscal_svc.core.config import settings
|
||||
|
||||
|
||||
class Base(DeclarativeBase):
|
||||
pass
|
||||
|
||||
|
||||
engine = create_async_engine(settings.database_url, echo=False)
|
||||
async_session_maker = async_sessionmaker(engine, expire_on_commit=False)
|
||||
|
||||
|
||||
async def get_session() -> AsyncGenerator[AsyncSession, None]:
|
||||
async with async_session_maker() as session:
|
||||
yield session
|
||||
@@ -0,0 +1,10 @@
|
||||
from fastapi import FastAPI
|
||||
|
||||
from fiscal_svc.core.config import settings
|
||||
|
||||
app = FastAPI(title=settings.app_name)
|
||||
|
||||
|
||||
@app.get("/v1/health")
|
||||
async def health_check() -> dict[str, str]:
|
||||
return {"status": "ok"}
|
||||
Reference in New Issue
Block a user