{"openapi":"3.1.0","info":{"title":"Mangkun Portfolio API","description":"# Mangkun Portfolio API — AI Agent Guide\n\nThis guide is written for **external AI agents** that programmatically write\nto the Mangkun portfolio graph (posts and roadmaps). Read it end-to-end\nbefore making any write call. Side effects (embedding, edge regeneration,\nbackup snapshots) are not optional.\n\n> **Discovery for headless agents** — `/doc` is JS-rendered. If your tool\n> cannot execute JavaScript, fetch one of these instead (all served as\n> plain HTTP responses on the public domain, no JS required):\n>\n> | URL | Content-Type | Purpose |\n> |---|---|---|\n> | `https://www.mangkun.work/openapi.json` | `application/json` | OpenAPI 3.x spec |\n> | `https://www.mangkun.work/api.md` | `text/markdown` | This guide as raw markdown |\n> | `https://www.mangkun.work/llms.txt` | `text/plain` | Resource index (llmstxt.org format) |\n>\n> All `/api/...` paths are also reachable on `www.mangkun.work` (proxied to\n> the backend origin), so you can call endpoints from either host.\n\n---\n\n## 1. Connection\n\n| Setting | Value |\n|---|---|\n| Production base URL | `https://mangkun-data.org` |\n| Local dev base URL | `http://localhost:8022` |\n| Auth | JWT Bearer in `Authorization: Bearer <access>` header |\n| Content-Type | `application/json` for write calls |\n| Public docs UI | `https://www.mangkun.work/doc` |\n| Timeout | **≥ 30 s** for `POST /api/admin/works` (sync re-linking) |\n\nGet an account from the operator. Never hardcode the password — use env vars.\n\n---\n\n## 2. Authentication flow\n\n### 2.1 Log in once → get access + refresh tokens\n\n```bash\ncurl -sS -X POST $BASE/api/auth/login \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"email\":\"you@example.com\",\"password\":\"…\"}'\n```\n\nResponse:\n```json\n{\n  \"access_token\": \"eyJhbGciOi…\",\n  \"refresh_token\": \"eyJhbGciOi…\",\n  \"token_type\": \"bearer\"\n}\n```\n\nThe access token lasts ~30 minutes; the refresh token ~14 days.\n\n### 2.2 Attach the access token to every admin call\n\n```\nAuthorization: Bearer <access_token>\n```\n\n### 2.3 When you get `401 Token expired`, refresh — don't re-login\n\n```bash\ncurl -sS -X POST $BASE/api/auth/refresh \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"refresh_token\":\"<refresh>\"}'\n```\n\nReturns a new `{access_token, refresh_token}` pair. Replace both.\n\n### 2.4 Identity / role\n\n```\nGET /api/auth/me        →  {id, email, role, created_at}\n```\n\nRoles: `admin` (everything), `editor` (writes), `viewer` (read-only).\nPosting requires `editor` or `admin`.\n\n---\n\n## 3. Writing a post (Work)\n\nA **Work** is one portfolio item — a project, a tool, a research note, a lecture.\n\n### 3.1 Schema\n\n| Field | Type | Required | Notes |\n|---|---|---|---|\n| `id` | int | server-assigned | Do not send on create. |\n| `title` | string | ✅ | Short, human-readable. |\n| `description` | string | ✅ | 1–2 sentences. **Used for embedding.** |\n| `category` | string | ✅ | `development`, `ai`, `research`, `design`, `tools`, `lecture`, `game`, `other`, or new. |\n| `date` | string | ✅ | Format `YYYY.MM`. |\n| `label` | string | optional | Defaults to `title`. |\n| `tags` | string[] | optional | **Strongest linking signal.** 4–10 ideal. Mix Korean + English. |\n| `thumbnail` | string | optional | URL or `/static/uploads/…`. |\n| `externalUrl` | string | optional | Outbound link. |\n| `content` | string | optional | Long-form Markdown. **Embedded.** |\n| `published` | bool | optional | Default `true` for legacy; set `false` to keep as draft. |\n\nServer-managed (do not set):\n- `embedding` — 1024-dim, regenerated from `title + description + tags + content[:2000]` on every write.\n- Outgoing `RELATED_TO` edges — wiped + regenerated per write.\n\n### 3.2 End-to-end example (Python, stdlib only)\n\n```python\nimport os, json, urllib.request, urllib.error\n\nBASE  = os.environ.get(\"PORTFOLIO_API\", \"https://mangkun-data.org\")\nEMAIL = os.environ[\"MANGKUN_EMAIL\"]\nPWORD = os.environ[\"MANGKUN_PASSWORD\"]\n\ndef http(method, path, body=None, token=None, timeout=30):\n    headers = {\"Content-Type\": \"application/json\"}\n    if token:\n        headers[\"Authorization\"] = f\"Bearer {token}\"\n    req = urllib.request.Request(\n        BASE + path,\n        data=json.dumps(body).encode() if body else None,\n        headers=headers, method=method,\n    )\n    with urllib.request.urlopen(req, timeout=timeout) as r:\n        return json.loads(r.read())\n\n# 1. Log in once\ntok = http(\"POST\", \"/api/auth/login\", {\"email\": EMAIL, \"password\": PWORD})\naccess = tok[\"access_token\"]\n\n# 2. Dedupe before posting\nexisting = {w[\"title\"] for w in http(\"GET\", \"/api/admin/works\", token=access)}\n\npost = {\n    \"title\": \"Houdini\",\n    \"description\": \"Procedural 3D tool. VFX, simulation, 절차적 모델링.\",\n    \"category\": \"tools\",\n    \"date\": \"2026.05\",\n    \"tags\": [\"Houdini\", \"Procedural\", \"VFX\", \"Simulation\", \"3D\", \"절차적\"],\n    \"content\": \"## Houdini\\n\\nProcedural workflows…\",\n    \"published\": False,      # 초안으로 만들고 나중에 공개 토글\n}\n\nif post[\"title\"] in existing:\n    print(\"skip — already exists\")\nelse:\n    res = http(\"POST\", \"/api/admin/works\", post, token=access)\n    print(f\"created id={res['id']}  edges={res['edges_created']}\")\n```\n\n### 3.3 Publish toggle\n\nA new post defaults visible. To keep it draft and publish later:\n\n```bash\n# 초안으로 저장\nPOST /api/admin/works              { … , \"published\": false }\n\n# 나중에 공개\nPUT  /api/admin/publish/work/95    { \"published\": true }\n```\n\nPublic routes (`/api/graph`, `/api/works`, `/api/search`) only return\n`published=true` (or unset) items.\n\n---\n\n## 4. Writing a roadmap with a todo list\n\nA **Project** groups related work and has a status + dates. Inside each\nproject you keep a **todo list** of `Task`s, optionally grouped under\n`Milestone`s. When a project nears completion, you write `history_md` —\na curated markdown narrative shown to customers at\n`https://www.mangkun.work/roadmap/{project_id}`.\n\n### 4.1 Object shapes\n\n```\nProject    { id, name, description, status, start_date, target_date,\n             tags[], color, published, history_md? }\nMilestone  { id, project_id, title, description, due_date, status }\nTask       { id, project_id, milestone_id?, title, description,\n             status, due_date, completed_at? }\n```\n\n`completed_at` is set automatically when a Task's `status` transitions to\n`done`, and cleared if you move it back. You don't write it directly.\n`history_md` is the only customer-facing text — keep tasks technical and\nwrite the customer-facing story in `history_md`.\n\n`status` values:\n\n| Object | Allowed values |\n|---|---|\n| Project | `idea`, `planning`, `in_progress`, `blocked`, `done`, `archived` |\n| Milestone, Task | `todo`, `in_progress`, `done`, `cancelled` |\n\nDates are ISO `YYYY-MM-DD` (different from Work's `YYYY.MM`).\n\n### 4.2 Build a roadmap step-by-step\n\n```python\n# (continued from §3.2 — `access` is your bearer token)\n\n# 1. Create a project\nproj = http(\"POST\", \"/api/admin/projects\", {\n    \"name\": \"Mangkun Agent v2\",\n    \"description\": \"외부 에이전트가 작업물을 자동으로 큐레이션하는 시스템\",\n    \"status\": \"in_progress\",\n    \"start_date\": \"2026-05-01\",\n    \"target_date\": \"2026-08-01\",\n    \"tags\": [\"agent\", \"automation\"],\n    \"color\": \"#3b82f6\",\n    \"published\": False,\n}, token=access)\npid = proj[\"id\"]\n\n# 2. Add a milestone\nms = http(\"POST\", f\"/api/admin/projects/{pid}/milestones\", {\n    \"title\": \"Alpha release\",\n    \"due_date\": \"2026-06-15\",\n    \"status\": \"todo\",\n}, token=access)\nmid = ms[\"id\"]\n\n# 3. Add tasks (some grouped under the milestone, some not)\ntodos = [\n    {\"title\": \"Define agent SOP\",      \"status\": \"in_progress\", \"milestone_id\": mid},\n    {\"title\": \"Implement scheduler\",   \"status\": \"todo\",        \"milestone_id\": mid},\n    {\"title\": \"Hook up to Slack\",      \"status\": \"todo\",        \"due_date\": \"2026-06-01\"},\n    {\"title\": \"Write integration tests\", \"status\": \"todo\"},\n]\nfor t in todos:\n    http(\"POST\", f\"/api/admin/projects/{pid}/tasks\", t, token=access)\n\n# 4. Declare a dependency on another project\nhttp(\"POST\", f\"/api/admin/projects/{pid}/depends-on\", {\n    \"target_project_id\": \"<other-project-uuid>\",\n    \"note\": \"needs auth scaffold\",\n}, token=access)\n\n# 5. Link an API endpoint this project uses (optional)\nhttp(\"POST\", \"/api/admin/registry/endpoints/<endpoint-uuid>/used-by\", {\n    \"project_id\": pid,\n}, token=access)\n\n# 6. Fetch the unified roadmap (single call powers the /admin/roadmap UI)\nroad = http(\"GET\", \"/api/admin/roadmap\", token=access)\nprint(road[\"projects\"][0])  # progress = task_done_count / task_count\n```\n\n### 4.3 Updating task status\n\n```bash\nPUT /api/admin/tasks/{task_id}      { \"status\": \"done\" }\n```\n\nRe-fetch `/api/admin/roadmap` after each batch — `task_done_count` and\noverall progress recompute automatically.\n\n### 4.4 Closing a project + writing the customer history\n\n```python\n# 1) Mark all delivered tasks done — completed_at is set automatically\nfor t in http(\"GET\", f\"/api/admin/projects/{pid}/tasks\", token=access):\n    if t[\"title\"] in {\"Implement scheduler\", \"Hook up to Slack\"}:\n        http(\"PUT\", f\"/api/admin/tasks/{t['id']}\", {\"status\": \"done\"}, token=access)\n\n# 2) Write the customer-facing narrative (Markdown)\nhistory = \"\"\"# Mangkun Agent v2 — Phase 1 shipped\n\nA small agent that posts portfolio works on a schedule.\n\n## What shipped\n- **2026-06-12** — Authentication + token refresh\n- **2026-06-15** — Scheduler runs every 6 hours\n\n## What's next\nPhase 2 will add Slack notifications and dry-run mode.\n\"\"\"\nhttp(\"PUT\", f\"/api/admin/projects/{pid}\", {\n    \"status\": \"done\",\n    \"history_md\": history,\n}, token=access)\n\n# 3) Make it public\nhttp(\"PUT\", f\"/api/admin/publish/project/{pid}\", {\"published\": True}, token=access)\n```\n\nAfter publish, customers see the project at\n`https://www.mangkun.work/roadmap/{pid}`: the `history_md` is rendered\nat the top, followed by milestones, then a timeline of every `done` task\nin chronological order (using `completed_at`).\n\n**Tip**: the admin UI has a \"Generate from done tasks\" button that\npre-fills `history_md` with a chronological list. The agent equivalent\nis to read `GET /api/admin/projects/{pid}/tasks`, filter `status=='done'`,\nsort by `completed_at`, and assemble a markdown draft — then edit for\nvoice/tone before `PUT`-ing.\n\n---\n\n### 4.5 Reading public roadmap data (no auth)\n\n| Method | Path | Purpose |\n|---|---|---|\n| `GET` | `/api/projects` | List published projects (summary cards) |\n| `GET` | `/api/projects/{id}` | Detail: `history_md` + milestones + done-tasks timeline |\n\nPublic routes only return `published=true` projects, never drafts.\n\n---\n\n## 5. API key vault (using your stored secrets from another project)\n\nIf your agent needs an API key registered in the vault (e.g., to call an\nendpoint declared in the registry):\n\n```bash\nGET  /api/admin/vault/keys                       →  list metadata (preview only)\nGET  /api/admin/vault/keys/{id}/reveal           →  decrypted value (owner or admin)\n```\n\nReveal is logged. Only call it at the moment of use; never persist\nthe plaintext to disk.\n\n```python\nkey = http(\"GET\", f\"/api/admin/vault/keys/{kid}/reveal\", token=access)[\"value\"]\n# use `key` for the outbound call, then forget it\n```\n\n---\n\n## 6. Auto-linking semantics for Works\n\nWhen you `POST` or `PUT` a Work, the server regenerates outgoing edges:\n\n```\nscore = 0.70 · cosine(embedding_a, embedding_b)\n      + 0.20 · 1{same_category}\n      + 0.10 · jaccard(tags_a, tags_b)\n```\n\nEdge created when `score ≥ 0.42`. **Tag override**: if at least one tag\nmatches another work, an edge is always created — independent of\ncategory or semantic distance. Weight floor scales with shared tag count\n(0.45 + 0.05·n, capped at 0.60).\n\nImplication for an agent: **tagging well is the single highest-leverage\naction you take**.\n\n---\n\n## 7. Error contract\n\n| Status | Cause | Agent action |\n|---|---|---|\n| `401 Token expired` | Access token aged out. | Call `/api/auth/refresh`. |\n| `401 Invalid token` | Tampered or wrong secret. | Re-login. |\n| `403 Insufficient role` | Account is `viewer`. | Stop. Ask operator to elevate. |\n| `404 Not found` | Wrong id on PUT/DELETE. | Re-list and retry. |\n| `409 Already exists` | Duplicate email on register. | Use a different email. |\n| `422` | Validation error — missing field or wrong type. | Inspect `detail`, fix payload. |\n| `503` | Server unhealthy (Vault/JWT misconfigured). | Stop. Notify operator. |\n| `500` | Embedding service or Neo4j unreachable. | Backoff, retry once. |\n\n---\n\n## 8. Best practices\n\n1. **Log in once per session.** Cache tokens in memory; refresh, don't re-login.\n2. **Dedupe Works by title** before `POST` — pull `GET /api/admin/works` first.\n3. **Make `description` count.** It feeds the embedding directly. Two specific\n   sentences beat a one-line label.\n4. **Tag bilingually** (Korean + English). Both enter the embedding and the\n   tag-override path.\n5. **Use drafts** (`published: false`) for staged content; flip later via\n   `/admin/publish/{kind}/{id}`.\n6. **Coalesce edits.** Every `PUT /admin/works/{id}` re-embeds + relinks.\n7. **For roadmaps, fetch `/admin/roadmap` once** to get projects + tasks +\n   edges in a single payload — don't N+1.\n8. **Handle 401 with refresh, not re-login.** Re-login wastes the\n   audit trail and may rate-limit you.\n9. **Respect timeouts.** A successful Work POST can legitimately take\n   2–4 s (embedding + relinking are synchronous).\n10. **Do not store revealed vault values.** Fetch at the moment of use.\n\n---\n\n## 9. Companion files\n\n- `backend/.env.example` — environment template.\n- `backend/scripts/gen_sdk.sh` — generates TypeScript + Python clients\n  from this OpenAPI spec; install once and import the typed client from\n  your other projects.\n- `backend/scripts/embed_existing.py` — full graph rebuild (operator-only).\n- `backend/scripts/backup_db.py` — manual snapshot.\n","version":"2.0.0"},"paths":{"/api/graph":{"get":{"tags":["Graph"],"summary":"Get Graph","description":"공개 그래프 데이터 (published 항목만)","operationId":"get_graph_api_graph_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraphData"}}}}}}},"/api/search":{"get":{"tags":["Search"],"summary":"Search","description":"RAG 기반 검색 (published 작업물만 결과에 포함)","operationId":"search_api_search_get","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","description":"검색 쿼리","title":"Q"},"description":"검색 쿼리"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/works/{work_id}":{"get":{"tags":["Works"],"summary":"Get Work","description":"공개 작업물 상세 조회 (published 만)","operationId":"get_work_api_works__work_id__get","parameters":[{"name":"work_id","in":"path","required":true,"schema":{"type":"integer","title":"Work Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Work"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/works":{"get":{"tags":["Works"],"summary":"Get All Works","description":"공개 작업물 목록 (published 만)","operationId":"get_all_works_api_works_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/Work"},"type":"array","title":"Response Get All Works Api Works Get"}}}}}}},"/api/projects":{"get":{"tags":["PublicProjects","PublicProjects"],"summary":"List Public Projects","description":"공개된 프로젝트 목록 (고객용)","operationId":"list_public_projects_api_projects_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/PublicProjectSummary"},"type":"array","title":"Response List Public Projects Api Projects Get"}}}}}}},"/api/projects/{project_id}":{"get":{"tags":["PublicProjects","PublicProjects"],"summary":"Get Public Project","description":"공개 프로젝트 상세 — 히스토리(history_md) + 마일스톤 + 완료 태스크 타임라인","operationId":"get_public_project_api_projects__project_id__get","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicProjectDetail"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/login":{"post":{"tags":["Admin","admin"],"summary":"Login","description":"레거시 로그인 (정적 비밀번호) — JWT 마이그레이션 후 /auth/login 사용 권장","operationId":"login_api_admin_login_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminLoginRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminLoginResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/works":{"get":{"tags":["Admin","admin"],"summary":"List Works","description":"모든 작업물 조회","operationId":"list_works_api_admin_works_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-Admin-Password","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Admin-Password"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Admin","admin"],"summary":"Create Work","description":"새 작업물 생성 (자동 엣지 생성 포함)","operationId":"create_work_api_admin_works_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-Admin-Password","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Admin-Password"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/works/{work_id}":{"put":{"tags":["Admin","admin"],"summary":"Update Work","description":"작업물 수정","operationId":"update_work_api_admin_works__work_id__put","parameters":[{"name":"work_id","in":"path","required":true,"schema":{"type":"integer","title":"Work Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-Admin-Password","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Admin-Password"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Admin","admin"],"summary":"Delete Work","description":"작업물 삭제","operationId":"delete_work_api_admin_works__work_id__delete","parameters":[{"name":"work_id","in":"path","required":true,"schema":{"type":"integer","title":"Work Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-Admin-Password","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Admin-Password"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/profile":{"get":{"tags":["Admin","admin"],"summary":"Get Profile","description":"프로필 조회","operationId":"get_profile_api_admin_profile_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-Admin-Password","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Admin-Password"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["Admin","admin"],"summary":"Update Profile","description":"프로필 수정","operationId":"update_profile_api_admin_profile_put","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-Admin-Password","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Admin-Password"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/edges":{"get":{"tags":["Admin","admin"],"summary":"List Edges","description":"모든 엣지 조회","operationId":"list_edges_api_admin_edges_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-Admin-Password","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Admin-Password"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Admin","admin"],"summary":"Create Edge","description":"엣지 생성","operationId":"create_edge_api_admin_edges_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-Admin-Password","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Admin-Password"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EdgeCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Admin","admin"],"summary":"Delete Edge","description":"엣지 삭제","operationId":"delete_edge_api_admin_edges_delete","parameters":[{"name":"source","in":"query","required":true,"schema":{"type":"integer","title":"Source"}},{"name":"target","in":"query","required":true,"schema":{"type":"integer","title":"Target"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-Admin-Password","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Admin-Password"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/upload":{"post":{"tags":["Admin","admin"],"summary":"Upload Image","description":"이미지 업로드","operationId":"upload_image_api_admin_upload_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-Admin-Password","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Admin-Password"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_image_api_admin_upload_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/auth/login":{"post":{"tags":["Auth","Auth"],"summary":"Login","description":"이메일 + 비밀번호로 로그인 → 액세스/리프레시 토큰 발급","operationId":"login_api_auth_login_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenPair"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/auth/refresh":{"post":{"tags":["Auth","Auth"],"summary":"Refresh","description":"리프레시 토큰으로 새 토큰 쌍 발급","operationId":"refresh_api_auth_refresh_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenPair"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/auth/me":{"get":{"tags":["Auth","Auth"],"summary":"Me","description":"현재 로그인 사용자 정보","operationId":"me_api_auth_me_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserPublic"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/auth/register":{"post":{"tags":["Auth","Auth"],"summary":"Register","description":"관리자 전용 회원 가입 (오픈 가입 X)","operationId":"register_api_auth_register_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserPublic"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/auth/users":{"get":{"tags":["Auth","Auth"],"summary":"List All Users","description":"모든 사용자 목록","operationId":"list_all_users_api_auth_users_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UserPublic"},"title":"Response List All Users Api Auth Users Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/auth/users/{user_id}/role":{"put":{"tags":["Auth","Auth"],"summary":"Change Role","description":"사용자 역할 변경","operationId":"change_role_api_auth_users__user_id__role_put","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoleUpdateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserPublic"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/auth/users/{user_id}/password":{"put":{"tags":["Auth","Auth"],"summary":"Change Password","description":"비밀번호 변경 (본인 또는 admin)","operationId":"change_password_api_auth_users__user_id__password_put","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PasswordChangeRequest"}}}},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/auth/users/{user_id}":{"delete":{"tags":["Auth","Auth"],"summary":"Remove User","description":"사용자 삭제 (자기 자신은 불가)","operationId":"remove_user_api_auth_users__user_id__delete","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/projects":{"get":{"tags":["Projects","Projects"],"summary":"List Projects","description":"모든 프로젝트 조회","operationId":"list_projects_api_admin_projects_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Project"},"title":"Response List Projects Api Admin Projects Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Projects","Projects"],"summary":"Create Project","description":"프로젝트 생성","operationId":"create_project_api_admin_projects_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Project"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/projects/{project_id}":{"get":{"tags":["Projects","Projects"],"summary":"Get Project","description":"프로젝트 단건 조회","operationId":"get_project_api_admin_projects__project_id__get","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Project"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["Projects","Projects"],"summary":"Update Project","description":"프로젝트 수정","operationId":"update_project_api_admin_projects__project_id__put","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Project"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Projects","Projects"],"summary":"Delete Project","description":"프로젝트 삭제 (마일스톤/태스크 포함)","operationId":"delete_project_api_admin_projects__project_id__delete","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/projects/{project_id}/depends-on":{"post":{"tags":["Projects","Projects"],"summary":"Add Dependency","description":"프로젝트 의존성 추가: project_id → target_project_id","operationId":"add_dependency_api_admin_projects__project_id__depends_on_post","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DependencyRequest"}}}},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/projects/{project_id}/depends-on/{target_id}":{"delete":{"tags":["Projects","Projects"],"summary":"Remove Dependency","description":"의존성 제거","operationId":"remove_dependency_api_admin_projects__project_id__depends_on__target_id__delete","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"target_id","in":"path","required":true,"schema":{"type":"string","title":"Target Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/projects/{project_id}/milestones":{"get":{"tags":["Projects","Projects"],"summary":"List Milestones","description":"프로젝트의 마일스톤 목록","operationId":"list_milestones_api_admin_projects__project_id__milestones_get","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Milestone"},"title":"Response List Milestones Api Admin Projects  Project Id  Milestones Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Projects","Projects"],"summary":"Create Milestone","description":"마일스톤 생성","operationId":"create_milestone_api_admin_projects__project_id__milestones_post","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MilestoneCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Milestone"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/milestones/{milestone_id}":{"put":{"tags":["Projects","Projects"],"summary":"Update Milestone","description":"마일스톤 수정","operationId":"update_milestone_api_admin_milestones__milestone_id__put","parameters":[{"name":"milestone_id","in":"path","required":true,"schema":{"type":"string","title":"Milestone Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MilestoneUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Milestone"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Projects","Projects"],"summary":"Delete Milestone","description":"마일스톤 삭제","operationId":"delete_milestone_api_admin_milestones__milestone_id__delete","parameters":[{"name":"milestone_id","in":"path","required":true,"schema":{"type":"string","title":"Milestone Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/projects/{project_id}/tasks":{"get":{"tags":["Projects","Projects"],"summary":"List Tasks","description":"프로젝트의 태스크 목록","operationId":"list_tasks_api_admin_projects__project_id__tasks_get","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Task"},"title":"Response List Tasks Api Admin Projects  Project Id  Tasks Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Projects","Projects"],"summary":"Create Task","description":"태스크 생성","operationId":"create_task_api_admin_projects__project_id__tasks_post","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Task"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/tasks/{task_id}":{"put":{"tags":["Projects","Projects"],"summary":"Update Task","description":"태스크 수정. status='done' 진입 시 completed_at 자동 설정, 떠나면 클리어.","operationId":"update_task_api_admin_tasks__task_id__put","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","title":"Task Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Task"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Projects","Projects"],"summary":"Delete Task","description":"태스크 삭제","operationId":"delete_task_api_admin_tasks__task_id__delete","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","title":"Task Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/roadmap":{"get":{"tags":["Roadmap","Roadmap"],"summary":"Get Roadmap","description":"모든 프로젝트의 통합 로드맵을 반환.\n프론트엔드는 같은 데이터를 ① 타임라인 ② 태스크 리스트 ③ 의존성 그래프 세 가지 뷰로 렌더링.","operationId":"get_roadmap_api_admin_roadmap_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoadmapResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/registry/endpoints":{"get":{"tags":["Registry","Registry"],"summary":"List Endpoints","description":"등록된 API 엔드포인트 목록","operationId":"list_endpoints_api_admin_registry_endpoints_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Endpoint"},"title":"Response List Endpoints Api Admin Registry Endpoints Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Registry","Registry"],"summary":"Create Endpoint","description":"API 엔드포인트 등록","operationId":"create_endpoint_api_admin_registry_endpoints_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EndpointCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Endpoint"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/registry/endpoints/{endpoint_id}":{"get":{"tags":["Registry","Registry"],"summary":"Get Endpoint","description":"엔드포인트 단건 조회","operationId":"get_endpoint_api_admin_registry_endpoints__endpoint_id__get","parameters":[{"name":"endpoint_id","in":"path","required":true,"schema":{"type":"string","title":"Endpoint Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Endpoint"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["Registry","Registry"],"summary":"Update Endpoint","description":"엔드포인트 수정","operationId":"update_endpoint_api_admin_registry_endpoints__endpoint_id__put","parameters":[{"name":"endpoint_id","in":"path","required":true,"schema":{"type":"string","title":"Endpoint Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EndpointUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Endpoint"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Registry","Registry"],"summary":"Delete Endpoint","description":"엔드포인트 삭제","operationId":"delete_endpoint_api_admin_registry_endpoints__endpoint_id__delete","parameters":[{"name":"endpoint_id","in":"path","required":true,"schema":{"type":"string","title":"Endpoint Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/registry/endpoints/{endpoint_id}/used-by":{"post":{"tags":["Registry","Registry"],"summary":"Link Project To Endpoint","description":"프로젝트가 이 엔드포인트를 사용함을 표시","operationId":"link_project_to_endpoint_api_admin_registry_endpoints__endpoint_id__used_by_post","parameters":[{"name":"endpoint_id","in":"path","required":true,"schema":{"type":"string","title":"Endpoint Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectUsesApi"}}}},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/registry/endpoints/{endpoint_id}/used-by/{project_id}":{"delete":{"tags":["Registry","Registry"],"summary":"Unlink Project From Endpoint","description":"연결 제거","operationId":"unlink_project_from_endpoint_api_admin_registry_endpoints__endpoint_id__used_by__project_id__delete","parameters":[{"name":"endpoint_id","in":"path","required":true,"schema":{"type":"string","title":"Endpoint Id"}},{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/vault/keys":{"get":{"tags":["Vault","Vault"],"summary":"List Keys","description":"등록된 키 메타데이터 (값은 노출하지 않음)","operationId":"list_keys_api_admin_vault_keys_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/KeyMeta"},"title":"Response List Keys Api Admin Vault Keys Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Vault","Vault"],"summary":"Create Key","description":"새 API 키 등록 — 즉시 암호화 후 저장","operationId":"create_key_api_admin_vault_keys_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeyCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeyMeta"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/vault/keys/{key_id}":{"get":{"tags":["Vault","Vault"],"summary":"Get Key Meta","description":"키 메타데이터 (값 미포함)","operationId":"get_key_meta_api_admin_vault_keys__key_id__get","parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"string","title":"Key Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeyMeta"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["Vault","Vault"],"summary":"Update Key","description":"키 메타데이터/값 수정. value가 주어지면 재암호화.","operationId":"update_key_api_admin_vault_keys__key_id__put","parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"string","title":"Key Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeyUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeyMeta"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Vault","Vault"],"summary":"Delete Key","description":"키 삭제 (본인 소유 또는 admin)","operationId":"delete_key_api_admin_vault_keys__key_id__delete","parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"string","title":"Key Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/vault/keys/{key_id}/reveal":{"get":{"tags":["Vault","Vault"],"summary":"Reveal Key","description":"복호화된 키 값을 반환. 본인 소유 또는 admin 만 가능.\n다른 프로젝트가 사용할 수 있도록 호출 시점에만 평문을 제공한다.","operationId":"reveal_key_api_admin_vault_keys__key_id__reveal_get","parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"string","title":"Key Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeyReveal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/publish/{kind}/{node_id}":{"put":{"tags":["Publish","Publish"],"summary":"Set Published","description":"published 플래그 설정. work는 id가 int, project는 string(uuid).","operationId":"set_published_api_admin_publish__kind___node_id__put","parameters":[{"name":"kind","in":"path","required":true,"schema":{"enum":["work","project"],"type":"string","title":"Kind"}},{"name":"node_id","in":"path","required":true,"schema":{"type":"string","title":"Node Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublishRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublishResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/publish/status/{kind}/{node_id}":{"get":{"tags":["Publish","Publish"],"summary":"Get Published","description":"현재 published 상태 조회","operationId":"get_published_api_admin_publish_status__kind___node_id__get","parameters":[{"name":"kind","in":"path","required":true,"schema":{"enum":["work","project"],"type":"string","title":"Kind"}},{"name":"node_id","in":"path","required":true,"schema":{"type":"string","title":"Node Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublishResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/health":{"get":{"summary":"Health Check","description":"헬스 체크 엔드포인트","operationId":"health_check_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}}},"components":{"schemas":{"AdminLoginRequest":{"properties":{"password":{"type":"string","title":"Password"}},"type":"object","required":["password"],"title":"AdminLoginRequest"},"AdminLoginResponse":{"properties":{"success":{"type":"boolean","title":"Success"},"message":{"type":"string","title":"Message"}},"type":"object","required":["success","message"],"title":"AdminLoginResponse"},"Body_upload_image_api_admin_upload_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_upload_image_api_admin_upload_post"},"DependencyRequest":{"properties":{"target_project_id":{"type":"string","title":"Target Project Id"},"note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Note"}},"type":"object","required":["target_project_id"],"title":"DependencyRequest"},"EdgeCreate":{"properties":{"source":{"type":"integer","title":"Source"},"target":{"type":"integer","title":"Target"},"weight":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Weight","default":0.5}},"type":"object","required":["source","target"],"title":"EdgeCreate"},"Endpoint":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"base_url":{"type":"string","title":"Base Url"},"auth_type":{"type":"string","enum":["none","bearer","api_key","basic","oauth2"],"title":"Auth Type"},"api_key_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Key Id"},"openapi_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Openapi Url"},"docs_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Docs Url"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"tags":{"items":{"type":"string"},"type":"array","title":"Tags","default":[]},"created_at":{"type":"string","title":"Created At"},"updated_at":{"type":"string","title":"Updated At"}},"type":"object","required":["id","name","base_url","auth_type","created_at","updated_at"],"title":"Endpoint"},"EndpointCreate":{"properties":{"name":{"type":"string","title":"Name"},"base_url":{"type":"string","title":"Base Url"},"auth_type":{"type":"string","enum":["none","bearer","api_key","basic","oauth2"],"title":"Auth Type","default":"none"},"api_key_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Key Id"},"openapi_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Openapi Url"},"docs_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Docs Url"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"tags":{"items":{"type":"string"},"type":"array","title":"Tags"}},"type":"object","required":["name","base_url"],"title":"EndpointCreate"},"EndpointUpdate":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"base_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Base Url"},"auth_type":{"anyOf":[{"type":"string","enum":["none","bearer","api_key","basic","oauth2"]},{"type":"null"}],"title":"Auth Type"},"api_key_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Key Id"},"openapi_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Openapi Url"},"docs_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Docs Url"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Tags"}},"type":"object","title":"EndpointUpdate"},"GraphData":{"properties":{"nodes":{"items":{"$ref":"#/components/schemas/GraphNode"},"type":"array","title":"Nodes"},"edges":{"items":{"$ref":"#/components/schemas/GraphEdge"},"type":"array","title":"Edges"}},"type":"object","required":["nodes","edges"],"title":"GraphData","description":"그래프 데이터"},"GraphEdge":{"properties":{"source":{"type":"integer","title":"Source"},"target":{"type":"integer","title":"Target"},"weight":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Weight"}},"type":"object","required":["source","target"],"title":"GraphEdge","description":"그래프 엣지"},"GraphNode":{"properties":{"id":{"type":"integer","title":"Id"},"label":{"type":"string","title":"Label"},"category":{"type":"string","title":"Category"},"date":{"type":"string","title":"Date"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},"type":"object","required":["id","label","category","date"],"title":"GraphNode","description":"그래프 노드"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HealthResponse":{"properties":{"status":{"type":"string","title":"Status"},"neo4j_connected":{"type":"boolean","title":"Neo4J Connected"},"version":{"type":"string","title":"Version"}},"type":"object","required":["status","neo4j_connected","version"],"title":"HealthResponse","description":"헬스 체크 응답"},"KeyCreate":{"properties":{"provider":{"type":"string","title":"Provider"},"label":{"type":"string","title":"Label"},"value":{"type":"string","title":"Value"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"tags":{"items":{"type":"string"},"type":"array","title":"Tags"}},"type":"object","required":["provider","label","value"],"title":"KeyCreate"},"KeyMeta":{"properties":{"id":{"type":"string","title":"Id"},"provider":{"type":"string","title":"Provider"},"label":{"type":"string","title":"Label"},"preview":{"type":"string","title":"Preview"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"tags":{"items":{"type":"string"},"type":"array","title":"Tags","default":[]},"owner_id":{"type":"string","title":"Owner Id"},"created_at":{"type":"string","title":"Created At"},"updated_at":{"type":"string","title":"Updated At"}},"type":"object","required":["id","provider","label","preview","owner_id","created_at","updated_at"],"title":"KeyMeta","description":"비밀값 미포함 메타데이터"},"KeyReveal":{"properties":{"id":{"type":"string","title":"Id"},"provider":{"type":"string","title":"Provider"},"label":{"type":"string","title":"Label"},"preview":{"type":"string","title":"Preview"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"tags":{"items":{"type":"string"},"type":"array","title":"Tags","default":[]},"owner_id":{"type":"string","title":"Owner Id"},"created_at":{"type":"string","title":"Created At"},"updated_at":{"type":"string","title":"Updated At"},"value":{"type":"string","title":"Value"}},"type":"object","required":["id","provider","label","preview","owner_id","created_at","updated_at","value"],"title":"KeyReveal","description":"복호화된 값을 포함 — 권한 있는 사용자에게만 반환"},"KeyUpdate":{"properties":{"provider":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Provider"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Value"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Tags"}},"type":"object","title":"KeyUpdate"},"LoginRequest":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"password":{"type":"string","title":"Password"}},"type":"object","required":["email","password"],"title":"LoginRequest"},"Milestone":{"properties":{"id":{"type":"string","title":"Id"},"project_id":{"type":"string","title":"Project Id"},"title":{"type":"string","title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"due_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Due Date"},"status":{"type":"string","enum":["todo","in_progress","done","cancelled"],"title":"Status"},"created_at":{"type":"string","title":"Created At"}},"type":"object","required":["id","project_id","title","status","created_at"],"title":"Milestone"},"MilestoneCreate":{"properties":{"title":{"type":"string","title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"due_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Due Date"},"status":{"type":"string","enum":["todo","in_progress","done","cancelled"],"title":"Status","default":"todo"}},"type":"object","required":["title"],"title":"MilestoneCreate"},"MilestoneUpdate":{"properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"due_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Due Date"},"status":{"anyOf":[{"type":"string","enum":["todo","in_progress","done","cancelled"]},{"type":"null"}],"title":"Status"}},"type":"object","title":"MilestoneUpdate"},"PasswordChangeRequest":{"properties":{"new_password":{"type":"string","title":"New Password"}},"type":"object","required":["new_password"],"title":"PasswordChangeRequest"},"ProfileUpdate":{"properties":{"content":{"type":"string","title":"Content"}},"type":"object","required":["content"],"title":"ProfileUpdate"},"Project":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"status":{"type":"string","enum":["idea","planning","in_progress","blocked","done","archived"],"title":"Status"},"start_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Date"},"target_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Date"},"tags":{"items":{"type":"string"},"type":"array","title":"Tags","default":[]},"color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Color"},"published":{"type":"boolean","title":"Published","default":false},"history_md":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"History Md"},"created_at":{"type":"string","title":"Created At"},"updated_at":{"type":"string","title":"Updated At"}},"type":"object","required":["id","name","status","created_at","updated_at"],"title":"Project"},"ProjectCreate":{"properties":{"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"status":{"type":"string","enum":["idea","planning","in_progress","blocked","done","archived"],"title":"Status","default":"idea"},"start_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Date"},"target_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Date"},"tags":{"items":{"type":"string"},"type":"array","title":"Tags"},"color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Color"},"published":{"type":"boolean","title":"Published","default":false},"history_md":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"History Md"}},"type":"object","required":["name"],"title":"ProjectCreate"},"ProjectUpdate":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"status":{"anyOf":[{"type":"string","enum":["idea","planning","in_progress","blocked","done","archived"]},{"type":"null"}],"title":"Status"},"start_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Date"},"target_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Date"},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Tags"},"color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Color"},"published":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Published"},"history_md":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"History Md"}},"type":"object","title":"ProjectUpdate"},"ProjectUsesApi":{"properties":{"project_id":{"type":"string","title":"Project Id"}},"type":"object","required":["project_id"],"title":"ProjectUsesApi"},"PublicMilestone":{"properties":{"id":{"type":"string","title":"Id"},"title":{"type":"string","title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"due_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Due Date"},"status":{"type":"string","title":"Status"}},"type":"object","required":["id","title","status"],"title":"PublicMilestone"},"PublicProjectDetail":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"status":{"type":"string","title":"Status"},"start_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Date"},"target_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Date"},"color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Color"},"tags":{"items":{"type":"string"},"type":"array","title":"Tags","default":[]},"task_count":{"type":"integer","title":"Task Count","default":0},"task_done_count":{"type":"integer","title":"Task Done Count","default":0},"history_md":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"History Md"},"milestones":{"items":{"$ref":"#/components/schemas/PublicMilestone"},"type":"array","title":"Milestones","default":[]},"completed_tasks":{"items":{"$ref":"#/components/schemas/PublicTask"},"type":"array","title":"Completed Tasks","default":[]}},"type":"object","required":["id","name","status"],"title":"PublicProjectDetail"},"PublicProjectSummary":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"status":{"type":"string","title":"Status"},"start_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Date"},"target_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Date"},"color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Color"},"tags":{"items":{"type":"string"},"type":"array","title":"Tags","default":[]},"task_count":{"type":"integer","title":"Task Count","default":0},"task_done_count":{"type":"integer","title":"Task Done Count","default":0}},"type":"object","required":["id","name","status"],"title":"PublicProjectSummary"},"PublicTask":{"properties":{"id":{"type":"string","title":"Id"},"milestone_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Milestone Id"},"title":{"type":"string","title":"Title"},"status":{"type":"string","title":"Status"},"due_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Due Date"},"completed_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Completed At"}},"type":"object","required":["id","title","status"],"title":"PublicTask"},"PublishRequest":{"properties":{"published":{"type":"boolean","title":"Published"}},"type":"object","required":["published"],"title":"PublishRequest"},"PublishResponse":{"properties":{"kind":{"type":"string","enum":["work","project"],"title":"Kind"},"id":{"anyOf":[{"type":"string"},{"type":"integer"}],"title":"Id"},"published":{"type":"boolean","title":"Published"}},"type":"object","required":["kind","id","published"],"title":"PublishResponse"},"RefreshRequest":{"properties":{"refresh_token":{"type":"string","title":"Refresh Token"}},"type":"object","required":["refresh_token"],"title":"RefreshRequest"},"RegisterRequest":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"password":{"type":"string","title":"Password"},"role":{"type":"string","enum":["admin","editor","viewer"],"title":"Role","default":"viewer"}},"type":"object","required":["email","password"],"title":"RegisterRequest"},"RoadmapEdge":{"properties":{"source":{"type":"string","title":"Source"},"target":{"type":"string","title":"Target"},"kind":{"type":"string","title":"Kind"},"note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Note"}},"type":"object","required":["source","target","kind"],"title":"RoadmapEdge"},"RoadmapProject":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"start_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Date"},"target_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Date"},"color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Color"},"published":{"type":"boolean","title":"Published","default":false},"tags":{"items":{"type":"string"},"type":"array","title":"Tags","default":[]},"has_history":{"type":"boolean","title":"Has History","default":false},"milestone_count":{"type":"integer","title":"Milestone Count","default":0},"task_count":{"type":"integer","title":"Task Count","default":0},"task_done_count":{"type":"integer","title":"Task Done Count","default":0}},"type":"object","required":["id","name","status"],"title":"RoadmapProject"},"RoadmapResponse":{"properties":{"projects":{"items":{"$ref":"#/components/schemas/RoadmapProject"},"type":"array","title":"Projects"},"tasks":{"items":{"$ref":"#/components/schemas/RoadmapTask"},"type":"array","title":"Tasks"},"edges":{"items":{"$ref":"#/components/schemas/RoadmapEdge"},"type":"array","title":"Edges"}},"type":"object","required":["projects","tasks","edges"],"title":"RoadmapResponse"},"RoadmapTask":{"properties":{"id":{"type":"string","title":"Id"},"project_id":{"type":"string","title":"Project Id"},"project_name":{"type":"string","title":"Project Name"},"milestone_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Milestone Id"},"title":{"type":"string","title":"Title"},"status":{"type":"string","title":"Status"},"due_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Due Date"},"completed_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Completed At"}},"type":"object","required":["id","project_id","project_name","title","status"],"title":"RoadmapTask"},"RoleUpdateRequest":{"properties":{"role":{"type":"string","enum":["admin","editor","viewer"],"title":"Role"}},"type":"object","required":["role"],"title":"RoleUpdateRequest"},"SearchResponse":{"properties":{"query":{"type":"string","title":"Query"},"aiResponse":{"type":"string","title":"Airesponse"},"works":{"items":{"$ref":"#/components/schemas/Work"},"type":"array","title":"Works"},"filteredNodeIds":{"items":{"type":"integer"},"type":"array","title":"Filterednodeids"}},"type":"object","required":["query","aiResponse","works","filteredNodeIds"],"title":"SearchResponse","description":"검색 응답"},"Task":{"properties":{"id":{"type":"string","title":"Id"},"project_id":{"type":"string","title":"Project Id"},"milestone_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Milestone Id"},"title":{"type":"string","title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"status":{"type":"string","enum":["todo","in_progress","done","cancelled"],"title":"Status"},"due_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Due Date"},"created_at":{"type":"string","title":"Created At"},"completed_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Completed At"}},"type":"object","required":["id","project_id","title","status","created_at"],"title":"Task"},"TaskCreate":{"properties":{"title":{"type":"string","title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"status":{"type":"string","enum":["todo","in_progress","done","cancelled"],"title":"Status","default":"todo"},"due_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Due Date"},"milestone_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Milestone Id"}},"type":"object","required":["title"],"title":"TaskCreate"},"TaskUpdate":{"properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"status":{"anyOf":[{"type":"string","enum":["todo","in_progress","done","cancelled"]},{"type":"null"}],"title":"Status"},"due_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Due Date"},"milestone_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Milestone Id"}},"type":"object","title":"TaskUpdate"},"TokenPair":{"properties":{"access_token":{"type":"string","title":"Access Token"},"refresh_token":{"type":"string","title":"Refresh Token"},"token_type":{"type":"string","title":"Token Type","default":"bearer"}},"type":"object","required":["access_token","refresh_token"],"title":"TokenPair","description":"JWT 토큰 응답"},"UserPublic":{"properties":{"id":{"type":"string","title":"Id"},"email":{"type":"string","title":"Email"},"role":{"type":"string","enum":["admin","editor","viewer"],"title":"Role"},"created_at":{"type":"string","title":"Created At"}},"type":"object","required":["id","email","role","created_at"],"title":"UserPublic","description":"공개 사용자 모델 (비밀번호 해시 제외)"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"Work":{"properties":{"id":{"type":"integer","title":"Id"},"title":{"type":"string","title":"Title"},"description":{"type":"string","title":"Description"},"date":{"type":"string","title":"Date"},"category":{"type":"string","title":"Category"},"thumbnail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumbnail"},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Tags"},"externalUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Externalurl"},"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content"}},"type":"object","required":["id","title","description","date","category"],"title":"Work","description":"작업물"},"WorkCreate":{"properties":{"title":{"type":"string","title":"Title"},"description":{"type":"string","title":"Description"},"category":{"type":"string","title":"Category"},"date":{"type":"string","title":"Date"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Tags"},"thumbnail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumbnail"},"externalUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Externalurl"},"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content"}},"type":"object","required":["title","description","category","date"],"title":"WorkCreate"},"WorkUpdate":{"properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category"},"date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Date"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Tags"},"thumbnail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumbnail"},"externalUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Externalurl"},"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content"}},"type":"object","title":"WorkUpdate"}}}}