diff --git a/scripts/build_docs.py b/scripts/build_docs.py
new file mode 100644
index 0000000..2445ca9
--- /dev/null
+++ b/scripts/build_docs.py
@@ -0,0 +1,238 @@
+#!/opt/homebrew/bin/python3.11
+"""Build HTML documentation from module source files."""
+import os, markdown, re, glob, shutil
+
+MODULES_DIR = os.path.join(os.path.dirname(__file__), "..", "docs_v1.0", "API_WORKSPACE", "modules")
+DOC_DIR = os.path.join(os.path.dirname(__file__), "..", "docs_v1.0", "doc")
+DOC_DEV_DIR = os.path.join(os.path.dirname(__file__), "..", "docs_v1.0", "doc_developer")
+
+# User-facing modules (no developer content)
+USER_MODULES = {
+ "01_auth", "02_health", "03_register", "04_lookup", "05_process",
+ "06_search", "07_identity", "08_identity_agent", "08_media",
+ "09_tmdb", "10_pipeline", "12_agent",
+}
+
+
+def md_to_html(md_text: str) -> str:
+ """Convert Markdown to HTML."""
+ html = markdown.markdown(md_text, extensions=['fenced_code', 'tables', 'codehilite'])
+ # Wrap tables
+ html = re.sub(r'
', '', html)
+ return html
+
+def build_index(files, dev=False):
+ """Build index.html."""
+ links = []
+ for fname in sorted(files):
+ name = os.path.splitext(fname)[0]
+ label = MODULE_LABELS.get(name, name.replace("_", " ").title())
+ if "|" in label:
+ cn, en = label.split("|", 1)
+ else:
+ cn, en = label, ""
+ html_name = fname.replace(".md", ".html")
+ links.append(f'| {cn} | {en} |
')
+
+ title = "Momentry API 開發者文件" if dev else "Momentry API 文件"
+ subtitle = "開發者專用" if dev else "API 參考手冊 — 登入後可瀏覽各模組文件"
+
+ return f"""
+
+
+
+{title}
+
+
+
+
+
+"""
+
+MODULE_LABELS = {
+ "01_auth": "安全認證|Authentication",
+ "02_health": "健康檢查|Health",
+ "03_register": "檔案註冊|File Registration",
+ "04_lookup": "檔案屬性查詢|File Lookup",
+ "05_process": "處理流程|Processing",
+ "06_search": "搜尋功能|Search",
+ "07_identity": "身份識別|Identity",
+ "08_identity_agent": "智能身份綁定|Smart Identity Binding",
+ "08_media": "串流與截圖|Streaming & Thumbnails",
+ "09_tmdb": "TMDb 整合|TMDb Integration",
+ "10_pipeline": "生產線|Pipeline",
+ "11_error_codes": "錯誤碼|Error Codes",
+ "12_agent": "智慧代理|AI Agents",
+}
+
+def build_html(md_text: str, title: str) -> str:
+ """Wrap MD content in HTML page."""
+ content = md_to_html(md_text)
+ return f"""
+
+
+
+{title} - Momentry API Docs
+
+
+
+
+
+"""
+
+def login_page() -> str:
+ return """
+
+
+
+Login - Momentry Docs
+
+
+
+
+
+
+"""
+
+def main():
+ # Clean and recreate doc dirs
+ for d in [DOC_DIR, DOC_DEV_DIR]:
+ if os.path.exists(d):
+ shutil.rmtree(d)
+ os.makedirs(d)
+
+ md_files = sorted(glob.glob(os.path.join(MODULES_DIR, "*.md")))
+ if not md_files:
+ print(f"No MD files found in {MODULES_DIR}")
+ return
+
+ user_html = []
+ dev_html = []
+ for md_path in md_files:
+ with open(md_path) as f:
+ md_text = f.read()
+ fname = os.path.basename(md_path)
+ stem = os.path.splitext(fname)[0]
+
+ # Skip template
+ if stem == "_template":
+ continue
+
+ # Skip error codes (developer-only)
+ if stem == "11_error_codes":
+ dev_only = True
+ else:
+ dev_only = stem not in USER_MODULES
+
+ title = stem.replace("_", " ").title()
+ html = build_html(md_text, title)
+
+ if dev_only:
+ out_path = os.path.join(DOC_DEV_DIR, fname.replace(".md", ".html"))
+ with open(out_path, "w") as f:
+ f.write(html)
+ dev_html.append(fname)
+ print(f" [dev] {fname}")
+ else:
+ out_path = os.path.join(DOC_DIR, fname.replace(".md", ".html"))
+ with open(out_path, "w") as f:
+ f.write(html)
+ user_html.append(fname)
+ print(f" [doc] {fname}")
+
+ # Build indexes + login page
+ for d, files, label in [(DOC_DIR, user_html, "User"), (DOC_DEV_DIR, dev_html, "Dev")]:
+ index = build_index(files)
+ with open(os.path.join(d, "index.html"), "w") as f:
+ f.write(index)
+ with open(os.path.join(d, "login.html"), "w") as f:
+ f.write(login_page())
+ print(f" {label}: {len(files)} pages -> {d}")
+
+if __name__ == "__main__":
+ main()