diff --git a/app/modules/expense/db.py b/app/modules/expense/db.py index d83433e..f1f4424 100644 --- a/app/modules/expense/db.py +++ b/app/modules/expense/db.py @@ -20,27 +20,17 @@ from psycopg_pool import ConnectionPool from .store import CATEGORIES, METHODS, STATUSES -_DDL = """ -CREATE TABLE IF NOT EXISTS expense_items ( - id TEXT PRIMARY KEY, - owner TEXT NOT NULL, - spent_at DATE NOT NULL, - category TEXT NOT NULL, - method TEXT NOT NULL, - merchant TEXT NOT NULL DEFAULT '', - amount BIGINT NOT NULL DEFAULT 0 CHECK (amount >= 0), - memo TEXT NOT NULL DEFAULT '', - status TEXT NOT NULL DEFAULT '작성중', - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now() -); -CREATE INDEX IF NOT EXISTS idx_expense_owner_spent ON expense_items (owner, spent_at DESC); -CREATE INDEX IF NOT EXISTS idx_expense_status ON expense_items (status); -""" - class ExpenseDBStore: - """`ExpenseStore` 와 동일한 메서드 시그니처.""" + """`ExpenseStore` 와 동일한 메서드 시그니처. + + 스키마(테이블/인덱스/트리거)는 앱이 직접 만들지 않는다. + `scripts/sql/expense_db_init.sql` 과 `expense_db_002_*.sql` 을 통해 + superuser 가 사전 적용한다. 앱 계정(expense_app)은 SELECT/INSERT/UPDATE/DELETE + 권한만 받기 때문에 PostgreSQL 15+ 의 strict public-schema 정책과 충돌하지 않음. + + 연결 풀은 lazy open — 부팅 시점에 DB 가 잠시 끊겨도 컨테이너가 죽지 않게. + """ def __init__(self, dsn: str, *, min_size: int = 1, max_size: int = 5): self._pool = ConnectionPool( @@ -48,17 +38,13 @@ class ExpenseDBStore: min_size=min_size, max_size=max_size, kwargs={"row_factory": dict_row, "autocommit": True}, - open=True, + open=False, ) - self._ensure_schema() + self._pool.open(wait=False) def close(self) -> None: self._pool.close() - def _ensure_schema(self) -> None: - with self._pool.connection() as conn: - conn.execute(_DDL) - # ── 조회 ── def list_for(self, email: str) -> list[dict[str, Any]]: email = email.lower().strip()