Sync kanban board tasks to EOB weekly worklogs. Reads completed/in-progress kanban cards, maps them to worklog projects, estimates hours from timestamps, aggregates by day, and submits via the EOB API.
Reads kanban board tasks and creates weekly worklog entries in the Engineering Operation Board (EOB). Tasks are aggregated by date + project + work type into one worklog card per group.
Each kanban project has a worklog_type:
| type | Behavior |
|---|---|
work | Maps to an EOB project; worklog created with project_id |
non-project | Worklog created without project_id (work type only) |
personal | Excluded from sync entirely |
Primary: Kanban DB project_settings table (via PUT /api/project-settings/:project)
Fallback: ~/.claude/worklog-sync.json → (only if the deployed API has not been updated yet)
project_map-- Kanban DB table (auto-created on connection)
CREATE TABLE IF NOT EXISTS project_settings (
project TEXT PRIMARY KEY,
worklog_type TEXT NOT NULL DEFAULT 'work',
eob_project_id TEXT,
eob_product_line_id TEXT,
default_work_type_code TEXT DEFAULT 'ENG-SW',
label TEXT
);
KANBAN_API="$BASE_URL" # from kanban config
# List all
curl -s "${AUTH_HEADER[@]}" "$KANBAN_API/api/project-settings"
# Get one
curl -s "${AUTH_HEADER[@]}" "$KANBAN_API/api/project-settings/$PROJECT"
# Upsert
curl -s "${AUTH_HEADER[@]}" -X PUT "$KANBAN_API/api/project-settings/$PROJECT" \
-H 'Content-Type: application/json' \
-d '{"worklog_type":"work","eob_project_id":"<UUID>","default_work_type_code":"ENG-SW","label":"..."}'
If the API returns 404, fall back to project_map in config file. Do not read any local DB directly.
~/.claude/worklog-sync.json:
{
"eob_base_url": "https://eob.10.182.252.32.sslip.io",
"kanban_api": "https://cyanlunakanban.vercel.app",
"kanban_auth_token": "<X-Kanban-Auth token>",
"access_token": null,
"refresh_token": null,
"user_id": null,
"project_map": {
"edwards.oqc.infra": { "worklog_type": "work", "eob_project_id": "ac78d5ae-a15e-4a40-9638-8109539d6633", "default_work_type_code": "ENG-SW", "label": "OQC Digitalization Infrastructure" },
"unify": { "worklog_type": "work", "eob_project_id": "013c7ee7-edcc-46bc-bcc8-55b15bb2481f", "default_work_type_code": "ENG-SW", "label": "Unify Plasma Single" },
"edwards.operation.board": { "worklog_type": "non-project", "default_work_type_code": "ENG-SW", "label": "Team DX / Productivity" },
"testrig-dashboard": { "worklog_type": "non-project", "default_work_type_code": "ENG-SW", "label": "Team Work" },
"3dx.api": { "worklog_type": "non-project", "default_work_type_code": "ENG-SW", "label": "3DX API (Team Work)" },
"cpet.db": { "worklog_type": "personal" },
"cpet": { "worklog_type": "personal" },
"ai.cycling.workout.planner": { "worklog_type": "personal" },
"ai-cycling-coach": { "worklog_type": "personal" },
"unahouse.finance": { "worklog_type": "personal" },
"today.bike": { "worklog_type": "personal" },
"asan.bicycle": { "worklog_type": "personal" },
"cyanluna-portfolio": { "worklog_type": "personal" },
"cyanluna.skills": { "worklog_type": "personal" },
"bangwahu": { "worklog_type": "personal" },
"remotion-video-gen": { "worklog_type": "personal" },
"type1recovery": { "worklog_type": "personal" },
"kanban-board": { "worklog_type": "personal" }
}
}
/worklog-sync login — Authenticate with EOBAsk user for email and password via AskUserQuestion.
Authenticate:
EOB="https://eob.10.182.252.32.sslip.io"
AUTH=$(curl -s -X POST "$EOB/api/auth/login" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "username=$EMAIL&password=$PASSWORD")
TOKEN=$(echo "$AUTH" | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")
REFRESH=$(echo "$AUTH" | python3 -c "import sys,json; print(json.load(sys.stdin)['refresh_token'])")
ME=$(curl -s "$EOB/api/auth/me" -H "Authorization: Bearer $TOKEN")
USER_ID=$(echo "$ME" | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
~/.claude/worklog-sync.json./worklog-sync map — Configure Project MappingBOARD=$(curl -s "${AUTH_HEADER[@]}" "$KANBAN_API/api/board")
# board.projects = ["project-a", "project-b", ...]
# board.project_settings = { "project-a": {...}, ... }
PROJECTS=$(curl -s "$EOB/api/projects/hierarchy" -H "Authorization: Bearer $TOKEN")
For each kanban project without settings, ask user via AskUserQuestion:
work / non-project / personalwork: select EOB project from hierarchySave via API:
curl -s "${AUTH_HEADER[@]}" -X PUT "$KANBAN_API/api/project-settings/$PROJECT" \
-H 'Content-Type: application/json' \
-d '{"worklog_type": "work", "eob_project_id": "...", "label": "..."}'
/worklog-sync — Main Sync FlowProcedure:
CONFIG=$(cat ~/.claude/worklog-sync.json)
EOB=... TOKEN=... REFRESH=... USER_ID=...
If token expired, try refresh → if refresh fails, prompt /worklog-sync login.
TODAY=$(date +%Y-%m-%d)
DOW=$(date -d "$TODAY" +%u)
MONDAY=$(date -d "$TODAY -$((DOW-1)) days" +%Y-%m-%d)
SUNDAY=$(date -d "$MONDAY +6 days" +%Y-%m-%d)
KANBAN_API=$(echo "$CONFIG" | python3 -c "import sys,json; print(json.load(sys.stdin).get('kanban_api','https://cyanlunakanban.vercel.app'))")
KANBAN_TOKEN=$(echo "$CONFIG" | python3 -c "import sys,json; print(json.load(sys.stdin).get('kanban_auth_token',''))")
BOARD=$(curl -s -H "X-Kanban-Auth: $KANBAN_TOKEN" "$KANBAN_API/api/board")
board.project_settings first, fall back to config.project_mapworklog_type == "personal" → skip entirelyCollect tasks relevant for the week
done with completed_at within the target weekimpl, impl_review, test, plan, plan_review with timestamps within the weekEstimate hours from timestamps
Use task lifecycle timestamps to calculate actual work time per day:
started_at → planned_at = planning work
planned_at → reviewed_at = review + iteration
reviewed_at → tested_at = implementation time
tested_at → completed_at = testing time
started_at → completed_at = total elapsed (fallback)
Rules:
agent_log timestamps can be used for more granular per-day breakdownExample:
started_at=04/01 09:00, completed_at=04/02 15:00Fetch existing worklogs (duplicate check)
EXISTING=$(curl -s "$EOB/api/worklogs?user_id=$USER_ID&start_date=$MONDAY&end_date=$SUNDAY" \
-H "Authorization: Bearer $TOKEN")
Skip if same date + project + similar description already exists.
WORK_TYPES=$(curl -s "$EOB/api/work-types/tree" -H "Authorization: Bearer $TOKEN")
Aggregate into daily worklog cards
Core rule: same date + same project + same work_type → one worklog card.
Group all task entries by (date, project, work_type_code), then:
project_settings.eob_project_idDescription format — concise activity log, not individual task dumps:
인증 모듈 구현 완료, API 검증 수정, 사이드바 정렬 개선
SW 개발 7건 (인증 모듈, API 검증 외 5건)Daily cap: If a single card exceeds 8h, cap at 8h. Remaining hours are dropped (user can adjust in preview).
Example aggregation:
Raw tasks for 02/27, OQC Digitalization, ENG-SW:
#37 run.sh 실행 모드 개선 (0.5h)
#40 SemiAutoTaskForm (0.5h)
#41 TaskSchema parser (0.5h)
#42 Edge Runner timeout (0.5h)
#44 Gherkin DB 마이그레이션 (0.5h)
→ Aggregated card:
date: 2026-02-27
project: OQC Digitalization Infrastructure
work_type: ENG-SW
hours: 2.5h
description: "run.sh 실행모드 개선, SemiAutoTaskForm, TaskSchema parser, Edge Runner timeout, Gherkin DB 마이그레이션 완료"
Preview to user
## Worklog Preview: 2026-02-24 ~ 2026-03-01
| Date | Project | Type | Hours | Description |
|-------|----------------------|-------------|-------|----------------------------------------------------|
| 02/24 | OQC Digitalization | ENG-SW | 1.0h | DB 도메인 분리 완료 |
| 02/24 | Unify Plasma Single | ENG-SW | 5.5h | SQL 통합관리, db-viewer 제거, config manager 생성 외 |
| 02/25 | OQC Digitalization | ENG-SW | 2.0h | FT&CC 카탈로그, Inspection 선택, 자동화 배지 외 |
| 02/25 | OQC Digitalization | ENG-SW-TST | 0.5h | Auto task form 테스트 |
| 02/27 | OQC Digitalization | ENG-SW | 8.0h | Gherkin Pattern A, Corrective 탭, run.sh 개선 외 |
| 02/27 | Unify Plasma Single | ENG-SW | 8.0h | Config Manager 통합, Metadata Viewer 외 |
**Total: 35h / 12 cards** (personal 3건 제외)
Proceed? (Enter to confirm, or edit)
User adjusts via AskUserQuestion if needed (hours, project, work type, date, remove).
Submit approved entries
curl -s -X POST "$EOB/api/worklogs" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"date\": \"$DATE\",
\"user_id\": \"$USER_ID\",
\"project_id\": \"$PROJECT_ID\",
\"work_type_category_id\": $WTC_ID,
\"hours\": $HOURS,
\"description\": \"$DESCRIPTION\"
}"
## Sync Complete
Created 3 entries (9h) for 2026-03-30 ~ 2026-04-05. Failed: 0
/worklog-sync status — Weekly Summarycurl -s "$EOB/api/worklogs?user_id=$USER_ID&start_date=$MONDAY&end_date=$SUNDAY" \
-H "Authorization: Bearer $TOKEN"
## Week: 2026-03-30 ~ 2026-04-05
| Day | Hours | Entries |
|-----|-------|---------|
| Mon 03/30 | 3.75h | 5 |
| Tue 03/31 | 4.0h | 5 |
| Wed 04/01 | 8.0h | 3 |
| Thu 04/02 | 4.5h | 8 |
| Fri 04/03 | 2.5h | 3 |
| **Total** | **22.75h / 40h** | **24** |
| Code | Name | When to Use |
|---|---|---|
ENG-SW | Software Development | Default for kanban coding tasks |
ENG-SW-COD | Implementation (Coding) | Specific coding work |
ENG-SW-REQ | Requirements Analysis | Planning/requirements tasks |
ENG-SW-TST | Unit Testing | Test writing |
ENG-SW-DBG | Debugging | Bug fixes |
PRJ-REV | Review & Approval | Code review tasks |
PRJ-PLN | Planning & Scheduling | Sprint planning |
MTG-INT | Internal Meeting | Team meetings |
QMS-QC | Quality Control | QC-related tasks |
SUP-TKT | Ticket/Issue Resolution | Support tickets |
When default_work_type_code doesn't cover it, infer from task content:
PRJ-REVENG-SW-DBGENG-SW-TSTMTG-INTQMS-QCdefault_work_type_codeproject_map for classification metadata.