diff --git a/app/modules/project/db.py b/app/modules/project/db.py index 86a5e6f..89ceebf 100644 --- a/app/modules/project/db.py +++ b/app/modules/project/db.py @@ -238,11 +238,13 @@ class ProjectStore: return [self._serialize(r) for r in rows] def add_stage( - self, *, project_id: int, name: str, is_done_stage: bool = False, created_by: str = "" + self, *, project_id: int, name: str, is_done_stage: bool = False, + color: str | None = None, created_by: str = "", ) -> dict[str, Any]: nm = store.norm_str(name) if not nm: raise ValueError("세션 이름은 필수입니다.") + col = store.validate_stage_color(color) with self._pool.connection() as conn: nxt = conn.execute( "SELECT COALESCE(MAX(sort_order), -1) + 1 AS n " @@ -250,9 +252,9 @@ class ProjectStore: (project_id,), ).fetchone() row = conn.execute( - "INSERT INTO project_stages (project_id, name, sort_order, is_done_stage, created_by) " - "VALUES (%s,%s,%s,%s,%s) RETURNING *", - (project_id, nm, int(nxt["n"]), bool(is_done_stage), + "INSERT INTO project_stages (project_id, name, sort_order, is_done_stage, color, created_by) " + "VALUES (%s,%s,%s,%s,%s,%s) RETURNING *", + (project_id, nm, int(nxt["n"]), bool(is_done_stage), col, store.norm_str(created_by, lower=True)), ).fetchone() return self._serialize(row) @@ -776,8 +778,10 @@ class ProjectStore: # ════════════════════════════════════════════════════════════ def update_stage( self, *, stage_id: int, name: str | None = None, - is_done_stage: bool | None = None, + is_done_stage: bool | None = None, color: Any = ..., ) -> dict[str, Any]: + """color 는 지정 안 함(기본 `...`)과 명시적으로 지우기(`None`)를 + 구분해야 해서 다른 필드처럼 `is None` 이 아니라 `is not ...` 로 검사한다.""" sets: list[str] = [] params: list[Any] = [] if name is not None: @@ -789,6 +793,9 @@ class ProjectStore: if is_done_stage is not None: sets.append("is_done_stage = %s") params.append(bool(is_done_stage)) + if color is not ...: + sets.append("color = %s") + params.append(store.validate_stage_color(color)) if not sets: raise ValueError("변경할 내용이 없습니다.") params.append(stage_id) diff --git a/app/modules/project/router.py b/app/modules/project/router.py index a61e379..6aa6667 100644 --- a/app/modules/project/router.py +++ b/app/modules/project/router.py @@ -618,6 +618,7 @@ async def project_page(request: Request, project_id: int) -> HTMLResponse: "avatars": avatars, "priority_labels": store.PRIORITY_LABELS, "color_palette": list(store.COLOR_PALETTE), + "stage_color_palette": list(store.STAGE_COLOR_PALETTE), "today": today.isoformat(), "year": year, "month": month, @@ -865,6 +866,7 @@ async def api_add_stage( project_id=project_id, name=payload.get("name", ""), is_done_stage=bool(payload.get("is_done_stage", False)), + color=payload.get("color"), created_by=user["email"], ) except ValueError as exc: @@ -1362,6 +1364,7 @@ async def api_update_stage( stage_id=stage_id, name=payload.get("name"), is_done_stage=payload.get("is_done_stage"), + color=payload.get("color", ...), ) except ValueError as exc: raise HTTPException(status_code=400, detail=str(exc)) diff --git a/app/modules/project/store.py b/app/modules/project/store.py index e46ddc8..b9570fc 100644 --- a/app/modules/project/store.py +++ b/app/modules/project/store.py @@ -49,6 +49,21 @@ COLOR_PALETTE: tuple[str, ...] = ( "#5a6772", # slate ) +# 세션(칸반 컬럼) 색상 팔레트 — 아사나 태그/커스텀필드에서 쓰는 10색. +# 세션 생성/편집 팝업의 색상표가 이 순서 그대로 노출된다. +STAGE_COLOR_PALETTE: tuple[str, ...] = ( + "#4573d2", # blue + "#37a3a3", # teal + "#62a420", # green + "#e8a33d", # amber + "#e8384f", # red + "#aa62e3", # purple + "#f06a6a", # coral + "#5a6772", # slate + "#e8398a", # pink + "#a15c43", # brown +) + # ════════════════════════════════════════════════════════════ # 대한민국 국경일·공휴일(2026~2030) — 프로젝트 달력 표시 전용. # @@ -181,6 +196,12 @@ def validate_color(color: Any) -> str: return COLOR_PALETTE[0] +def validate_stage_color(color: Any) -> str | None: + """세션 색상 — 팔레트 밖 값/빈값은 저장 안 함(NULL, 기본 회색 표시).""" + v = norm_str(color).lower() + return v if v in STAGE_COLOR_PALETTE else None + + def validate_date(d: Any) -> str | None: """'YYYY-MM-DD' 형식만 통과. 빈값은 None.""" from datetime import date as _date # noqa: WPS433 diff --git a/app/modules/project/templates/project/inbox.html b/app/modules/project/templates/project/inbox.html index 5067a6a..f85bfe9 100644 --- a/app/modules/project/templates/project/inbox.html +++ b/app/modules/project/templates/project/inbox.html @@ -1,7 +1,7 @@ {% extends "erp_base.html" %} {% block head_extra %} - + {% endblock %} @@ -45,5 +45,5 @@ {% endif %} - + {% endblock %} diff --git a/app/modules/project/templates/project/index.html b/app/modules/project/templates/project/index.html index 2ebe9d5..0e75246 100644 --- a/app/modules/project/templates/project/index.html +++ b/app/modules/project/templates/project/index.html @@ -1,7 +1,7 @@ {% extends "erp_base.html" %} {% block head_extra %} - + {% endblock %} @@ -393,5 +393,5 @@ - + {% endblock %} diff --git a/app/modules/project/templates/project/project.html b/app/modules/project/templates/project/project.html index cdcb5a6..5beed52 100644 --- a/app/modules/project/templates/project/project.html +++ b/app/modules/project/templates/project/project.html @@ -1,7 +1,7 @@ {% extends "erp_base.html" %} {% block head_extra %} - + @@ -290,6 +290,23 @@ + + +