{"openapi":"3.0.3","info":{"title":"SUNUP Site Admin API","version":"1.0.0","description":"SUNUP株式会社ウェブサイトのコンテンツ管理 REST API。\nAIエージェント（Hermes / OpenClaw / Claude など）による自動管理を想定しています。\n\n## 認証\nすべてのデータエンドポイントは Bearer トークン認証が必要です。\n`Authorization: Bearer <api_key>`\n\nAPIキーは管理画面 `/admin` → ⚙️設定 → APIキー管理 で発行してください。\n人間の管理者が発行したキーをエージェントに渡してください。\n\n## レスポンス形式\n- 一覧: `{ \"data\": [...], \"total\": N }`\n- 単一: `{ \"data\": { ... } }`\n- 作成成功: HTTP 201 + `{ \"data\": { ... } }`\n- エラー: `{ \"error\": \"説明文\" }`\n\n## 典型的なエージェントワークフロー例\n1. `GET /api/v1/stats` でサイト状況を把握\n2. `POST /api/v1/news` でお知らせ記事を自動投稿\n3. `GET /api/v1/leads` で新規リードを確認し `PATCH /api/v1/leads/:id` でステータス更新\n4. `POST /api/v1/templates` でテンプレートを登録 → upload-preview → upload-zip → publish","contact":{"email":"admin@sunup.co.jp"}},"servers":[{"url":"http://localhost:13000/api/v1","description":"SUNUP production server"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"管理画面 /admin → ⚙️設定 → APIキー管理 で発行したキー"}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string","example":"説明文"}},"required":["error"]},"NewsEntry":{"type":"object","properties":{"news_id":{"type":"string","format":"uuid"},"title":{"type":"string"},"content":{"type":"string","description":"HTML or plain text content"},"category":{"type":"string","example":"news","enum":["news","info","event"]},"is_published":{"type":"integer","enum":[0,1]},"published_at":{"type":"string","format":"date-time","nullable":true},"image_url":{"type":"string","nullable":true},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"Template":{"type":"object","properties":{"template_id":{"type":"string","format":"uuid"},"title":{"type":"string"},"description":{"type":"string","nullable":true},"category1":{"type":"string","nullable":true,"description":"業種 (例: 飲食・カフェ, 医療・クリニック, 美容・サロン, IT・テック など)"},"category2":{"type":"string","nullable":true,"description":"用途 (例: コーポレートサイト, ランディングページ, ECサイト など)"},"category3":{"type":"string","nullable":true,"description":"スタイル (例: モダン, ミニマル, ナチュラル, クール・ダーク など)"},"preview_image":{"type":"string","nullable":true,"description":"Relative path to preview JPEG"},"folder_path":{"type":"string","nullable":true,"description":"Server path where ZIP was extracted"},"is_published":{"type":"integer","enum":[0,1]},"sort_order":{"type":"integer","default":0},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"Lead":{"type":"object","properties":{"lead_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"email":{"type":"string","format":"email"},"company":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"status":{"type":"string","enum":["open","contacted","appointed","won","lost","archived"]},"probability":{"type":"number","nullable":true,"description":"成約確率 0.0–1.0"},"notes":{"type":"string","nullable":true},"created_at":{"type":"string","format":"date-time"}}},"Estimate":{"type":"object","properties":{"estimate_id":{"type":"string","format":"uuid"},"lead_id":{"type":"string","nullable":true},"title":{"type":"string","nullable":true},"summary":{"type":"string"},"price_min":{"type":"integer","description":"万円"},"price_max":{"type":"integer","description":"万円"},"total_days":{"type":"integer"},"timeline":{"type":"string"},"created_at":{"type":"string","format":"date-time"}}},"KnowledgeEntry":{"type":"object","properties":{"entry_id":{"type":"string","format":"uuid"},"title":{"type":"string"},"category":{"type":"string","enum":["project_example","budget_reference","timeline_guide","tech_stack_pricing","cloud_architecture","pitfall_warning"]},"content":{"type":"string","description":"Markdown content"},"budget_min":{"type":"integer","nullable":true},"budget_max":{"type":"integer","nullable":true},"timeline_weeks":{"type":"integer","nullable":true},"tags":{"type":"string","nullable":true,"description":"JSON array string"},"lifecycle_status":{"type":"string","enum":["draft","review_pending","published","archived"]},"is_active":{"type":"integer","enum":[0,1]},"created_at":{"type":"string","format":"date-time"}}},"Stats":{"type":"object","properties":{"leads":{"type":"object","properties":{"total":{"type":"integer"},"open":{"type":"integer"},"won":{"type":"integer"}}},"estimates":{"type":"object","properties":{"total":{"type":"integer"},"this_month":{"type":"integer"}}},"news":{"type":"object","properties":{"total":{"type":"integer"},"published":{"type":"integer"}}},"templates":{"type":"object","properties":{"total":{"type":"integer"},"published":{"type":"integer"}}},"knowledge":{"type":"object","properties":{"total":{"type":"integer"}}},"generated_at":{"type":"string","format":"date-time"}}}},"responses":{"NotFound":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"BadRequest":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/stats":{"get":{"operationId":"getStats","summary":"サイト統計サマリー","description":"リード数・見積もり数・記事数・テンプレート数・ナレッジ数を返します。エージェントのループ冒頭で現状把握に使ってください。","responses":{"200":{"description":"統計データ","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Stats"}}}}}}}}},"/news":{"get":{"operationId":"listNews","summary":"お知らせ記事一覧","parameters":[{"name":"published","in":"query","schema":{"type":"string","enum":["true","false"]},"description":"公開済みのみ取得する場合は true"},{"name":"category","in":"query","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":200}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"記事一覧","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/NewsEntry"}},"total":{"type":"integer"}}}}}}}},"post":{"operationId":"createNews","summary":"お知らせ記事を作成","description":"`is_published: true` を指定すると即時公開されます。","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title","content"],"properties":{"title":{"type":"string"},"content":{"type":"string"},"category":{"type":"string","default":"news"},"is_published":{"type":"boolean","default":false},"published_at":{"type":"string","format":"date-time","nullable":true}}}}}},"responses":{"201":{"description":"作成した記事","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/NewsEntry"}}}}}},"400":{"description":"バリデーションエラー","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/news/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getNews","summary":"記事取得","responses":{"200":{"description":"記事","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/NewsEntry"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"updateNews","summary":"記事更新","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string"},"content":{"type":"string"},"category":{"type":"string"},"is_published":{"type":"boolean"},"published_at":{"type":"string","nullable":true}}}}}},"responses":{"200":{"description":"更新後の記事","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/NewsEntry"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"operationId":"deleteNews","summary":"記事削除（画像ファイルも削除）","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/templates":{"get":{"operationId":"listTemplates","summary":"テンプレート一覧","parameters":[{"name":"published","in":"query","schema":{"type":"string","enum":["true"]},"description":"公開済みのみ"}],"responses":{"200":{"description":"テンプレート一覧","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Template"}},"total":{"type":"integer"}}}}}}}},"post":{"operationId":"createTemplate","summary":"テンプレートを新規作成","description":"まずメタデータを作成して `template_id` を取得します。その後 `upload-preview` → `upload-zip` → PATCH `is_published:true` の順で完成させます。","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title"],"properties":{"title":{"type":"string","example":"飲食店向けモダンテンプレート"},"description":{"type":"string","nullable":true},"category1":{"type":"string","nullable":true,"description":"業種 (飲食・カフェ / 医療・クリニック / 美容・サロン / 不動産 / IT・テック / 教育 / 小売・EC / その他)"},"category2":{"type":"string","nullable":true,"description":"用途 (コーポレートサイト / ランディングページ / ECサイト / ポートフォリオ / 採用サイト / その他)"},"category3":{"type":"string","nullable":true,"description":"スタイル (モダン / ミニマル / ナチュラル / クール・ダーク / ポップ・カラフル / クラシック)"},"is_published":{"type":"boolean","default":false},"sort_order":{"type":"integer","default":0}}}}}},"responses":{"201":{"description":"作成したテンプレート","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Template"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"}}}},"/templates/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getTemplate","summary":"テンプレート取得","responses":{"200":{"description":"テンプレート","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Template"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"updateTemplate","summary":"テンプレートのメタデータ更新・公開/非公開切り替え","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string"},"description":{"type":"string","nullable":true},"category1":{"type":"string","nullable":true},"category2":{"type":"string","nullable":true},"category3":{"type":"string","nullable":true},"is_published":{"type":"boolean"},"sort_order":{"type":"integer"}}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Template"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/templates/{id}/upload-preview":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"uploadTemplatePreview","summary":"プレビュー画像をアップロード","description":"画像は 1280×720px JPEG に自動リサイズされます。フィールド名は `preview`。","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["preview"],"properties":{"preview":{"type":"string","format":"binary","description":"PNG / JPEG / WebP など任意の画像形式"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"preview_url":{"type":"string"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/templates/{id}/upload-zip":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"uploadTemplateZip","summary":"ZIPファイルをアップロード・展開","description":"index.html を含む ZIP をアップロードします。ZIPルート直下または単一フォルダ内の index.html を自動検出します。フィールド名は `zip`。","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["zip"],"properties":{"zip":{"type":"string","format":"binary","description":".zip ファイル"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"file_count":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/leads":{"get":{"operationId":"listLeads","summary":"リード（見込み顧客）一覧","parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["open","contacted","appointed","won","lost","archived"]}},{"name":"q","in":"query","schema":{"type":"string"},"description":"名前・会社名・メールで検索"},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":200}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"リード一覧","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Lead"}},"total":{"type":"integer"}}}}}}}}},"/leads/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getLead","summary":"リード取得","responses":{"200":{"description":"リード","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Lead"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"updateLead","summary":"リード情報・ステータス更新","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["open","contacted","appointed","won","lost","archived"]},"notes":{"type":"string"},"internal_notes":{"type":"string"},"probability":{"type":"number"},"plan":{"type":"string"},"quoted_price":{"type":"integer"},"won_price":{"type":"integer"}}}}}},"responses":{"200":{"description":"更新後のリード","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Lead"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/estimates":{"get":{"operationId":"listEstimates","summary":"見積もり一覧（読み取り専用）","parameters":[{"name":"lead_id","in":"query","schema":{"type":"string","format":"uuid"},"description":"特定リードの見積もりに絞り込む"},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":200}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"見積もり一覧","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Estimate"}},"total":{"type":"integer"}}}}}}}}},"/knowledge":{"get":{"operationId":"listKnowledge","summary":"ナレッジベース一覧","parameters":[{"name":"category","in":"query","schema":{"type":"string","enum":["project_example","budget_reference","timeline_guide","tech_stack_pricing","cloud_architecture","pitfall_warning"]}},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":200}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"ナレッジ一覧","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/KnowledgeEntry"}},"total":{"type":"integer"}}}}}}}},"post":{"operationId":"createKnowledge","summary":"ナレッジエントリを作成","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title","content","category"],"properties":{"title":{"type":"string"},"content":{"type":"string","description":"Markdown形式推奨"},"category":{"type":"string","enum":["project_example","budget_reference","timeline_guide","tech_stack_pricing","cloud_architecture","pitfall_warning"]},"tech_stack":{"type":"string","nullable":true,"description":"JSON配列文字列 例: [\"React\",\"Node.js\"]"},"budget_min":{"type":"integer","nullable":true},"budget_max":{"type":"integer","nullable":true},"timeline_weeks":{"type":"integer","nullable":true},"tags":{"type":"string","nullable":true,"description":"JSON配列文字列"},"quality_score":{"type":"number","nullable":true,"description":"0.0–1.0"},"lifecycle_status":{"type":"string","enum":["draft","review_pending","published","archived"],"default":"published"}}}}}},"responses":{"201":{"description":"作成したエントリ","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/KnowledgeEntry"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"}}}},"/knowledge/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getKnowledge","summary":"ナレッジエントリ取得","responses":{"200":{"description":"エントリ","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/KnowledgeEntry"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"updateKnowledge","summary":"ナレッジエントリ更新","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string"},"content":{"type":"string"},"category":{"type":"string"},"lifecycle_status":{"type":"string"},"is_active":{"type":"boolean"},"quality_score":{"type":"number"}}}}}},"responses":{"200":{"description":"更新後","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/KnowledgeEntry"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}}}}