diff --git a/app/modules/project/router.py b/app/modules/project/router.py
index 8a1b589..091c1c2 100644
--- a/app/modules/project/router.py
+++ b/app/modules/project/router.py
@@ -441,6 +441,14 @@ async def project_page(request: Request, project_id: int) -> HTMLResponse:
board_stage_names.append(s["name"])
board_stage_names.sort(key=lambda n: (_order.get(n, 999), n))
+ # 아바타 맵: 이메일(소문자) → 구글 프로필 이미지 URL (담당자/댓글 작성자 표시용)
+ from app.main import user_store # noqa: WPS433
+ avatars = {
+ store.norm_str(u["email"], lower=True): u.get("picture") or ""
+ for u in user_store.list_all()
+ if u.get("picture")
+ }
+
# 달력(휴가식 월간 그리드) — ?y=&m= 로 월 이동, 기본 이번 달
today = today_kst()
try:
@@ -472,6 +480,7 @@ async def project_page(request: Request, project_id: int) -> HTMLResponse:
"projects_meta": projects_meta,
"stages_by_project": stages_by_project,
"board_stage_names": board_stage_names,
+ "avatars": avatars,
"priority_labels": store.PRIORITY_LABELS,
"color_palette": list(store.COLOR_PALETTE),
"today": today.isoformat(),
diff --git a/app/modules/project/templates/project/index.html b/app/modules/project/templates/project/index.html
index b564646..b46e6ad 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 %}
@@ -167,5 +167,5 @@
-
+
{% endblock %}
diff --git a/app/modules/project/templates/project/project.html b/app/modules/project/templates/project/project.html
index 0a6f638..e517a00 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 %}
-
+
@@ -285,10 +285,11 @@
"priorityLabels": {{ priority_labels | tojson }},
"projects": {{ projects_meta | tojson }},
"stagesByProject": {{ stages_by_project | tojson }},
- "boardStages": {{ board_stage_names | tojson }}
+ "boardStages": {{ board_stage_names | tojson }},
+ "avatars": {{ avatars | tojson }}
}
-
+
{% endblock %}
diff --git a/app/static/project.css b/app/static/project.css
index 9c16078..25a4940 100644
--- a/app/static/project.css
+++ b/app/static/project.css
@@ -108,7 +108,10 @@
.material-symbols-outlined { font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24; line-height: 1; vertical-align: middle; }
.pj-gicon { font-size: 24px; color: #5f6368; flex: 0 0 auto; }
.pj-gicon-sm { font-size: 20px; }
-.pj-assignee { display: inline-flex; align-items: center; gap: 3px; font-size: 12px; color: #5f6368; }
+.pj-assignee { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; color: #5f6368; }
+/* 구글 프로필 이미지 — 원형 */
+.pj-avatar { width: 22px; height: 22px; border-radius: 50%; object-fit: cover; flex: 0 0 auto; vertical-align: middle; background: #e7e9ec; }
+.pj-avatar.pj-gicon-sm { width: 18px; height: 18px; }
/* ── 툴바 + 탭 ── */
.pj-toolbar { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; }
diff --git a/app/static/project.js b/app/static/project.js
index f9594bf..e5ed5d1 100644
--- a/app/static/project.js
+++ b/app/static/project.js
@@ -193,6 +193,14 @@
const projectsMeta = data.projects || [];
const stagesByProject = data.stagesByProject || {};
const boardStages = data.boardStages || [];
+ const avatars = data.avatars || {};
+ // 담당자/작성자 아이콘 = 구글 프로필 이미지(원형). 없으면 기본 아이콘.
+ function avatarHtml(email, cls) {
+ const url = email ? avatars[String(email).toLowerCase()] : "";
+ const c = cls || "";
+ if (url) return '';
+ return 'account_circle';
+ }
let timeline = null;
let currentView = "calendar";
@@ -620,7 +628,7 @@
? '' + (priorityLabels[t.priority] || t.priority) + ""
: "") +
(t.assignee_email
- ? 'account_circle' +
+ ? '' + avatarHtml(t.assignee_email, "pj-gicon-sm") +
escapeHtml(idOf(t.assignee_email)) + ""
: "") +
(t.due_date ? '' + t.due_date + "" : "") +
@@ -738,6 +746,9 @@
tr.innerHTML = LIST_COLS.map(function (c) {
let inner = escapeHtml(String(c.text(t)));
if (c.key === "title") inner += cmtBadge(t);
+ if (c.key === "assignee" && t.assignee_email) {
+ inner = '' + avatarHtml(t.assignee_email, "pj-gicon-sm") + escapeHtml(idOf(t.assignee_email)) + "";
+ }
return "