| <!DOCTYPE html> |
| <html lang="th"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>ROGLAG · Tech Stack</title> |
| <link rel="preconnect" href="https://fonts.googleapis.com"> |
| <link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&family=IBM+Plex+Sans+Thai:wght@400;500;600;700&display=swap" rel="stylesheet"> |
| <style> |
| :root{--bg:#0b0f17;--panel:#121826;--panel2:#0f1420;--line:#1f2a3d;--txt:#e6edf6; |
| --muted:#aab8cc;--accent:#4da3ff;--accent2:#a78bfa;--teal:#5eead4;--ok:#34d399;--warn:#fbbf24;--crit:#f87171;--code:#0a0e16; |
| --hair:rgba(148,163,184,0.18);} |
| *{box-sizing:border-box}html{scroll-behavior:smooth} |
| body{margin:0;background-color:#0b0f17;background:radial-gradient(1200px 600px at 80% -10%,#15203a 0%,var(--bg) 55%); |
| color:var(--txt);font-family:"IBM Plex Sans Thai",-apple-system,"Segoe UI",sans-serif;line-height:1.65;font-size:16px} |
| .wrap{max-width:1060px;margin:0 auto;padding:32px 22px 96px} |
| header.hero{border:1px solid var(--line);border-radius:18px;padding:26px 30px; |
| background:linear-gradient(135deg,#13203a,#0f1420);margin-bottom:14px} |
| .hero h1{margin:0 0 6px;font-size:32px}.hero p{margin:0;color:var(--muted)} |
| .chips{display:flex;gap:8px;flex-wrap:wrap;margin-top:14px} |
| .chip{font-size:13px;padding:5px 11px;border:1px solid var(--line);border-radius:999px;background:#16203250;color:var(--teal)} |
| nav.toc{position:sticky;top:0;z-index:5;backdrop-filter:blur(8px);background:#0b0f17cc; |
| border:1px solid var(--line);border-radius:14px;padding:12px 16px;margin:18px 0 26px;display:flex;gap:14px;flex-wrap:wrap} |
| nav.toc a{color:var(--muted);text-decoration:none;font-size:13px}nav.toc a:hover{color:var(--accent)} |
| section{border:1px solid var(--line);border-radius:16px;padding:24px 26px;background:var(--panel);margin-bottom:22px} |
| h2{font-size:22px;margin:0 0 10px;display:flex;align-items:center;gap:10px} |
| h3{font-size:16px;margin:20px 0 8px;color:var(--accent)} |
| .sub{color:var(--muted);margin:2px 0 16px;font-size:13px} |
| small{font-size:12px;color:var(--muted)} |
| code{background:var(--code);border:1px solid var(--line);border-radius:6px;padding:1px 6px;font-size:13px;color:#cfe3ff; |
| font-family:"IBM Plex Mono",ui-monospace,monospace} |
| table{width:100%;border-collapse:collapse;margin:12px 0;font-size:13px} |
| th,td{border:1px solid var(--line);padding:9px 12px;text-align:left;vertical-align:top} |
| th{background:var(--panel2);color:var(--accent)} |
| td b{color:#fff} |
| .ver{color:var(--teal);font-family:"IBM Plex Mono",ui-monospace,monospace;font-size:13px} |
| .flow{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin:14px 0;font-size:13px} |
| .node{border:1px solid var(--line);background:var(--panel2);border-radius:10px;padding:8px 12px} |
| .arrow{color:var(--accent2);font-weight:700} |
| .callout{border:1px solid var(--hair);background:#0e1a2e;border-radius:10px;padding:12px 16px;margin:14px 0;font-size:13px} |
| .callout.warn{background:#241d0e} |
| .tag{display:inline-block;font-size:13px;padding:2px 8px;border-radius:999px;margin-left:6px} |
| .t-now{background:#0e2a1e;color:var(--ok);border:1px solid #1c4b36} |
| .t-prod{background:#241a2e;color:#c4a3ff;border:1px solid #3d2c4b} |
| ul{margin:8px 0 8px 4px;padding-left:20px}li{margin:4px 0} |
| footer{color:var(--muted);text-align:center;font-size:13px;margin-top:30px} |
| </style> |
| </head> |
| <body> |
| <div class="wrap"> |
| <header class="hero"> |
| <h1>🧱 ROGLAG · Tech Stack</h1> |
| <p>สแตกจริงของระบบ Security Log RAG + Realtime Threat Console</p> |
| <div class="chips"> |
| <span class="chip">Python 3.12</span><span class="chip">stdlib http.server</span> |
| <span class="chip">Vanilla JS</span><span class="chip">Three.js</span> |
| <span class="chip">Rule + RAG</span><span class="chip">FastAPI</span> |
| <span class="chip">SQLAlchemy</span><span class="chip">Docker</span><span class="chip">OpenRouter</span> |
| </div> |
| <p style="margin-top:14px;font-size:13px;color:var(--muted)"> |
| <span class="tag t-now">NOW</span> ที่รันอยู่จริงในเดโม่ · |
| <span class="tag t-prod">PROD</span> สแตกระดับ production ที่อยู่ใน repo เดียวกัน |
| </p> |
| </header> |
|
|
| <nav class="toc"> |
| <a href="#arch">สถาปัตยกรรม</a><a href="#fe">Frontend</a><a href="#be">Backend</a> |
| <a href="#detect">Detection & RAG</a><a href="#data">Data & Generator</a> |
| <a href="#prod">Production stack</a><a href="#ext">External</a><a href="#full">สรุปทั้งหมด</a> |
| </nav> |
|
|
| <section id="arch"> |
| <h2>ภาพรวมสถาปัตยกรรม</h2> |
| <p class="sub">เดโม่ปัจจุบันเน้น zero-dependency รันได้ทันที, แต่ใน repo มีสแตก production พร้อมไปต่อ</p> |
| <div class="flow"> |
| <span class="node">Log sources<br><small>auth/nginx/fw/system</small></span><span class="arrow">→</span> |
| <span class="node">Generator / CSV<br><small>ingest</small></span><span class="arrow">→</span> |
| <span class="node">Rule classifier<br><small>detect_rule</small></span><span class="arrow">→</span> |
| <span class="node">In-memory index<br><small>TF-IDF + vector</small></span><span class="arrow">→</span> |
| <span class="node">HTTP/JSON API</span><span class="arrow">→</span> |
| <span class="node">Dashboard<br><small>vanilla JS</small></span> |
| </div> |
| <div class="callout"> |
| เดโม่ใช้ <b>Python stdlib ล้วน</b> (ไม่ต้องลง dependency) เก็บ log ใน memory + ตอบ JSON API; ส่วน production ใช้ FastAPI + SQLAlchemy + Docker (หัวข้อ 6) |
| </div> |
| </section> |
|
|
| <section id="fe"> |
| <h2>Frontend <span class="tag t-now">NOW</span></h2> |
| <p class="sub">หน้าเดียว ไม่มี build step: โหลดเร็ว แก้ง่าย</p> |
| <table> |
| <tr><th>ส่วน</th><th>ใช้</th><th>หมายเหตุ</th></tr> |
| <tr><td><b>Markup/Logic</b></td><td>HTML5 + Vanilla JavaScript (ES2020+)</td><td>ไฟล์เดียว <code>web/index.html</code> ไม่มี framework/bundler</td></tr> |
| <tr><td><b>3D Globe</b></td><td>Three.js <span class="ver">0.160.0</span> (CDN)</td><td>WebGL globe + arcs + particles ในหน้า Overview</td></tr> |
| <tr><td><b>Charts</b></td><td>SVG เขียนเอง</td><td>Threat activity graph (เส้น risk + bar severity) ไม่ใช้ chart lib</td></tr> |
| <tr><td><b>Realtime monitor</b></td><td>Polling (fetch + setInterval)</td><td>tail-f log monitor, sort by time, ดึง events จาก ingest API</td></tr> |
| <tr><td><b>Styling</b></td><td>CSS เขียนเอง (custom properties)</td><td>dark theme, ไม่มี Tailwind/Bootstrap</td></tr> |
| <tr><td><b>Fonts</b></td><td>IBM Plex Mono + system fonts</td><td>โทน console/SOC</td></tr> |
| </table> |
| </section> |
|
|
| <section id="be"> |
| <h2>Backend เดโม่ <span class="tag t-now">NOW</span></h2> |
| <p class="sub"><code>server.py</code>: stdlib ล้วน ไม่มี dependency ภายนอก</p> |
| <table> |
| <tr><th>ส่วน</th><th>ใช้</th><th>หมายเหตุ</th></tr> |
| <tr><td><b>Runtime</b></td><td>Python <span class="ver">3.12</span> (รองรับ 3.10+)</td><td>ใช้ type hints แบบ PEP 604</td></tr> |
| <tr><td><b>HTTP server</b></td><td><code>http.server.ThreadingHTTPServer</code></td><td>stdlib, multithread, ไม่มี framework</td></tr> |
| <tr><td><b>Storage</b></td><td>In-memory (Python lists/dicts)</td><td>โหลด JSONL เข้า RAM ตอน start + append สดผ่าน <code>add_rows()</code></td></tr> |
| <tr><td><b>Vector store</b></td><td>SQLite <span class="ver">(stdlib sqlite3)</span></td><td><code>lograg_vectors.sqlite</code> เก็บ float32 embedding</td></tr> |
| <tr><td><b>HTTP client</b></td><td><code>urllib.request</code></td><td>เรียก OpenRouter โดยไม่ต้องลง requests</td></tr> |
| </table> |
| <h3>API endpoints</h3> |
| <table> |
| <tr><th>Method</th><th>Path</th><th>หน้าที่</th></tr> |
| <tr><td>GET</td><td><code>/api/health · /api/stats · /api/logs · /api/alerts</code></td><td>dashboard data</td></tr> |
| <tr><td>POST</td><td><code>/api/search · /api/ask</code></td><td>RAG retrieval + Q&A</td></tr> |
| <tr><td>POST</td><td><code>/api/mock/emit</code></td><td>ยิง mock log realtime (คืน events)</td></tr> |
| <tr><td>POST</td><td><code>/api/ingest/csv</code></td><td>อัปโหลด CSV → classify</td></tr> |
| <tr><td>GET</td><td><code>/api/generate/csv</code></td><td>สร้าง CSV ใหม่ (unseeded)</td></tr> |
| </table> |
| </section> |
|
|
| <section id="detect"> |
| <h2>Detection & RAG <span class="tag t-now">NOW</span></h2> |
| <table> |
| <tr><th>ส่วน</th><th>ใช้</th><th>หมายเหตุ</th></tr> |
| <tr><td><b>Classifier</b></td><td>Rule-based (regex patterns)</td><td><code>detect_rule()</code> → 7 categories + MITRE ATT&CK + risk score, ทำงานออฟไลน์</td></tr> |
| <tr><td><b>Keyword retrieval</b></td><td>TF-IDF เขียนเอง (postings + idf)</td><td>query expansion ไทย/อังกฤษ, ไม่ใช้ search engine</td></tr> |
| <tr><td><b>Vector retrieval</b></td><td>cosine similarity (SQLite blobs)</td><td>optional, ใช้เมื่อมี index + API key</td></tr> |
| <tr><td><b>Embeddings</b></td><td>OpenRouter <span class="ver">nvidia/llama-nemotron-embed</span></td><td>optional; fallback keyword เสมอ</td></tr> |
| <tr><td><b>LLM answer</b></td><td>OpenRouter (<span class="ver">openrouter/free</span>)</td><td>optional; มี local rule-based summary สำรอง</td></tr> |
| </table> |
| <div class="callout warn">ทุกชั้นมี fallback: vector → keyword → rule-based local answer → ระบบไม่ล่มแม้ไม่มี API key</div> |
| </section> |
|
|
| <section id="data"> |
| <h2>Data & Generator <span class="tag t-now">NOW</span></h2> |
| <table> |
| <tr><th>ส่วน</th><th>ใช้</th><th>หมายเหตุ</th></tr> |
| <tr><td><b>Dataset</b></td><td>JSONL (synthetic security logs)</td><td>10k / 50k records, 7 categories</td></tr> |
| <tr><td><b>Generator</b></td><td>Python (<code>app/generator.py</code>)</td><td>สุ่มไม่ซ้ำทุกครั้ง (unseeded), profile: mixed/attack/realistic</td></tr> |
| <tr><td><b>CSV I/O</b></td><td><code>csv</code> stdlib</td><td>generate + ingest ผ่าน DictReader/DictWriter</td></tr> |
| <tr><td><b>Categories</b></td><td>brute_force, port_scan, web_attack, priv_esc, data_exfil, c2_beacon, benign</td><td>map → MITRE + runbook</td></tr> |
| </table> |
| </section> |
|
|
| <section id="prod"> |
| <h2>Production stack <span class="tag t-prod">PROD</span></h2> |
| <p class="sub">อยู่ใน repo เดียวกัน (<code>app/</code> + Docker) สำหรับ deploy จริง / self-host เต็มรูปแบบ</p> |
| <table> |
| <tr><th>ชั้น</th><th>ใช้</th><th>เวอร์ชัน</th></tr> |
| <tr><td><b>Web framework</b></td><td>FastAPI</td><td class="ver">0.115.6</td></tr> |
| <tr><td><b>ASGI server</b></td><td>Uvicorn (standard)</td><td class="ver">0.34.0</td></tr> |
| <tr><td><b>ORM / DB toolkit</b></td><td>SQLAlchemy (async)</td><td class="ver">2.0.36</td></tr> |
| <tr><td><b>DB driver</b></td><td>asyncpg (Postgres) / aiosqlite (SQLite)</td><td class="ver">0.30.0 / 0.20.0</td></tr> |
| <tr><td><b>HTTP client</b></td><td>httpx (async)</td><td class="ver">0.28.1</td></tr> |
| <tr><td><b>File upload</b></td><td>python-multipart</td><td class="ver">0.0.20</td></tr> |
| <tr><td><b>Realtime</b></td><td>WebSocket (FastAPI native)</td><td>fan-out broadcast in-process</td></tr> |
| <tr><td><b>Database</b></td><td>PostgreSQL 16 / SQLite</td><td>portable ด้วย <code>DATABASE_URL</code></td></tr> |
| <tr><td><b>Container</b></td><td>Docker + docker-compose</td><td>python:3.12-slim, postgres:16-alpine</td></tr> |
| </table> |
| </section> |
|
|
| <section id="ext"> |
| <h2>External / Optional services</h2> |
| <table> |
| <tr><th>บริการ</th><th>ใช้ทำอะไร</th><th>สถานะ</th></tr> |
| <tr><td><b>OpenRouter</b></td><td>LLM answer + embeddings</td><td>optional (มี local fallback)</td></tr> |
| <tr><td><b>Qdrant</b></td><td>vector DB สำหรับ production RAG</td><td>optional (ตั้งผ่าน env)</td></tr> |
| <tr><td><b>n8n</b></td><td>automation: alert → enrich → ticket/notify</td><td>แนะนำใน plan</td></tr> |
| <tr><td><b>Vercel</b></td><td>deploy static + Python serverless (<code>api/*.py</code>)</td><td>มี <code>vercel.json</code></td></tr> |
| </table> |
| </section> |
|
|
| <section id="full"> |
| <h2>สรุป Full Stack</h2> |
| <table> |
| <tr><th>Layer</th><th>เดโม่ (NOW)</th><th>Production (PROD)</th></tr> |
| <tr><td><b>Frontend</b></td><td>Vanilla JS + Three.js + SVG</td><td>เหมือนเดิม (เพิ่ม WebSocket realtime)</td></tr> |
| <tr><td><b>Backend</b></td><td>stdlib http.server</td><td>FastAPI + Uvicorn</td></tr> |
| <tr><td><b>Storage</b></td><td>In-memory + SQLite</td><td>PostgreSQL (SQLAlchemy async)</td></tr> |
| <tr><td><b>Realtime</b></td><td>Polling</td><td>WebSocket</td></tr> |
| <tr><td><b>Retrieval</b></td><td>TF-IDF + SQLite vector</td><td>Qdrant / pgvector</td></tr> |
| <tr><td><b>Detection</b></td><td>Rule-based (regex + MITRE)</td><td>เหมือนเดิม + ML ในอนาคต</td></tr> |
| <tr><td><b>LLM</b></td><td>OpenRouter (optional)</td><td>OpenRouter / self-host Ollama</td></tr> |
| <tr><td><b>Deploy</b></td><td>รันตรง <code>python3 server.py</code></td><td>Docker Compose / Vercel</td></tr> |
| <tr><td><b>Automation</b></td><td>ไม่มี</td><td>n8n workflows</td></tr> |
| </table> |
| <div class="callout">ปรัชญา: <b>เดโม่ต้องรันได้ทันทีแบบ zero-dependency และออฟไลน์</b> แล้วค่อยสเกลขึ้น production ด้วยสแตกที่เตรียมไว้ในโปรเจกต์เดียวกัน</div> |
| </section> |
|
|
| <footer>ROGLAG · Tech Stack · ดู <a href="/plan" style="color:var(--accent)">/plan</a> สำหรับแผนยกระดับ production</footer> |
| </div> |
| </body> |
| </html> |
|
|