<!DOCTYPE html><html lang="ko"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>API — MetaHumotonic</title><meta name="description" content="MetaHumotonic API endpoints, services, and Cypher query examples."><link rel="icon" type="image/svg+xml" href="/favicon.svg"><style>.starfield-bg{z-index:-2;pointer-events:none;background:radial-gradient(80% 60% at 50% 35%,#6366f11a 0%,#0000 60%),radial-gradient(60% 50% at 70% 70%,#6366f10d 0%,#0000 55%),linear-gradient(#050507 0%,#000 70%);position:fixed;inset:0}.starfield-bg:after{content:"";opacity:.06;mix-blend-mode:overlay;pointer-events:none;background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.6'/%3E%3C/svg%3E");position:absolute;inset:0}.vignette{pointer-events:none;z-index:-1;background:radial-gradient(#0000 50%,#0009 100%);position:fixed;inset:0}#cosmos-canvas,#chu-canvas{z-index:0;pointer-events:none;position:fixed;inset:0}.mh-frame--dark,[data-theme=dark]{--bg-0:#000;--bg-1:#0a0a0a;--bg-2:#161618;--text:#e8e8ea;--text-dim:#86868b;--accent:#6366f1;--accent-soft:#6366f12e;--border:#ffffff14;--border-strong:#ffffff24;--highlight:#ffffff0f;--radius:8px;--ease:cubic-bezier(.4, 0, .2, 1)}.counter{font-variant-numeric:tabular-nums;letter-spacing:-.02em;font-weight:500}.kg-donut{border:1px solid #0e0e0c1f;border-radius:50%;width:220px;height:220px;position:relative}.kg-donut:after{content:"";background:var(--mh-paper,#f5f1e8);border:1px solid #0e0e0c1f;border-radius:50%;position:absolute;inset:28%}.kg-donut__label{z-index:1;flex-direction:column;justify-content:center;align-items:center;display:flex;position:absolute;inset:0}.kg-legend{flex-wrap:wrap;gap:.5rem;margin:0;padding:0;list-style:none;display:flex}.kg-legend__swatch{vertical-align:middle;border-radius:2px;width:8px;height:8px;margin-right:6px;display:inline-block}.sr-only{clip:rect(0, 0, 0, 0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}:focus-visible{outline:1px solid var(--accent,#6366f1);outline-offset:3px;border-radius:4px}.skip-link{background:var(--accent,#6366f1);color:#000;z-index:100;padding:.75rem 1.5rem;font-weight:500;transition:top .16s;position:absolute;top:-100%;left:0}.skip-link:focus{top:0}@media (width<=768px){.kg-donut{width:160px;height:160px}}@media (prefers-reduced-motion:reduce){#cosmos-canvas,#chu-canvas{display:none}}
*,:before,:after{box-sizing:border-box;margin:0;padding:0}html{scroll-behavior:smooth}body{color:#e0e6f0;background:#050810;font-family:Inter,system-ui,sans-serif;line-height:1.6;overflow-x:hidden}a{color:inherit;text-decoration:none}.page-wrap{z-index:1;max-width:1000px;margin:0 auto;padding:0 clamp(1rem,3vw,3rem);position:relative}.breadcrumb{color:#4a5578;padding:1.5rem 0;font-size:.85rem}.breadcrumb a{color:#67e8f9}.breadcrumb a:hover{text-decoration:underline}.breadcrumb span{margin:0 .3rem}.api-header{text-align:center;padding:2rem 0 3rem}.api-header h1{color:#fff;margin-bottom:1rem;font-size:clamp(2rem,5vw,3rem);font-weight:800}.api-desc{color:#8892b0;max-width:600px;margin:0 auto;font-size:1.1rem}.section{padding:2rem 0}.section h2{color:#fff;margin-bottom:.5rem;font-size:1.3rem;font-weight:700}.section-desc{color:#4a5578;margin-bottom:1.5rem;font-size:.9rem}.section-desc code{color:#67e8f9;font-size:.85rem}.endpoint-list{flex-direction:column;gap:1rem;display:flex}.endpoint-card{backdrop-filter:blur(8px);background:#0d1b2a99;border:1px solid #6b4c9926;border-radius:12px;padding:1.25rem}.endpoint-head{align-items:center;gap:.75rem;margin-bottom:.5rem;display:flex}.method{color:#050810;background:#34d399;border-radius:4px;padding:.15rem .5rem;font-size:.75rem;font-weight:700}.ep-path{color:#67e8f9;font-size:1rem}.endpoint-card p{color:#8892b0;font-size:.9rem}.ep-response{color:#a78bfa;background:#0000004d;border-radius:6px;margin-top:.5rem;padding:.5rem .75rem;font-family:JetBrains Mono,monospace;font-size:.8rem}.service-grid{grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:1rem;display:grid}.service-card{backdrop-filter:blur(8px);background:#0d1b2a99;border:1px solid #6b4c9926;border-radius:12px;padding:1rem;transition:border-color .3s}.service-card:hover{border-color:#a78bfa4d}.svc-head{align-items:center;gap:.5rem;margin-bottom:.4rem;display:flex}.svc-dot{border-radius:50%;flex-shrink:0;width:8px;height:8px}.svc-head h3{color:#fff;font-size:1rem;font-weight:600}.svc-port{color:#4a5578;font-size:.8rem}.svc-path{color:#67e8f9;margin-bottom:.4rem;font-size:.85rem;display:block}.service-card p{color:#8892b0;font-size:.85rem}.cypher-list{flex-direction:column;gap:1rem;display:flex}.cypher-card{backdrop-filter:blur(8px);background:#0d1b2a99;border:1px solid #6b4c9926;border-radius:12px;padding:1rem 1.25rem}.cypher-card h3{color:#a78bfa;margin-bottom:.5rem;font-size:.95rem;font-weight:600}.cypher-card pre{color:#67e8f9;white-space:pre-wrap;font-family:JetBrains Mono,monospace;font-size:.8rem;line-height:1.5;overflow-x:auto}.infra-diagram{max-width:650px;margin:0 auto}.infra-svg{width:100%;height:auto}.page-footer{justify-content:space-between;padding:3rem 0;display:flex}.back-link{color:#67e8f9;font-size:.9rem;font-weight:500}.back-link:hover{text-decoration:underline}.fade-in{opacity:0;transition:opacity .6s,transform .6s;transform:translateY(20px)}.fade-in.visible{opacity:1;transform:none}@media (width<=480px){.service-grid{grid-template-columns:1fr}}
</style><script type="module" src="/_astro/page.Dwipeu-R.js"></script></head><body><div class="starfield-bg" aria-hidden="true"></div><div class="vignette" aria-hidden="true"></div><div class="page-wrap"><nav class="breadcrumb"><a href="/">MetaHumotonic</a> <span>›</span> <span>API</span></nav><header class="api-header fade-in"><h1><span style="color:#fbbf24">API</span> & Services</h1><p class="api-desc">MetaHumotonic 서버의 API 엔드포인트, 서비스 접근 경로, Cypher 쿼리 예제.</p></header><section class="section fade-in"><h2>JSON API</h2><p class="section-desc">라이브 API — <code>metahumotonic_web_back</code> (FastAPI). Neo4j 실시간 + MongoDB 피드백.</p><div class="endpoint-list"><div class="endpoint-card"><div class="endpoint-head"><span class="method">GET</span><code class="ep-path">/api/stats</code></div><p>KG 전체 통계 — 라이브 Neo4j</p><pre class="ep-response">{ nodes, rels, labels, relTypes, domains, skills }</pre></div><div class="endpoint-card"><div class="endpoint-head"><span class="method">GET</span><code class="ep-path">/api/domains</code></div><p>DomainHub 목록 — 라이브</p><pre class="ep-response">[{ name, displayName, nodeCount, description }]</pre></div><div class="endpoint-card"><div class="endpoint-head"><span class="method">GET</span><code class="ep-path">/api/skills</code></div><p>스킬 목록 (7군단장 + infra/meta)</p><pre class="ep-response">[{ name, description, category }]</pre></div><div class="endpoint-card"><div class="endpoint-head"><span class="method">POST</span><code class="ep-path">/api/feedback</code></div><p>피드백 접수 — MongoDB 저장 확인·허니팟·레이트리밋</p><pre class="ep-response">{ ok, id, status: &quot;stored&quot; } · 저장 미확인 시 503</pre></div></div></section><section class="section fade-in"><h2>서비스 엔드포인트</h2><p class="section-desc">Traefik 리버스 프록시 경유. Base: <code>http://bhgman.iptime.org</code></p><div class="service-grid"><div class="service-card"><div class="svc-head"><span class="svc-dot" style="background:#67e8f9"></span><h3>Neo4j Browser</h3><span class="svc-port">:7474</span></div><code class="svc-path">/neo4j/</code><p>Knowledge Graph 브라우저. Cypher 쿼리 실행.</p></div><div class="service-card"><div class="svc-head"><span class="svc-dot" style="background:#a78bfa"></span><h3>n8n Workflows</h3><span class="svc-port">:5678</span></div><code class="svc-path">/n8n/</code><p>워크플로우 자동화 플랫폼.</p></div><div class="service-card"><div class="svc-head"><span class="svc-dot" style="background:#fbbf24"></span><h3>MinIO Console</h3><span class="svc-port">:9001</span></div><code class="svc-path">/minio/</code><p>오브젝트 스토리지 관리. S3 호환.</p></div><div class="service-card"><div class="svc-head"><span class="svc-dot" style="background:#fbbf24"></span><h3>MinIO S3 API</h3><span class="svc-port">:9000</span></div><code class="svc-path">/s3/</code><p>S3 호환 API 엔드포인트.</p></div><div class="service-card"><div class="svc-head"><span class="svc-dot" style="background:#34d399"></span><h3>Traefik Dashboard</h3><span class="svc-port">:8080</span></div><code class="svc-path">/traefik/</code><p>리버스 프록시 + 라우팅 대시보드.</p></div><div class="service-card"><div class="svc-head"><span class="svc-dot" style="background:#f472b6"></span><h3>Skill Registry</h3><span class="svc-port">:-</span></div><code class="svc-path">/skills/</code><p>Claude Code 스킬 18개 레지스트리.</p></div></div></section><section class="section fade-in"><h2>Cypher 쿼리 예제</h2><p class="section-desc">Neo4j KG (bolt://localhost:7687) 직접 쿼리.</p><div class="cypher-list"><div class="cypher-card"><h3>전체 통계</h3><pre><code>MATCH (n) WITH count(n) as nodes
MATCH ()-[r]-&gt;() RETURN nodes, count(r) as rels</code></pre></div><div class="cypher-card"><h3>도메인 목록</h3><pre><code>MATCH (d:DomainHub)
RETURN d.displayName, d.nodeCount
ORDER BY d.nodeCount DESC</code></pre></div><div class="cypher-card"><h3>오답노트 조회</h3><pre><code>MATCH (l:Lesson)
WHERE l.resolved IS NULL
RETURN l.name, l.problem, l.severity</code></pre></div><div class="cypher-card"><h3>워크스페이스 온톨로지</h3><pre><code>MATCH (n:AbstractNode)
RETURN labels(n), n.name, n.description
LIMIT 20</code></pre></div></div></section><section class="section fade-in"><h2>인프라 구조</h2><div class="infra-diagram"><svg viewBox="0 0 600 300" class="infra-svg"><text x="300" y="25" text-anchor="middle" fill="#4a5578" font-size="11" font-weight="600">Internet (218.233.221.77)</text><line x1="300" y1="32" x2="300" y2="55" stroke="#4a5578" stroke-width="1" stroke-dasharray="3 3"></line><rect x="220" y="55" width="160" height="35" rx="8" fill="rgba(52,211,153,0.1)" stroke="rgba(52,211,153,0.4)" stroke-width="1"></rect><text x="300" y="77" text-anchor="middle" fill="#34d399" font-size="11" font-weight="600">Traefik :80</text><line x1="300" y1="90" x2="60" y2="130" stroke="rgba(107,76,153,0.3)" stroke-width="0.8"></line><line x1="300" y1="90" x2="160" y2="130" stroke="rgba(107,76,153,0.3)" stroke-width="0.8"></line><line x1="300" y1="90" x2="260" y2="130" stroke="rgba(107,76,153,0.3)" stroke-width="0.8"></line><line x1="300" y1="90" x2="360" y2="130" stroke="rgba(107,76,153,0.3)" stroke-width="0.8"></line><line x1="300" y1="90" x2="460" y2="130" stroke="rgba(107,76,153,0.3)" stroke-width="0.8"></line><line x1="300" y1="90" x2="560" y2="130" stroke="rgba(107,76,153,0.3)" stroke-width="0.8"></line><g><rect x="20" y="130" width="80" height="30" rx="6" fill="rgba(13,27,42,0.6)" stroke="#67e8f9" stroke-width="0.8" opacity="0.8"></rect><text x="60" y="150" text-anchor="middle" fill="#67e8f9" font-size="9" font-weight="500">Neo4j</text></g><g><rect x="120" y="130" width="80" height="30" rx="6" fill="rgba(13,27,42,0.6)" stroke="#a78bfa" stroke-width="0.8" opacity="0.8"></rect><text x="160" y="150" text-anchor="middle" fill="#a78bfa" font-size="9" font-weight="500">PostgreSQL</text></g><g><rect x="220" y="130" width="80" height="30" rx="6" fill="rgba(13,27,42,0.6)" stroke="#a78bfa" stroke-width="0.8" opacity="0.8"></rect><text x="260" y="150" text-anchor="middle" fill="#a78bfa" font-size="9" font-weight="500">n8n</text></g><g><rect x="320" y="130" width="80" height="30" rx="6" fill="rgba(13,27,42,0.6)" stroke="#fbbf24" stroke-width="0.8" opacity="0.8"></rect><text x="360" y="150" text-anchor="middle" fill="#fbbf24" font-size="9" font-weight="500">MinIO</text></g><g><rect x="420" y="130" width="80" height="30" rx="6" fill="rgba(13,27,42,0.6)" stroke="#f472b6" stroke-width="0.8" opacity="0.8"></rect><text x="460" y="150" text-anchor="middle" fill="#f472b6" font-size="9" font-weight="500">Redis</text></g><g><rect x="520" y="130" width="80" height="30" rx="6" fill="rgba(13,27,42,0.6)" stroke="#34d399" stroke-width="0.8" opacity="0.8"></rect><text x="560" y="150" text-anchor="middle" fill="#34d399" font-size="9" font-weight="500">Kafka</text></g><line x1="300" y1="160" x2="300" y2="195" stroke="rgba(107,76,153,0.3)" stroke-width="0.8" stroke-dasharray="3 3"></line><rect x="170" y="195" width="260" height="30" rx="8" fill="rgba(251,191,36,0.05)" stroke="rgba(251,191,36,0.3)" stroke-width="0.8"></rect><text x="300" y="215" text-anchor="middle" fill="#fbbf24" font-size="10">/Volumes/DB_STORAGE (4TB)</text><line x1="300" y1="225" x2="300" y2="255" stroke="rgba(107,76,153,0.3)" stroke-width="0.8" stroke-dasharray="3 3"></line><rect x="200" y="255" width="200" height="30" rx="8" fill="rgba(167,139,250,0.1)" stroke="rgba(167,139,250,0.4)" stroke-width="1"></rect><text x="300" y="275" text-anchor="middle" fill="#a78bfa" font-size="10" font-weight="600">Neo4j KG (<tspan data-kg-stat="nodes" data-kg-fmt="k">583K</tspan>+ nodes)</text></svg></div></section><footer class="page-footer"><a href="/" class="back-link">← Home</a><a href="/explore" class="back-link">Explore KG →</a></footer></div></body></html><script type="module">var e=new IntersectionObserver(t=>{t.forEach(t=>{t.isIntersecting&&(t.target.classList.add(`visible`),e.unobserve(t.target))})},{threshold:0,rootMargin:`0px 0px 50px 0px`});document.querySelectorAll(`.fade-in`).forEach(t=>e.observe(t)),setTimeout(()=>document.querySelectorAll(`.fade-in:not(.visible)`).forEach(e=>e.classList.add(`visible`)),1500);</script><script src="/js/kg-live.js" defer></script>