feat: DEFAULT_TOPICS_SEED + ensure_topics_seeded
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -12,6 +12,90 @@ import random
|
||||
from collections import Counter, defaultdict
|
||||
from pathlib import Path
|
||||
|
||||
DEFAULT_TOPICS_SEED = [
|
||||
{
|
||||
"id": "T1",
|
||||
"title": "내 인생 시간 도둑 처단기",
|
||||
"tagline": "매일 짜증나는 반복 작업 하나를 2시간 안에 박살내기.",
|
||||
"tone": "실용 + 살짝 치트키",
|
||||
"items": [
|
||||
"Slack 멘션 자동 분류/요약기 — '진짜 날 부른 거' vs 'FYI' 분리",
|
||||
"Jira 티켓 1줄 자동 요약 + 다음 액션 제안기",
|
||||
"회의 캘린더 → 하루 시작 브리핑 (\"오늘 3개 있고 2개는 안 가도 됨\")",
|
||||
"PR 리뷰 우선순위 큐 (크기/긴급도/차단여부 기반)",
|
||||
"반복 쿼리/kubectl 명령 매크로 CLI — 자주 치는 10개를 1글자로",
|
||||
"온콜 노이즈 필터 — 진짜 볼 알람 vs 무시해도 되는 알람",
|
||||
"\"이번 주 내 활동 자동 요약\" — PR/티켓/리뷰 통합 리포트",
|
||||
"Grafana 자주 보는 패널 즐겨찾기 통합 뷰",
|
||||
"Slack 스레드 장문 요약기 — 놓친 채널 따라잡기용",
|
||||
"\"이 회의 들어가야 함?\" 분류기 — 캘린더 제목·참석자 기반 추천",
|
||||
],
|
||||
},
|
||||
{
|
||||
"id": "T2",
|
||||
"title": "벼르던 사이드 프로젝트",
|
||||
"tagline": "평소 \"저거 하나 만들고 싶은데\" 하던 개인 토이를 2시간 안에 작은 완성품으로.",
|
||||
"tone": "몰입 + 작은 완결성",
|
||||
"items": [
|
||||
"내 PR/커밋 패턴 분석 개인 대시보드 (시간대/요일/사이즈 분포)",
|
||||
"팀 Wiki/Notion을 터미널에서 fzf 스타일로 검색하는 CLI",
|
||||
"사내 모델/데이터셋 메타데이터 검색 프로토타입",
|
||||
"git 히스토리 인터랙티브 시각화 뷰어",
|
||||
"\"오늘 내가 한 일\" 자동 일기 생성기 (커밋/PR/티켓 통합)",
|
||||
"PR 코멘트 감정/톤 분석으로 팀 리뷰 문화 리포트",
|
||||
"로컬 Kubernetes 리소스 관계 그래프 실시간 시각화",
|
||||
"사내 논문/테크 문서 RAG 검색 도구",
|
||||
"터미널에서 차트 포함된 마크다운 뷰어",
|
||||
"북마크/링크 자동 분류·태깅 개인 도구",
|
||||
],
|
||||
},
|
||||
{
|
||||
"id": "T3",
|
||||
"title": "오버엔지니어링 선수권",
|
||||
"tagline": "평소 안 써본 무거운 기술 패턴을 일부러 작은 문제에 적용해 배우기.",
|
||||
"tone": "학습형 오버엔지니어링",
|
||||
"items": [
|
||||
"Todo 앱에 이벤트 소싱 + CQRS 제대로 적용",
|
||||
"간단한 계산기 서비스에 OpenTelemetry 풀 트레이싱 구축",
|
||||
"문서 검색 기능에 벡터 DB + 하이브리드 검색 (BM25 + 임베딩)",
|
||||
"파일 업로드에 S3 presigned URL + 체크섬 검증 + 재시도 로직 정식 설계",
|
||||
"팀 투표 기능을 Raft 합의 알고리즘으로 구현",
|
||||
"회의실 예약을 Kafka 이벤트 스트리밍 기반으로",
|
||||
"로컬 개발 환경을 완전한 K8s 매니페스트 (Deployment/Service/Ingress/HPA)로 재현",
|
||||
"LLM + RAG 기반 PR 자동 리뷰 봇 아키텍처 설계·구현",
|
||||
"멀티 에이전트 협업(프롬프트 2~3단계)으로 간단한 의사결정 시스템",
|
||||
"사이드카 패턴으로 로깅/메트릭/인증 분리 데모",
|
||||
],
|
||||
},
|
||||
{
|
||||
"id": "T4",
|
||||
"title": "팀에게 주는 작은 선물",
|
||||
"tagline": "동료를 돕는 도구/봇/사이트. 특정인을 놀리는 게 아니라 팀 전체를 위한 것.",
|
||||
"tone": "실질적 도움 + 가벼운 온기",
|
||||
"items": [
|
||||
"배포 상태 집계·알림 봇 (성공/실패/롤백 요약)",
|
||||
"신입 한 주 서바이벌 가이드 자동 생성기 (온보딩 링크/문서 수집)",
|
||||
"팀 내부 용어/약어 사전 봇 — 신입/리서처 친화",
|
||||
"아침 브리핑 봇 — 오늘 회의/배포/만료 알람 한방",
|
||||
"점심 투표 1분 컷 봇 — 선택지 자동 생성 후 이모지 투표",
|
||||
"팀 반복 질문 FAQ 봇 — 같은 질문 반복되는 채널용",
|
||||
"온콜 교대 시 인수인계 자동 요약 생성기",
|
||||
"회의실 스마트 추천 — 인원/시간대/위치 기반",
|
||||
"사내 서비스 변경사항 요약 구독 봇",
|
||||
"\"이번 주 팀 지표 한 장\" 리포트 — 머지 PR, 해결 티켓, 배포 수",
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def ensure_topics_seeded(data):
|
||||
"""topics 비어있으면 default 시드. 기존 있으면 보존."""
|
||||
cats = data.get("topics", {}).get("categories", [])
|
||||
if not cats:
|
||||
data.setdefault("topics", {})
|
||||
data["topics"]["categories"] = DEFAULT_TOPICS_SEED
|
||||
|
||||
|
||||
# 시니어 명단 (Platform/Data/HPC/System만 알고 있음)
|
||||
SENIORS = {
|
||||
"한지승", "손현준", "강승형", "변수민", # Platform/Data
|
||||
@@ -271,6 +355,7 @@ def main():
|
||||
"votes": [],
|
||||
}
|
||||
data["people"] = people_records
|
||||
ensure_topics_seeded(data) # 신규
|
||||
# 누락 키 보강
|
||||
for k, v in [
|
||||
("settings", {"voting_open": True}),
|
||||
|
||||
22
tests/e2e.py
22
tests/e2e.py
@@ -278,6 +278,27 @@ def t_topics_helpers():
|
||||
assert get_topics() == sample2
|
||||
|
||||
|
||||
def t_topics_seeded_after_assign():
|
||||
from app import get_topics, _empty_state, save_data, load_data
|
||||
# 빈 상태로 reset
|
||||
save_data(_empty_state())
|
||||
assert get_topics() == []
|
||||
|
||||
from assign_teams import ensure_topics_seeded
|
||||
data = load_data()
|
||||
ensure_topics_seeded(data)
|
||||
save_data(data)
|
||||
|
||||
cats = get_topics()
|
||||
assert len(cats) == 4
|
||||
for c in cats:
|
||||
assert len(c["items"]) == 10
|
||||
assert c["id"] in ("T1", "T2", "T3", "T4")
|
||||
assert c["title"]
|
||||
assert c["tagline"]
|
||||
assert c["tone"]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(f"# E2E (data={TEST_DATA})\n")
|
||||
test("hackathon.json 로드 (34명, 7팀)", t_load)
|
||||
@@ -296,6 +317,7 @@ if __name__ == "__main__":
|
||||
test("load_data nested 키 backfill", t_load_data_backfills_nested_settings)
|
||||
test("stage 헬퍼", t_stage_helpers)
|
||||
test("topics 헬퍼", t_topics_helpers)
|
||||
test("topics 시드", t_topics_seeded_after_assign)
|
||||
|
||||
fails = sum(1 for r, _ in results if r == FAIL)
|
||||
print(f"\n# {len(results)} 중 통과 {len(results) - fails}, 실패 {fails}")
|
||||
|
||||
Reference in New Issue
Block a user