690529:1702 ADR-030-230 context aware #09
CI / CD Pipeline / build (push) Successful in 4m53s
CI / CD Pipeline / deploy (push) Failing after 2m16s

This commit is contained in:
2026-05-29 17:02:12 +07:00
parent 8367ced926
commit f33487f511
9 changed files with 1774 additions and 12 deletions
@@ -1,29 +1,47 @@
# ADR-031: NAP-DMS Integration Strategy (Hermes Agent & Telegram Bridge)
# ADR-031: Hermes Agent — Autonomous Dev Orchestrator & Telegram DevOps Bridge (v2.0)
## Status
- **Status:** Draft
- **Date:** 2026-05-28
- **Version:** 2.0 (2026-05-29 — grill-with-docs: Orchestration as primary concern)
- **Deciders:** NAP-DMS Architecture Team
- **Supersedes:** ADR-031 v1.1 (DevOps Bridge only)
### Locked Decisions During Grill
### Locked Decisions (v1.x — DevOps Bridge Foundation)
ข้อตกลงด้านล่างถูกล็อคระหว่าง grill session แล้ว แต่ ADR-031 ยังอยู่ในสถานะ Draft จนกว่า scope และ rollout plan จะ stable:
ข้อตกลงด้านล่างถูกล็อคตั้งแต่ v1.x และยังคงบังคับใช้ใน v2.0:
* **Hermes role:** Hermes เป็น Developer Operations Agent / Integration Assistant เท่านั้น ไม่ใช่ production DMS service และไม่ใช่ AI inference boundary ของ DMS
* **Database access:** Hermes เชื่อม MariaDB ได้เฉพาะ read-only account หรือ read-only replica สำหรับ schema inspection, metadata diagnostics, และ query verification เท่านั้น
* **Document storage:** Hermes ห้าม mount, browse, หรืออ่าน permanent document storage ของ production โดยตรง หากต้องตรวจเอกสารจริงต้องผ่าน DMS Backend API
* **Hermes role:** Hermes เป็น Developer Operations Agent / Autonomous Dev Orchestrator ไม่ใช่ production DMS service และไม่ใช่ AI inference boundary ของ DMS
* **Database access:** Hermes เชื่อม MariaDB ได้เฉพาะ read-only account สำหรับ schema inspection, metadata diagnostics เท่านั้น
* **Document storage:** Hermes ห้าม mount, browse, หรืออ่าน permanent document storage ของ production โดยตรง
* **Telegram scope:** Hermes Telegram ใช้สำหรับ DevOps commands เท่านั้น ไม่ใช่ production DMS command channel
* **DMS Telegram:** Telegram command สำหรับ query/mutate เอกสารจริงเป็น future separate ADR/spec และต้อง enforce ADR-009/016/019/023A
* **Hermes proxy:** `hermes proxy` เป็น Developer AI Proxy only สำหรับ coding/devops assistance ไม่ใช่ DMS AI runtime หรือ document intelligence path
* **Telegram writes:** Telegram write actions ต้องมี explicit confirmation; forbidden actions เช่น push ไป `main`/`master`, production deploy, schema migration execution, direct DB writes, และ storage delete ห้ามทำผ่าน Telegram
* **Schema rollout:** ADR-031 rollout ไม่เพิ่มหรือแก้ production DMS schema รวมถึงไม่สร้าง `user_telegram_mapping`
* **DMS Telegram:** Telegram command สำหรับ query/mutate เอกสารจริงเป็น future separate ADR/spec
* **Hermes proxy:** `hermes proxy` เป็น Developer AI Proxy only ไม่ใช่ DMS AI runtime
* **Telegram writes:** ต้องมี explicit confirmation; push `main`/`master`, production deploy, schema migration, direct DB writes, storage delete ห้ามทุกกรณี
* **Schema rollout:** ADR-031 ไม่เพิ่มหรือแก้ production DMS schema
### Locked Decisions (v2.0 — Orchestration Layer)
ข้อตกลงใหม่จาก grill session 2026-05-29:
* **Cloud AI Exception:** Hermes Orchestrator layer อนุญาต Cloud AI API (Claude/GPT-4o) ได้ — เป็น exception จาก ADR-023A ที่ใช้เฉพาะ DevOps/Dev Orchestration layer เท่านั้น ไม่ใช่ DMS document processing
* **Data Classification (Dev-Out Policy):** Code, Config, ADR, Stack trace ส่ง Cloud AI ได้ — Production runtime data จาก DB query (document content, user info, project business data) ห้ามส่งออกทุกกรณี
* **Dev Qdrant:** Separate Qdrant instance บน ASUSTOR สำหรับ codebase embedding โดยเฉพาะ — ห้ามใช้ Qdrant instance เดียวกับ DMS document RAG (ADR-023A)
* **SOUL.md:** Hermes working journal อยู่ใน container เท่านั้น (`/volume1/docker/hermes/SOUL.md`) ไม่ sync กลับ repo
* **Context Source:** Hermes ดึง project context จาก `specs/06-Decision-Records/CONTEXT-ADR-031.md` + `AGENTS.md` โดยตรง ไม่ใช้ Obsidian หรือ external knowledge base
* **Sub-agent Delegation:** Hermes orchestrate โดย (1) Cloud sub-agents ใช้ model เล็กกว่า (Claude Haiku/GPT-4o-mini) สำหรับ code generation tasks และ (2) MCP invocations ไปยัง Windsurf/agy ที่มีอยู่แล้ว
* **Git Identity:** Hermes ใช้ Gitea service account (`hermes-bot`) push เฉพาะ `hermes/*` branches — ห้าม push ตรง `main`/`develop` ทุกกรณี — ทุก change ต้องผ่าน PR ที่ human approve
## Context
การตั้งค่าระบบ **Hermes Agent** ในโปรเจกต์ **NAP-DMS (LCBP3)**วอร์ชัน 1.9.0 เพื่อเชื่อมต่อกับโครงสร้างพื้นฐานเดิมและขยายขีดความสามารถผ่าน Telegram Bridge สำหรับการแจ้งเตือนและการสั่งงานผ่านระบบ Command
การตั้งค่าระบบ **Hermes Agent** ในโปรเจกต์ **NAP-DMS (LCBP3)**พื่อทำหน้าที่เป็น **Autonomous Development Loop Orchestrator** — ควบคุมงาน AI Coding ทั้งหมด วาง Roadmap จ่ายงานให้ sub-agents ตรวจสอบผลลัพธ์ และสร้าง PR สำหรับ human review
Hermes Agent ถูกนิยามเป็น **Developer Operations Agent / Integration Assistant** สำหรับงานพัฒนา, ตรวจสอบ, ประสานเครื่องมือ, และช่วยสั่งงาน DevOps เท่านั้น ไม่ใช่ production DMS service และไม่ใช่ AI inference boundary ของ DMS ตาม ADR-023/ADR-023A
ใน v2.0 Hermes มี 2 primary roles:
1. **Autonomous Dev Orchestrator** (primary) — คุม development loop ตั้งแต่ requirement จนถึง PR
2. **Telegram DevOps Bridge** (subsystem) — DevOps commands, CI status, Gitea notifications
Hermes ไม่ใช่ production DMS service และไม่ใช่ DMS AI inference boundary (ADR-023/ADR-023A) แต่ได้รับ **Cloud AI exception** สำหรับ dev orchestration layer โดยเฉพาะ พร้อม Data Classification Policy ที่ชัดเจน
## Decision
@@ -58,6 +76,166 @@ Hermes Agent ถูกนิยามเป็น **Developer Operations Agent /
---
## Orchestration Architecture (v2.0 — Primary Concern)
### Overview: Autonomous Development Loop
Hermes ทำหน้าที่เป็น "Lead Developer" / "Conductor" ที่คุม development loop ทั้งหมด โดยไม่ลงไปเขียนโค้ดทุกบรรทัดเอง แต่วางแผน จ่ายงาน ตรวจสอบผลลัพธ์ และสร้าง PR:
```
[Developer / Telegram Command]
┌─────────────────────────────────────────┐
│ Hermes Orchestrator (Flagship Cloud AI) │
│ Claude / GPT-4o │
│ Context: CONTEXT-ADR-031.md + AGENTS.md │
│ Memory: SOUL.md (container-local) │
│ Search: Dev Qdrant (ASUSTOR) │
└──────────┬──────────────────────────────┘
┌───────┴────────┐
▼ ▼
[Cloud Sub-agents] [MCP Tool Invocations]
Claude Haiku / Windsurf / agy / Codex
GPT-4o-mini (existing tools, no new models)
│ ▼
└────────┬───────
[Self-Correction Loop]
npm run lint / jest / tsc
→ Error? Re-delegate to sub-agent
→ Pass? Continue
[Git: hermes/* branch]
hermes-bot commits
Creates PR → Human Review & Approve
```
### Step 1: Requirement & Context Assembly
Hermes โหลด context แบบ **selective** ตาม task type เพื่อลด token ที่ส่งไป Cloud AI:
| Task Type | Context ที่โหลด |
|-----------|----------------|
| DevOps / CI / Git | `CONTEXT-ADR-031.md` + `AGENTS.md` |
| DMS feature coding | `CONTEXT-ADR-031.md` + `AGENTS.md` + `CONTEXT.md` |
| Schema / DB work | `CONTEXT-ADR-031.md` + `AGENTS.md` + `CONTEXT.md` + schema SQL (read-only) |
| Bug fix / refactor | `CONTEXT-ADR-031.md` + `AGENTS.md` + Dev Qdrant (code patterns) |
**Sources:**
- `specs/06-Decision-Records/CONTEXT-ADR-031.md` — agent rules, project identity, tooling, infra paths
- `CONTEXT.md` (root) — domain terminology (Correspondence, RFA, Workflow Engine, AI concepts) — โหลดเฉพาะ DMS feature tasks
- `AGENTS.md` — TypeScript rules, forbidden patterns (no `any`, no `parseInt` on UUID), ADR references
- Dev Qdrant (ASUSTOR) — semantic code search หา reference patterns จาก codebase embeddings
**ห้ามดึง** production runtime data (DB query results, document content, user data) เข้า cloud AI context
### Step 2: Semantic Code Search (Dev Qdrant)
Hermes ใช้ Qdrant instance แยก (บน ASUSTOR, ไม่ใช่ DMS Qdrant) ทำ semantic search หา reference patterns ใน codebase:
```yaml
# docker-compose.hermes-qdrant.yml (ASUSTOR — แยกจาก DMS)
services:
hermes-qdrant:
image: qdrant/qdrant:latest
container_name: hermes-qdrant
volumes:
- hermes_qdrant_data:/qdrant/storage
ports:
- "6334:6333" # port แยกจาก DMS Qdrant (:6333)
deploy:
resources:
limits:
memory: 2G
```
Collection: `lcbp3_code_chunks` — indexed by `repoName` + `moduleName` (ไม่ใช่ `projectPublicId` ซึ่งเป็น DMS document isolation)
### Step 3: Sub-agent Delegation
Hermes แตกงานเป็น tasks แล้ว delegate ผ่าน 2 channels:
**Channel A — Cloud Sub-agents (Code Generation):**
```
Orchestrator (Claude/GPT-4o)
→ "เขียน NestJS service สำหรับ X"
→ Sub-agent (Claude Haiku / GPT-4o-mini)
→ Returns code diff
→ Orchestrator validates against AGENTS.md rules
```
**Channel B — MCP Tool Invocations (File Execution):**
```
Orchestrator
→ MCP hermes-tools: bash/git operations บน ASUSTOR
→ MCP mariadb: schema lookup (read-only)
→ MCP gitea: PR/issue management
→ Triggers Windsurf/agy ถ้า complex scaffolding needed
```
**Data Classification Enforcement:**
| ส่งได้ | ห้ามส่ง |
|--------|---------|
| Code snippets, patterns | Production DB query results |
| ADR/spec content | Document content (title, body) |
| Stack traces, error output | User data, project names from DB |
| Config files, tsconfig | API keys, tokens, passwords |
| Schema structure (column names) | Storage paths ที่มี PII |
### Step 4: Self-Correction Loop
โค้ดที่ sub-agent ส่งกลับมาต้องผ่าน validation ก่อนใช้:
```bash
# Hermes runs via MCP hermes-tools
npm run lint # ESLint — ต้องผ่านทุก rule
npx tsc --noEmit # TypeScript strict mode
npm test -- --passWithNoTests # Jest tests ที่เกี่ยวข้อง
```
ถ้าพบ error → Hermes วิเคราะห์ output → ส่งกลับให้ sub-agent แก้ไข (max 3 iterations)
ถ้า iteration > 3 → หยุดและแจ้ง developer ผ่าน Telegram
### Step 5: Git Identity & PR Flow
```
hermes-bot commits → hermes/feat-{task-id} branch
├─ git config user.name "Hermes Bot"
├─ git config user.email "hermes-bot@np-dms.work"
├─ commit message: "feat(hermes): {task description}\n\nOrchestrated by Hermes ADR-031 v2.0"
└─ push → Gitea → Create PR → assign to developer
```
**Git Identity Rules:**
- Service account: `hermes-bot` (Gitea, least privilege, write token เฉพาะ feature branches)
- Branch pattern: `hermes/feat-*`, `hermes/fix-*`, `hermes/refactor-*`
- ห้าม push ตรง `main`, `develop`, `release/*` ทุกกรณี
- PR ต้องผ่าน CI (lint + test) ก่อน merge
- Human ต้อง review และ approve ก่อน merge เสมอ — ห้าม auto-merge
### SOUL.md — Hermes Working Journal
`/volume1/docker/hermes/SOUL.md` เก็บ per-session working memory ของ Hermes:
```markdown
## Session 2026-05-29T10:30
Task: scaffold correspondence search feature
Context loaded: CONTEXT-ADR-031.md, backend/src/modules/correspondence/
Sub-agents delegated: 2 code generation calls
Iterations: 1 (lint pass first try)
PR created: hermes/feat-correspondence-search → #142
Status: DONE
```
- ไม่ commit ลง repo — อยู่ใน container volume เท่านั้น
- Hermes อ่าน SOUL.md ต้น session เพื่อ resume context
- Rotate ทุก 30 วัน หรือ manual clear
---
## Implementation Details
### 1. Infrastructure Configuration
@@ -801,6 +979,7 @@ ADR-031 ต้อง rollout แบบเป็น stage เพื่อลด
- ADR-016: Security & Authentication
- ADR-019: Hybrid Identifier Strategy (UUIDv7)
- ADR-023/ADR-023A: Unified AI Architecture และ AI isolation boundary
- ADR-031 v2.0: Cloud AI exception สำหรับ Hermes dev orchestration layer (ดู Locked Decisions v2.0)
---
@@ -812,3 +991,5 @@ ADR-031 ต้อง rollout แบบเป็น stage เพื่อลด
| 2026-05-28 | 1.1.0 | Added sections 46 from CONTEXT-ADR-031-Added-2: Hermes Interface Modes, agy+Hermes MCP Integration, Deploy Prerequisites; fixed port conflict (hermes proxy :8766, not :8765) |
| 2026-05-29 | 1.1.1 | Aligned with CONTEXT-ADR-031.md grill-with-docs: fixed monorepo structure (flat layout), corrected file paths, updated repo URL to git.np-dms.work, added AGENTS.md v1.9.7 reference |
| 2026-05-29 | 1.1.2 | Linked root CONTEXT.md with specs/CONTEXT-ADR-031.md; fixed setup-context.sh paths; updated Windsurf/agy/Hermes symlink targets |
| 2026-05-29 | 2.0.0 | **v2.0 Rewrite** — grill-with-docs: Orchestration as primary concern; Added Autonomous Dev Loop architecture; Cloud AI exception (Data Classification Policy C); Separate Dev Qdrant on ASUSTOR; SOUL.md container-local journal; Sub-agent delegation (Cloud+MCP); Git identity hermes-bot + hermes/* branches + PR-only flow |
| 2026-05-29 | 2.0.1 | Step 1 context assembly: เพิ่ม `CONTEXT.md` (root domain terminology) เป็น selective context source สำหรับ DMS feature coding และ Schema/DB work tasks |
@@ -0,0 +1,38 @@
# Specification Quality Checklist: Hermes Agent — Autonomous Dev Orchestrator & Telegram DevOps Bridge
**Purpose**: Validate specification completeness and quality before proceeding to planning
**Created**: 2026-05-29
**Feature**: [spec.md](../spec.md)
## Content Quality
- [x] No implementation details (languages, frameworks, APIs)
- [x] Focused on user value and business needs
- [x] Written for non-technical stakeholders
- [x] All mandatory sections completed
## Requirement Completeness
- [x] No [NEEDS CLARIFICATION] markers remain (ADR-031 v2.0 provides all decisions locked)
- [x] Requirements are testable and unambiguous
- [x] Success criteria are measurable (SC-001 through SC-010)
- [x] Success criteria are technology-agnostic (no implementation details)
- [x] All acceptance scenarios are defined (US1US5, 5 scenarios each)
- [x] Edge cases are identified (10 edge cases)
- [x] Scope is clearly bounded (Out of Scope section present)
- [x] Dependencies and assumptions identified (Assumptions section present)
## Feature Readiness
- [x] All functional requirements have clear acceptance criteria (FR-001 through FR-020)
- [x] User scenarios cover primary flows (Orchestration, Telegram Read, Telegram Write, Proxy, Staged Rollout)
- [x] Feature meets measurable outcomes defined in Success Criteria
- [x] No implementation details leak into specification
## Notes
- Spec derived from ADR-031 v2.0 (2026-05-29) — Locked Decisions are authoritative
- Cloud AI exception scope clearly bounded to dev orchestration layer only
- Failure isolation (SC-004) is the most critical non-functional requirement
- Staged rollout (FR-015, SC-007) is prerequisite to any production deployment
- All items pass — spec is ready for clarification and planning phases
@@ -0,0 +1,339 @@
openapi: 3.0.3
info:
title: Hermes Agent API
description: |
Hermes Agent — Autonomous Dev Orchestrator & Telegram DevOps Bridge
Feature: 231-hermes-agent | ADR-031 v2.0
IMPORTANT:
- All endpoints are LAN/VPN-only (never public internet)
- Telegram webhook endpoint is the only exception (via reverse proxy with TLS)
- Authentication: X-API-Key header for all non-webhook endpoints
- All responses include transactionId for traceability
version: 1.0.0
contact:
name: NAP-DMS Architecture Team
servers:
- url: http://{ASUSTOR_IP}:8080/api/v1
description: Hermes Agent API (LAN/VPN only)
variables:
ASUSTOR_IP:
default: "192.168.10.X"
security:
- ApiKeyAuth: []
components:
securitySchemes:
ApiKeyAuth:
type: apiKey
in: header
name: X-API-Key
description: HERMES_PROXY_API_KEY — stored in ASUSTOR secret store
schemas:
TransactionId:
type: string
format: uuid
description: UUIDv7 transaction identifier (ADR-019)
example: "019505a1-7c3e-7000-8000-abc123def456"
HermesStatus:
type: object
properties:
status:
type: string
enum: [HEALTHY, DEGRADED, DOWN]
version:
type: string
uptime:
type: number
queues:
type: object
properties:
notification:
type: object
properties:
waiting: { type: number }
active: { type: number }
failed: { type: number }
orchestration:
type: object
properties:
waiting: { type: number }
active: { type: number }
failed: { type: number }
soulMdLastEntry:
type: string
description: ISO datetime of last SOUL.md session entry
timestamp:
type: string
format: date-time
OperationsLogEntry:
type: object
properties:
id:
$ref: '#/components/schemas/TransactionId'
operatorIdentity:
type: string
commandType:
type: string
enum: [TELEGRAM_INBOUND, TELEGRAM_OUTBOUND, ORCHESTRATION_TASK, GIT_WRITE, PROXY_REQUEST]
targetSystem:
type: string
commandSummary:
type: string
description: Redacted command description
status:
type: string
enum: [PENDING, IN_PROGRESS, COMPLETED, FAILED, REJECTED]
createdAt:
type: string
format: date-time
completedAt:
type: string
format: date-time
nullable: true
errorClassification:
type: string
nullable: true
OrchestrationTaskRequest:
type: object
required: [description, taskType, telegramChatId]
properties:
description:
type: string
description: Coding task description (no production data)
taskType:
type: string
enum: [DEVOPS, DMS_FEATURE, SCHEMA_DB, BUG_FIX]
telegramChatId:
type: string
description: Chat ID for progress/result notifications
OrchestrationTaskResponse:
type: object
properties:
taskId:
$ref: '#/components/schemas/TransactionId'
status:
type: string
enum: [QUEUED, CONTEXT_LOADING, SUB_AGENT_DELEGATED, SELF_CORRECTION, PR_CREATED, DONE, ESCALATED, FAILED]
prUrl:
type: string
nullable: true
description: Gitea PR URL (populated when status=PR_CREATED or DONE)
branchName:
type: string
nullable: true
TelegramWebhookPayload:
type: object
properties:
message:
type: object
properties:
from:
type: object
properties:
id: { type: integer }
username: { type: string }
text: { type: string }
chat:
type: object
properties:
id: { type: integer }
ErrorResponse:
type: object
properties:
error:
type: string
message:
type: string
transactionId:
$ref: '#/components/schemas/TransactionId'
paths:
/health:
get:
summary: Hermes health check
description: Returns current health status of Hermes Agent and its subsystems
security: []
operationId: getHealth
tags: [System]
responses:
'200':
description: Health status
content:
application/json:
schema:
$ref: '#/components/schemas/HermesStatus'
/telegram/webhook:
post:
summary: Telegram webhook inbound handler
description: |
Receives Telegram Bot webhook updates.
MUST be behind reverse proxy with TLS.
MUST verify X-Telegram-Bot-Api-Secret-Token header.
DevOps commands only — no DMS document operations.
security: []
operationId: handleTelegramWebhook
tags: [Telegram]
parameters:
- name: X-Telegram-Bot-Api-Secret-Token
in: header
required: true
schema:
type: string
description: Telegram webhook secret for request verification
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/TelegramWebhookPayload'
responses:
'200':
description: Webhook processed (command dispatched or acknowledged)
content:
application/json:
schema:
type: object
properties:
transactionId:
$ref: '#/components/schemas/TransactionId'
status:
type: string
enum: [DISPATCHED, REJECTED, ACKNOWLEDGED]
'401':
description: Invalid webhook secret token
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'429':
description: Rate limit exceeded
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/orchestration/tasks:
post:
summary: Submit autonomous coding task
description: |
Submit a coding task for Hermes to orchestrate via sub-agents.
NEVER include production document content, DB query results, or secrets in task description.
operationId: submitOrchestrationTask
tags: [Orchestration]
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/OrchestrationTaskRequest'
responses:
'202':
description: Task queued successfully
content:
application/json:
schema:
$ref: '#/components/schemas/OrchestrationTaskResponse'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/orchestration/tasks/{taskId}:
get:
summary: Get orchestration task status
operationId: getOrchestrationTask
tags: [Orchestration]
parameters:
- name: taskId
in: path
required: true
schema:
$ref: '#/components/schemas/TransactionId'
responses:
'200':
description: Task status
content:
application/json:
schema:
$ref: '#/components/schemas/OrchestrationTaskResponse'
'404':
description: Task not found
/operations/logs:
get:
summary: Query Hermes operations log
description: Returns paginated DevOps operations log entries. Admin only.
operationId: getOperationsLog
tags: [Operations]
parameters:
- name: limit
in: query
schema:
type: integer
default: 50
maximum: 200
- name: offset
in: query
schema:
type: integer
default: 0
- name: status
in: query
schema:
type: string
enum: [PENDING, IN_PROGRESS, COMPLETED, FAILED, REJECTED]
- name: commandType
in: query
schema:
type: string
responses:
'200':
description: Operations log entries
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/OperationsLogEntry'
total:
type: integer
offset:
type: integer
/operations/logs/{transactionId}:
get:
summary: Get specific operation by transactionId
description: Used by Telegram /status command to track DevOps transactions
operationId: getOperationByTransactionId
tags: [Operations]
parameters:
- name: transactionId
in: path
required: true
schema:
$ref: '#/components/schemas/TransactionId'
responses:
'200':
description: Operation details
content:
application/json:
schema:
$ref: '#/components/schemas/OperationsLogEntry'
'404':
description: Transaction not found
@@ -0,0 +1,149 @@
// File: specs/200-fullstacks/231-hermes-agent/data-model.md
// Change Log:
// - 2026-05-29: Initial data model for Hermes Agent
# Data Model: Hermes Agent
**Feature**: 231-hermes-agent | **Date**: 2026-05-29
> **Important**: Hermes ไม่เพิ่มหรือแก้ DMS production schema ทุกกรณี (ADR-031, FR-017)
> Data model นี้ทั้งหมดอยู่ใน **Hermes-owned storage** (SQLite / container volume) ไม่ใช่ DMS MariaDB
---
## 1. HermesOperationsLog (SQLite table: `hermes_operations_log`)
บันทึก inbound/outbound DevOps operations ทุก transaction ของ Hermes
| Field | Type | Constraints | Description |
|-------|------|-------------|-------------|
| `id` | TEXT (UUIDv7) | PRIMARY KEY | Transaction ID — ใช้ UUIDv7 ตาม ADR-019 |
| `operator_identity` | TEXT | NOT NULL | Telegram user ID หรือ CLI session identity |
| `command_type` | TEXT | NOT NULL | เช่น `TELEGRAM_INBOUND`, `TELEGRAM_OUTBOUND`, `ORCHESTRATION_TASK`, `GIT_WRITE` |
| `target_system` | TEXT | NOT NULL | เช่น `TELEGRAM`, `GITEA`, `CLOUD_AI`, `DEV_QDRANT` |
| `command_summary` | TEXT | NOT NULL | Redacted command description (ห้ามมี secret/token/sensitive path) |
| `status` | TEXT | NOT NULL | `PENDING` / `IN_PROGRESS` / `COMPLETED` / `FAILED` / `REJECTED` |
| `created_at` | DATETIME | NOT NULL DEFAULT CURRENT_TIMESTAMP | |
| `completed_at` | DATETIME | NULLABLE | |
| `error_classification` | TEXT | NULLABLE | เช่น `AUTH_FAILURE`, `RATE_LIMIT`, `FORBIDDEN_ACTION`, `EXTERNAL_API_ERROR` |
| `gitea_token_identity` | TEXT | NULLABLE | Token scope/identity สำหรับ Git write actions (ไม่ใช่ token value) |
| `target_repo` | TEXT | NULLABLE | สำหรับ Git write actions |
| `target_branch` | TEXT | NULLABLE | สำหรับ Git write actions |
**Retention**: 90 วัน แล้ว archive/delete ตาม DevOps log policy
**Access**: Read เฉพาะ admin/operator ที่จำเป็น
**Redaction**: `command_summary` ต้องผ่าน secret scanner ก่อน insert
---
## 2. HermesRateLimitState (Redis key pattern)
| Key Pattern | Value | TTL | Description |
|-------------|-------|-----|-------------|
| `hermes:telegram:{telegramUserId}` | INT (request count) | 60s | Rate limit counter per user; expire ทุก 60 วินาที |
---
## 3. HermesBullMQJobs (Redis via `hermes-notification-queue`)
### Job: `telegram-devops-outbound`
| Field | Type | Description |
|-------|------|-------------|
| `transactionId` | string (UUIDv7) | Reference ID for tracking |
| `chatId` | string | Telegram chat ID |
| `message` | string | Outbound message text (ไม่มี secret/PII) |
| `retryCount` | number | Current retry count (max 3) |
---
## 4. HermesOrchestrationTask (Redis via `hermes-orchestration-queue`)
### Job: `orchestration-task`
| Field | Type | Description |
|-------|------|-------------|
| `taskId` | string (UUIDv7) | Task tracking ID |
| `taskType` | `DEVOPS` / `DMS_FEATURE` / `SCHEMA_DB` / `BUG_FIX` | กำหนด context loading strategy |
| `description` | string | Task description (no production data) |
| `contextSources` | string[] | Context files to load |
| `maxIterations` | number | Self-correction loop limit (default: 3) |
| `telegramChatId` | string | สำหรับ progress/result notification |
| `createdAt` | string (ISO 8601) | |
---
## 5. SOUL.md (Container File: `/volume1/docker/hermes/SOUL.md`)
ไม่ใช่ DB table แต่เป็น plain Markdown file working journal ใน container volume
**Structure per session entry**:
```markdown
## Session {ISO_DATETIME}
Task: {task description}
TaskType: {DEVOPS|DMS_FEATURE|SCHEMA_DB|BUG_FIX}
Context loaded: {comma-separated context files}
Sub-agents delegated: {count} code generation calls
Iterations: {count} ({result of last iteration})
PR created: {branch} → #{pr_number}
Status: {DONE|ESCALATED|FAILED}
```
**File management**:
- Read at session start for context resumption
- Append only (never overwrite previous entries)
- Rotate (clear and archive) every 30 days or manual clear
- Never synced to repo — container volume only
---
## 6. DevQdrantCollection (`lcbp3_code_chunks` on ASUSTOR:6334)
| Field | Type | Description |
|-------|------|-------------|
| `id` | string (UUID) | Chunk ID |
| `repoName` | string | Repository name (e.g., `lcbp3`) |
| `moduleName` | string | Module path (e.g., `backend/src/modules/correspondence`) |
| `filePath` | string | Relative file path |
| `chunkIndex` | number | Chunk position in file |
| `content` | string | Code chunk text |
| `vector` | float[] | nomic-embed-text embedding (768 dimensions) |
> **ไม่ใช้ `projectPublicId` filter** (ซึ่งเป็น DMS document isolation key) — ใช้ `repoName` + `moduleName` แทน ตาม ADR-031 v2.0
---
## Entity Relationships
```
HermesAgent
├── orchestrates → HermesOrchestrationTask (via hermes-orchestration-queue)
│ ├── delegates → HermesSubAgent (Cloud AI: Claude Haiku / GPT-4o-mini)
│ ├── searches → DevQdrantCollection (code patterns)
│ └── records → SOUL.md (session journal)
└── bridges → HermesTelegramGateway
├── validates → HermesRateLimitState (Redis)
├── records → HermesOperationsLog (SQLite)
└── dispatches → HermesBullMQJobs (hermes-notification-queue)
└── sends → Telegram API
```
---
## State Transitions: HermesOperationsLog.status
```
PENDING → IN_PROGRESS → COMPLETED
→ FAILED
→ REJECTED (allowlist/rate-limit/forbidden-action check)
```
## State Transitions: HermesOrchestrationTask
```
QUEUED → CONTEXT_LOADING → SUB_AGENT_DELEGATED
→ SELF_CORRECTION (max 3 iterations)
→ PR_CREATED → DONE
→ ESCALATED (>3 iterations, notify Developer)
→ FAILED
```
@@ -0,0 +1,258 @@
// File: specs/200-fullstacks/231-hermes-agent/plan.md
// Change Log:
// - 2026-05-29: Initial implementation plan for Hermes Agent (ADR-031 v2.0)
# Implementation Plan: Hermes Agent — Autonomous Dev Orchestrator & Telegram DevOps Bridge
**Branch**: `231-hermes-agent` | **Date**: 2026-05-29 | **Spec**: [spec.md](./spec.md)
**Input**: Feature specification from `specs/200-fullstacks/231-hermes-agent/spec.md`
---
## Summary
Hermes Agent เป็น standalone NestJS service รันบน ASUSTOR Docker ทำหน้าที่ 2 บทบาทหลัก:
1. **Autonomous Dev Orchestrator** — รับ coding task, delegate ไป Cloud AI sub-agents, รัน self-correction loop, push PR via hermes-bot
2. **Telegram DevOps Bridge** — webhook handler สำหรับ DevOps commands พร้อม allowlist + rate-limit + operations log
Hermes ไม่แตะ DMS production schema หรือ DMS production services ทุกกรณี (FR-017, ADR-031)
---
## Technical Context
**Language/Version**: TypeScript 5.x / Node.js 22 LTS
**Primary Dependencies**:
- NestJS 10 (framework)
- BullMQ 5 (queue: hermes-notification-queue + hermes-orchestration-queue)
- `@anthropic-ai/sdk` + `openai` npm packages (Cloud AI clients)
- `better-sqlite3` (hermes_operations_log SQLite)
- `ioredis` (rate limiting + BullMQ)
- `@qdrant/js-client-rest` (Dev Qdrant client)
- `node-telegram-bot-api` or `telegraf` (Telegram Bot SDK)
- `simple-git` (Git operations via hermes-bot)
- `uuid` v7 (UUIDv7 generation — ADR-019)
**Storage**:
- SQLite (`/volume1/docker/hermes/data/ops.db`) — HermesOperationsLog
- Redis (hermes-redis container) — BullMQ queues + rate limiting
- Dev Qdrant (hermes-qdrant container, port 6334) — codebase embeddings
- File volume (`/volume1/docker/hermes/SOUL.md`) — SOUL.md working journal
**Testing**: Jest (unit + integration); no E2E browser tests required
**Target Platform**: ASUSTOR NAS (Linux ARM/x86) — Docker container, non-Swarm
**Performance Goals**:
- Telegram read-only commands: ≤ 10s response (SC-003)
- Coding task PR creation: ≤ 30 min typical (SC-001)
- Self-correction loop: ≤ 3 iterations (SC-002)
**Constraints**:
- CPU ≤ 2.0 cores, RAM ≤ 4096MB (ASUSTOR resource limits)
- LAN/VPN-only exposure (except Telegram webhook via reverse proxy)
- ห้ามใช้ DMS production Redis, DMS Qdrant, DMS audit_logs
- Cloud AI: ห้ามส่ง production DB query results, document content, user data
- Port 8766 สำหรับ hermes proxy เท่านั้น (ห้ามใช้ 8765 ที่ PaddleOCR ใช้อยู่)
**Scale/Scope**: Single DevOps team tool (2-5 concurrent users); not production DMS service
---
## Constitution Check
_GATE: Must pass before Phase 0 research. Re-check after Phase 1 design._
| Rule | Status | Notes |
|------|--------|-------|
| ADR-019: UUIDv7, no parseInt | ✅ PASS | transactionId ใช้ UUIDv7; ไม่มี parseInt บน UUID |
| ADR-016: Auth/RBAC | ✅ PASS | API Key auth + Telegram allowlist; webhook secret verification |
| ADR-007: Error handling | ✅ PASS | BullMQ retry 3x exponential backoff; ADR-007 error classification |
| ADR-008: BullMQ | ✅ PASS | `hermes-notification-queue` + `hermes-orchestration-queue` |
| ADR-023/023A: AI boundary | ✅ PASS | Cloud AI exception (ADR-031 v2.0 Locked) สำหรับ dev orchestration; ไม่ใช่ DMS document path |
| ADR-009: No migration | ✅ PASS | ไม่มี DMS schema delta; Hermes-owned SQLite ไม่ใช่ DMS DB |
| No `any` TypeScript | ✅ PASS | strict mode; all types explicit |
| No `console.log` | ✅ PASS | NestJS Logger ทั้งหมด |
| Forbidden patterns | ✅ PASS | ไม่มี parseInt(UUID), ไม่ expose INT PK, ไม่มี inline notification |
| File headers | ✅ PASS | ทุก TypeScript file เริ่มด้วย `// File: ...` |
| Data Classification | ✅ PASS | Code/Config/ADR ส่ง Cloud AI ได้; Production data ห้ามส่งออก |
| Failure isolation | ✅ PASS | Hermes ไม่ใช่ DMS dependency; DMS ทำงานได้โดยไม่มี Hermes |
**No constitution violations. Proceed.**
---
## Project Structure
### Documentation (this feature)
```text
specs/200-fullstacks/231-hermes-agent/
├── spec.md # Feature specification
├── plan.md # This file
├── research.md # Phase 0 output
├── data-model.md # Phase 1 output
├── quickstart.md # Phase 1 output
├── contracts/
│ └── hermes-api.yaml # OpenAPI contract
└── tasks.md # Phase 2 output
```
### Source Code (new Hermes stack — NOT part of backend/ or frontend/)
```text
hermes/
├── src/
│ ├── orchestrator/
│ │ ├── orchestrator.module.ts
│ │ ├── orchestrator.service.ts # Autonomous dev loop
│ │ ├── context-loader.service.ts # Selective context loading
│ │ ├── sub-agent.service.ts # Cloud AI delegation
│ │ ├── self-correction.service.ts # Lint/tsc/test loop (max 3 iter)
│ │ └── soul.service.ts # SOUL.md journal management
│ ├── integrations/
│ │ ├── telegram/
│ │ │ ├── telegram.module.ts
│ │ │ ├── hermes-telegram-gateway.ts # Inbound webhook handler
│ │ │ ├── hermes-telegram-dispatcher.ts # BullMQ outbound worker
│ │ │ ├── hermes-devops-command-router.ts # Command routing
│ │ │ └── telegram-rate-limiter.service.ts
│ │ ├── gitea/
│ │ │ ├── gitea.module.ts
│ │ │ └── gitea.service.ts # Gitea API (read-only + write-with-confirmation)
│ │ └── mcp/
│ │ ├── mcp.module.ts
│ │ └── mcp-server.service.ts # Exposes hermes MCP tools endpoint
│ ├── proxy/
│ │ ├── proxy.module.ts
│ │ └── proxy.service.ts # hermes proxy (OpenAI-compatible, port 8766)
│ ├── operations/
│ │ ├── operations.module.ts
│ │ ├── operations-log.service.ts # SQLite hermes_operations_log
│ │ └── operations.controller.ts # /operations/logs API
│ ├── qdrant/
│ │ ├── qdrant.module.ts
│ │ └── dev-qdrant.service.ts # Dev Qdrant client (port 6334)
│ ├── health/
│ │ ├── health.module.ts
│ │ └── health.controller.ts # /health endpoint
│ ├── common/
│ │ ├── guards/
│ │ │ ├── api-key.guard.ts # X-API-Key validation
│ │ │ └── telegram-allowlist.guard.ts # Allowlist check
│ │ ├── interceptors/
│ │ │ └── transaction.interceptor.ts # Auto-inject transactionId
│ │ └── utils/
│ │ ├── uuid.util.ts # UUIDv7 generation (ADR-019)
│ │ └── secret-redactor.util.ts # Redact secrets from log payload
│ ├── config/
│ │ └── hermes.config.ts # All env vars typed
│ ├── app.module.ts
│ └── main.ts
├── test/
│ ├── unit/
│ │ ├── telegram-gateway.spec.ts
│ │ ├── command-router.spec.ts
│ │ ├── orchestrator.spec.ts
│ │ └── secret-redactor.spec.ts
│ └── integration/
│ └── staged-rollout.spec.ts
├── specs/ # Docker compose + config
│ └── 04-Infrastructure-OPS/
│ └── 04-00-docker-compose/
│ └── ASUSTOR/
│ └── hermes/
│ ├── docker-compose.hermes.yml
│ ├── docker-compose.hermes-redis.yml
│ ├── docker-compose.hermes-qdrant.yml
│ ├── hermes.redis.conf
│ └── .env.example # เฉพาะ placeholder ห้าม commit secret จริง
├── .env.example
├── Dockerfile
├── nest-cli.json
├── package.json
└── tsconfig.json
```
**Structure Decision**: Standalone NestJS project (`hermes/`) แยกจาก `backend/` และ `frontend/` ทั้งหมด เพราะ Hermes ไม่ใช่ DMS production service และมี deploy target แยก (ASUSTOR NAS) รวมถึงมี Redis/SQLite/Qdrant ของตัวเอง
---
## Implementation Phases
### Phase 1: Setup & Infrastructure Foundation
- สร้าง `hermes/` project structure (NestJS + TypeScript strict)
- Docker Compose files (hermes agent + hermes-redis + hermes-qdrant)
- Config module (typed env vars + secrets validation)
- HealthController + basic API Key guard
### Phase 2: Core Foundational Services
- OperationsLogService (SQLite + create/read/update)
- SecretRedactorUtil (scan + redact sensitive patterns)
- UuidUtil (UUIDv7 generation)
- TransactionInterceptor (auto-inject transactionId per request)
### Phase 3: US1 — Autonomous Dev Orchestrator (P1)
- ContextLoaderService (selective context loading by task type)
- SubAgentService (Claude Haiku/GPT-4o-mini delegation)
- SelfCorrectionService (lint/tsc/test loop, max 3 iterations)
- OrchestratorService (main development loop coordination)
- OrchestratorController (POST /orchestration/tasks, GET /orchestration/tasks/:id)
- SoulService (SOUL.md read/append/rotate)
- DevQdrantService (hermes-qdrant client, code chunk search)
### Phase 4: US2 — Telegram Read-only Commands (P2)
- TelegramRateLimiterService (Redis-based, 10 req/min/user)
- HermesTelegramGateway (webhook verification, allowlist check, rate limit)
- HermesDevOpsCommandRouter (route read-only commands: /status, /ci_status, /repo_summary)
- GiteaService (read-only: repos, issues, PRs, CI status)
- HermesTelegramDispatcher (BullMQ worker, hermes-notification-queue, retry 3x backoff)
### Phase 5: US3 — Telegram Write-with-Confirmation (P3)
- Write action confirmation flow (HermesDevOpsCommandRouter extension)
- GiteaService write methods (create branch/issue/PR/trigger CI — write token scope)
- Forbidden action blocklist enforcement
- hermes-bot Git identity integration (simple-git + hermes-bot service account)
- Branch pattern validation (hermes/{feat,fix,refactor}-*)
- Operations log write action recording (token identity, target repo/branch)
### Phase 6: US4 — Developer AI Proxy (P4)
- ProxyService (OpenAI-compatible API, port 8766)
- Secret payload detection middleware (reject if production data detected)
- MCP server endpoint (/mcp) for agy + Windsurf integration
- HermesMemoryMcpTool (expose DMS context for agy recall)
- HermesToolsMcpTool (expose bash/git execution capability)
### Phase 7: US5 — Staged Rollout Tooling (P5)
- Stage acceptance gate checklist scripts (PowerShell/bash)
- Monitoring alerts (DevOps warning vs. production outage separation)
- Failure isolation verification tests
- Rollback documentation finalization
### Phase 8: Polish & Cross-Cutting
- Structured logging with NestJS Logger (no console.log)
- JSDoc for all public classes (Thai comments per AGENTS.md)
- Secret scan validation in CI pipeline
- Docker resource limit verification script
- SOUL.md rotation cron job
---
## Key Technical Decisions
| Decision | Choice | Rationale |
|----------|--------|-----------|
| Hermes stack | Standalone NestJS | แยกจาก DMS backend; same tooling; ทีมรู้จักดี |
| Cloud AI | Anthropic SDK + OpenAI SDK | ADR-031 Cloud AI Exception; model flexibility |
| Operations log | SQLite (better-sqlite3) | Simple, no external service, queryable |
| Rate limiting | Redis-based (ioredis) | Stateless container-safe; shares hermes-redis |
| Git operations | simple-git | Lightweight; TypeScript-native |
| Dev Qdrant | Port 6334 (ASUSTOR) | แยกจาก DMS Qdrant port 6333 (QNAP) |
| Telegram SDK | telegraf or node-telegram-bot-api | ต้อง verify ตอน implementation (ADR-031 note) |
@@ -0,0 +1,200 @@
// File: specs/200-fullstacks/231-hermes-agent/quickstart.md
// Change Log:
// - 2026-05-29: Initial quickstart / verification guide for Hermes Agent staged rollout
# Quickstart: Hermes Agent Staged Rollout
**Feature**: 231-hermes-agent | **Date**: 2026-05-29
---
## Prerequisites
- [ ] ASUSTOR NAS with Docker support (ADM + Docker add-on)
- [ ] ASUSTOR IP confirmed (default: `192.168.10.X` — run `df -h` to confirm share paths)
- [ ] Gitea `hermes-bot` service account created with read-only token (write token created separately for Stage 4)
- [ ] Telegram bot created via @BotFather → bot token available
- [ ] Cloud AI API keys (Claude/Anthropic + OpenAI) stored in ASUSTOR secret store
- [ ] inter-VLAN routing confirmed: ASUSTOR → QNAP (MariaDB :3306, Gitea :3000) — required for Stage 2+
---
## Stage 0 — Documentation Only (Architecture Team approval required)
**Goal**: ADR boundary reviewed, locked decisions captured, no deploy files applied
Verification gate:
- [ ] ADR-031 v2.0 reviewed and all Locked Decisions confirmed
- [ ] No SQL delta files created
- [ ] No docker-compose files applied to ASUSTOR
**Gate passed** → advance to Stage 1
---
## Stage 1 — Hermes Container LAN-only (DevOps/Admin approval)
```bash
# บน ASUSTOR shell (SSH ก่อน)
ssh admin@<ASUSTOR_IP>
# ขึ้น stack (hermes-redis + hermes-agent)
cd /volume1/docker/hermes
docker compose -f docker-compose.hermes.yml up -d
# Verify resource limits enforce จริง
docker inspect hermes_agent_lcbp3 | grep -E '"Memory"|"NanoCpus"'
docker stats hermes_agent_lcbp3 --no-stream
```
Verification gate:
- [ ] Container running: `docker ps | grep hermes_agent_lcbp3`
- [ ] LAN/VPN-only: Hermes `:8080`, `:8766`, `/mcp` ไม่ accessible จาก public internet
- [ ] Redis แยกจาก DMS: `docker network inspect lcbp3 | grep hermes-redis` (ต้องอยู่ใน network แยก หรือ isolate ด้วย ACL)
- [ ] CPU ≤ 2.0 cores, RAM ≤ 4096MB enforce จาก `docker inspect`
**Gate passed** → advance to Stage 2
---
## Stage 2 — Read-only Diagnostics (DBA/Security + DevOps approval)
```bash
# ทดสอบ MariaDB read-only connection (ไม่ควร write ได้)
docker exec hermes_agent_lcbp3 node -e "
const mysql = require('mysql2');
const conn = mysql.createConnection({
host: process.env.HERMES_MARIADB_READONLY_HOST,
user: process.env.HERMES_MARIADB_READONLY_USER,
password: process.env.HERMES_MARIADB_READONLY_PASSWORD,
database: process.env.HERMES_MARIADB_READONLY_DATABASE
});
conn.query('SHOW TABLES', (err, rows) => { console.log(rows); conn.end(); });
"
# ทดสอบ write ต้องล้มเหลว
# (INSERT statement should return error with read-only user)
```
Verification gate:
- [ ] Read-only DB grant verified: SELECT pass, INSERT/UPDATE/DELETE fail
- [ ] Masked/redacted fields verified: no document content, user passwords, storage paths in query results
- [ ] Gitea read-only token verified: GET repos/issues/PRs pass, POST/PATCH/DELETE fail
- [ ] No direct storage mount: `docker inspect hermes_agent_lcbp3 | grep Mounts` — no permanent storage paths
**Gate passed** → advance to Stage 3
---
## Stage 3 — Telegram Read-only DevOps (DevOps/Security approval)
```bash
# ทดสอบ webhook secret verification
curl -X POST http://localhost:8080/api/v1/telegram/webhook \
-H "X-Telegram-Bot-Api-Secret-Token: WRONG_SECRET" \
-H "Content-Type: application/json" \
-d '{"message":{"from":{"id":123},"text":"/status","chat":{"id":123}}}' \
# ต้องได้ 401 Unauthorized
# ทดสอบ allowlist rejection
curl -X POST http://localhost:8080/api/v1/telegram/webhook \
-H "X-Telegram-Bot-Api-Secret-Token: ${HERMES_TELEGRAM_WEBHOOK_SECRET}" \
-H "Content-Type: application/json" \
-d '{"message":{"from":{"id":999999999},"text":"/status","chat":{"id":999999999}}}' \
# ต้องได้ rejected (user ไม่อยู่ใน allowlist)
# ทดสอบ /ci_status จาก authorized user
# (ส่งผ่าน Telegram จริง หรือ simulate ด้วย authorized user ID)
```
Verification gate:
- [ ] Telegram allowlist verified: non-allowlisted user rejected 100%
- [ ] Webhook secret verified: wrong secret → 401
- [ ] Rate limit verified: >10 requests/minute from same user → rejected
- [ ] `hermes_operations_log` captures inbound/outbound transactions with transactionId
- [ ] `/ci_status`, `/repo_summary`, `/status`, `/audit_summary` return correct data
**Gate passed** → advance to Stage 4
---
## Stage 4 — Write-with-Confirmation DevOps (Architecture + Security + Repo Owner approval)
```bash
# ทดสอบ forbidden action blocker
# ส่งคำสั่ง "push to main" ผ่าน Telegram
# ต้องได้ rejection message โดยไม่มีการดำเนินการใดๆ
# ทดสอบ confirmation flow
# ส่ง "เตรียม branch proposal สำหรับ fix/test-issue"
# → Hermes แสดง summary + ขอ confirmation
# → ยืนยัน
# → ตรวจสอบ Gitea: branch hermes/fix-test-issue ถูกสร้าง
# → ตรวจสอบ hermes_operations_log: มี entry พร้อม transactionId
# ทดสอบ hermes-bot token scope
git -c http.extraHeader="Authorization: token ${HERMES_BOT_WRITE_TOKEN}" \
push gitea-origin main
# ต้องได้ 403 Forbidden (branch protection + token scope block)
```
Verification gate:
- [ ] Explicit confirmation flow verified: write action requires confirmation before executing
- [ ] Forbidden action blocklist verified: push main/develop, production deploy, schema migration, direct DB write → rejected
- [ ] Branch protection + Gitea token scope verified: hermes-bot cannot push to main/develop
- [ ] `hermes_operations_log` records token identity, target repo/branch for all write actions
**Gate passed** → advance to Stage 5
---
## Stage 5 — Developer AI Proxy (Architecture + Security approval)
```powershell
# บน Windows PowerShell — ทดสอบ hermes proxy
$env:OPENAI_BASE_URL = "http://<ASUSTOR_IP>:8766/v1"
$env:OPENAI_API_KEY = "<HERMES_PROXY_API_KEY>"
# ทดสอบ basic coding request (no production data)
codex "scaffold NestJS module for health check"
# ต้องได้ response พร้อม DMS context
# ทดสอบ secret payload rejection
# ส่ง payload ที่มี "password: secret123" หรือ storage path
# ต้องได้ rejected + redact ใน log
```
Verification gate:
- [ ] Proxy LAN/VPN-only: port 8766 ไม่ accessible จาก public internet
- [ ] No secrets/document payload: test payload ที่มี token/password/storage path ถูก reject และ redact ใน log
- [ ] Proxy ไม่ wired เข้า DMS AI runtime หรือ DMS document intelligence path
- [ ] Wrong API key → 401
**All stages complete** → Hermes fully operational
---
## Rollback Procedures
| Stage | Rollback |
|-------|---------|
| Stage 1 | `docker compose -f docker-compose.hermes.yml down`; verify DMS production unaffected |
| Stage 2 | Revoke DB/Gitea read-only credentials via Gitea admin; disable MCP servers; confirm no storage mount |
| Stage 3 | `curl -X DELETE "https://api.telegram.org/bot{TOKEN}/deleteWebhook"`; revoke bot token if needed |
| Stage 4 | Revoke Gitea write token via Gitea admin; disable write commands in Hermes config |
| Stage 5 | Unset `OPENAI_BASE_URL` on all clients; stop hermes proxy; revoke proxy API key |
---
## Health Check Endpoints
```bash
# Hermes health (Stage 1+)
curl http://<ASUSTOR_IP>:8080/api/v1/health
# hermes proxy health (Stage 5)
curl http://<ASUSTOR_IP>:8766/v1/models
# Dev Qdrant health (if deployed)
curl http://<ASUSTOR_IP>:6334/healthz
```
@@ -0,0 +1,103 @@
// File: specs/200-fullstacks/231-hermes-agent/research.md
// Change Log:
// - 2026-05-29: Phase 0 research — all unknowns resolved from ADR-031 v2.0
# Research: Hermes Agent
**Feature**: 231-hermes-agent | **Date**: 2026-05-29
---
## R-001: Hermes Stack / Runtime
**Decision**: NestJS (TypeScript) บน Node.js 22 — เช่นเดียวกับ DMS backend เพื่อ reuse tooling, tsconfig, ESLint, Jest
**Rationale**: ทีมรู้จัก NestJS ดีแล้ว; BullMQ ใช้ร่วม npm package ได้; TypeScript strict mode enforce ตาม AGENTS.md
**Alternatives considered**:
- Python FastAPI — reuse Ollama/ML code แต่ทีมหลักเป็น TypeScript/NestJS
- Go — performance ดีกว่าแต่ไม่มี BullMQ native และทีมไม่คุ้นเคย
---
## R-002: Cloud AI Provider & Model Selection
**Decision**: Claude Sonnet (orchestration) / Claude Haiku (sub-agents) เป็น primary; GPT-4o / GPT-4o-mini เป็น fallback
**Rationale**: ADR-031 v2.0 Locked Decision — Cloud AI Exception สำหรับ dev orchestration layer โดยเฉพาะ; ใช้ model ขนาดเล็กกว่าสำหรับ sub-agents เพื่อลด cost
**Alternatives considered**:
- Ollama only (Gemma4/gemma2) — ไม่ได้รับ exception จาก ADR-023A สำหรับ dev orchestration; context window จำกัด; ไม่เหมาะกับ orchestration workload ขนาดใหญ่
- GPT-4o only — ราคาสูงกว่าถ้าใช้ทุก request
---
## R-003: Dev Qdrant Isolation
**Decision**: Separate Qdrant instance บน ASUSTOR port 6334 (container: `hermes-qdrant`); collection `lcbp3_code_chunks` indexed by `repoName` + `moduleName`
**Rationale**: ADR-031 v2.0 Locked — ห้ามใช้ Qdrant instance เดียวกับ DMS document RAG (port 6333 บน QNAP ADR-023A); separation ป้องกัน cross-contamination
**Alternatives considered**:
- Shared DMS Qdrant — ปฏิเสธ: ADR-031 v2.0 explicit lock; DMS Qdrant ใช้ `projectPublicId` filter สำหรับ document isolation ซึ่งไม่เหมาะกับ code chunks
---
## R-004: BullMQ Queue Architecture
**Decision**: `hermes-notification-queue` เป็น queue หลักสำหรับ outbound Telegram; `hermes-orchestration-queue` สำหรับ async dev tasks; ใช้ Redis instance แยก (`hermes-redis` container)
**Rationale**: ADR-031 Redis Isolation Policy — ห้ามใช้ DMS production Redis (อาจ evict DMS BullMQ/lock/cache keys ถ้าใช้ `allkeys-lru`); queue names ขึ้นต้น `hermes-`
**Alternatives considered**:
- Shared DMS Redis — ปฏิเสธ: ADR-031 explicit policy; ถ้าจำเป็นต้องแชร์ต้องมี keyPrefix แยก, DB index แยก, ACL user แยก
---
## R-005: hermes_operations_log Storage
**Decision**: SQLite database ภายใน Hermes container volume (`/volume1/docker/hermes/data/ops.db`) — เริ่มต้นง่าย, ไม่ต้อง external service, เพียงพอสำหรับ DevOps audit trail
**Rationale**: ADR-031 — ต้องอยู่ใน Hermes-owned storage เท่านั้น; ไม่ใช่ DMS `audit_logs`; single-operator DevOps tool ไม่ต้องการ high-concurrency DB
**Alternatives considered**:
- Postgres volume ภายใน Hermes stack — option ถ้า ops volume เติบโต แต่ SQLite เพียงพอสำหรับ Stage 1-4
- Structured log files + ship to log collector — viable แต่ SQLite ง่ายกว่าสำหรับ query ด้วย `/status <transactionId>`
---
## R-006: SOUL.md เป็น Session Memory
**Decision**: Plain Markdown file ภายใน container volume `/volume1/docker/hermes/SOUL.md`; Hermes อ่านต้น session และ append per-session entry; rotate ทุก 30 วัน
**Rationale**: ADR-031 v2.0 Locked — ไม่ sync ลง repo ทุกกรณี; container-local เท่านั้น; ไม่ใช้ Obsidian หรือ external knowledge base
**Alternatives considered**:
- Redis-based session memory — volatile และ restart ทำให้ข้อมูลหาย
- Gitea wiki/issue — sync ลง repo ซึ่งขัดกับ ADR-031 locked decision
---
## R-007: Telegram Webhook Security
**Decision**: Verify `X-Telegram-Bot-Api-Secret-Token` header ทุก request; enforce allowlist (`HERMES_TELEGRAM_ALLOWED_USER_IDS`); Redis-based rate limit 10 req/min/user; expose webhook เฉพาะ LAN หรือผ่าน reverse proxy ที่มี TLS + Telegram secret verification
**Rationale**: ป้องกัน spoofed requests; ป้องกัน unauthorized DevOps access; ป้องกัน spam/DoS ตาม ADR-031 security requirements
**Alternatives considered**:
- IP allowlist only — ไม่เพียงพอถ้า Telegram ใช้ dynamic IPs
- No rate limiting — risk ของ spam/DoS จาก compromised Telegram account
---
## R-008: Git Identity & PR Flow
**Decision**: `hermes-bot` Gitea service account (least privilege); write token scope: create branch/issue/PR/trigger CI เท่านั้น (ไม่ใช่ admin token); branch pattern `hermes/{feat,fix,refactor}-*`; ห้าม push main/develop; ต้องผ่าน CI ก่อน merge; human approve required
**Rationale**: ADR-031 v2.0 Locked — ทุก change ผ่าน PR ที่ human review เท่านั้น; ป้องกัน accidental direct push to protected branches
**Alternatives considered**:
- Hermes push ตรง develop — ปฏิเสธ: ADR-031 explicit lock; repo gate compliance
- Admin token — ปฏิเสธ: ADR-031 explicit prohibition; least privilege principle
---
## R-009: Resource Limits บน ASUSTOR (non-Swarm Docker)
**Decision**: กำหนด fallback resource limits ทั้งใน `deploy.resources` (Swarm syntax) และ top-level `cpus`/`mem_limit` (non-Swarm syntax) เพื่อให้ enforce บน ASUSTOR ADM Docker; verify ด้วย `docker inspect` และ `docker stats`
**Rationale**: ADR-031 note — `deploy.resources` อาจถูก ignore ใน non-Swarm Docker บน ASUSTOR; ต้อง verify จาก runtime ไม่ใช่ compose file เท่านั้น
**Alternatives considered**:
- Swarm mode บน ASUSTOR — ไม่จำเป็นสำหรับ single-node DevOps tool; เพิ่ม complexity โดยไม่จำเป็น
---
## R-010: Context Loading Strategy (Selective Context)
**Decision**: Hermes โหลด context แบบ selective ตาม task type เพื่อลด token ที่ส่งไป Cloud AI: DevOps task → CONTEXT-ADR-031+AGENTS.md; DMS feature coding → +CONTEXT.md; Schema/DB → +schema SQL (read-only); Bug fix → +Dev Qdrant search results
**Rationale**: ADR-031 v2.0 — ลด cost ของ Cloud AI; ป้องกันส่ง production DB query results เข้า Cloud AI context (Data Classification Policy)
**Alternatives considered**:
- โหลด CONTEXT.md ทุก request — เพิ่ม token cost; ไม่จำเป็นสำหรับ pure DevOps queries
@@ -0,0 +1,220 @@
// File: specs/200-fullstacks/231-hermes-agent/spec.md
// Change Log:
// - 2026-05-29: Initial specification derived from ADR-031 v2.0
# Feature Specification: Hermes Agent — Autonomous Dev Orchestrator & Telegram DevOps Bridge
**Feature Branch**: `231-hermes-agent`
**Created**: 2026-05-29
**Status**: Draft
**Category**: 200-fullstacks
**Input**: ADR-031 v2.0 (specs/06-Decision-Records/ADR-031-hermes-agent-telegram-devops-bridge.md)
## Overview
Hermes Agent เป็น Autonomous Development Loop Orchestrator และ Telegram DevOps Bridge ที่รันบน ASUSTOR NAS แบบ always-on โดยทำหน้าที่ 2 roles หลัก:
1. **Autonomous Dev Orchestrator** (primary) — รับ coding task จาก Developer ผ่าน Telegram/CLI, โหลด context, วางแผน, จ่ายงานให้ sub-agents (Cloud AI), รัน self-correction loop (lint/tsc/test), และสร้าง PR ใน Gitea สำหรับ human review
2. **Telegram DevOps Bridge** (subsystem) — รับ DevOps commands ผ่าน Telegram bot สำหรับ read-only queries (CI status, repo summary) และ write-with-confirmation actions (create branch/issue/PR/trigger CI)
Hermes **ไม่ใช่** production DMS service, ไม่ใช่ DMS AI inference boundary, และไม่แตะ production DMS schema ทุกกรณี
---
## Clarifications
### Session 2026-05-29
Ambiguity scan ran across all 10 taxonomy categories. All categories scored **Clear** — ADR-031 v2.0 Locked Decisions (grill-with-docs 2026-05-29) pre-resolve every design choice that would otherwise require clarification:
- Q: Cloud AI scope (which AI services allowed for Hermes?) → A: Claude/GPT-4o for orchestration + Haiku/GPT-4o-mini for sub-agents; DMS document processing remains ADR-023A Ollama-only (Cloud AI Exception, ADR-031 v2.0 Locked)
- Q: Dev Qdrant isolation (shared with DMS Qdrant?) → A: Separate instance on ASUSTOR port 6334, collection `lcbp3_code_chunks` indexed by `repoName`+`moduleName` — never shared with DMS Qdrant port 6333 (ADR-031 v2.0 Locked)
- Q: SOUL.md persistence (repo vs. container?) → A: Container volume only (`/volume1/docker/hermes/SOUL.md`), never synced to repo, rotated every 30 days (ADR-031 v2.0 Locked)
- Q: hermes proxy port (conflict with PaddleOCR?) → A: Port 8766 for hermes proxy; port 8765 is reserved for PaddleOCR sidecar per ADR-023A (ADR-031 v1.1.1 fix)
- Q: hermes_operations_log location (DMS audit_logs?) → A: Hermes-owned store only (SQLite/Postgres volume or structured log), never writes to DMS `audit_logs` (ADR-031 v2.0 Locked)
**Coverage Summary**: Functional Scope ✅ | Domain & Data Model ✅ | Interaction & UX ✅ | Non-Functional ✅ | Integration ✅ | Edge Cases ✅ | Constraints ✅ | Terminology ✅ | Completion Signals ✅
No questions asked. Proceeding directly to `/speckit-plan`.
---
## User Scenarios & Testing _(mandatory)_
### User Story 1 — Autonomous Coding Task Orchestration (Priority: P1)
Developer ส่ง coding task เช่น "scaffold NestJS module for X" ผ่าน Telegram หรือ CLI แล้ว Hermes โหลด project context, วางแผน, แตกงาน, delegate ไปยัง sub-agents, รัน lint/tsc/test self-correction loop, และสร้าง PR ใน Gitea branch `hermes/feat-*` สำหรับ Developer review/approve
**Why this priority**: เป็น core value ของ Hermes — ช่วยให้ Developer สั่งงาน coding จากที่ไหนก็ได้โดยไม่ต้องเปิด IDE และได้รับ PR ที่พร้อม review ภายในเวลาอันสั้น
**Independent Test**: Developer ส่ง Telegram message "scaffold NestJS module for repository diagnostics" → Hermes ส่งกลับ PR link ใน Gitea branch `hermes/feat-*` ที่ผ่าน lint/tsc
**Acceptance Scenarios**:
1. **Given** Developer อยู่ใน Telegram allowlist, **When** ส่ง coding task, **Then** Hermes โหลด context ที่เหมาะกับ task type (selective loading), วางแผน, delegate sub-agent, รัน lint/tsc/test
2. **Given** sub-agent ส่งโค้ดที่ lint ล้มเหลว, **When** Hermes รัน self-correction, **Then** ส่งกลับไปให้ sub-agent แก้ไขสูงสุด 3 iterations ก่อนหยุดและแจ้ง Developer
3. **Given** โค้ดผ่าน lint/tsc/test ทุก check, **When** Hermes push, **Then** commit ลง `hermes/feat-{task-id}` branch โดย `hermes-bot` service account แล้วสร้าง PR พร้อม assign to Developer
4. **Given** Hermes ต้องการ code patterns จาก codebase, **When** ค้นหา, **Then** ใช้ Dev Qdrant (ASUSTOR) ที่แยกจาก DMS Qdrant เท่านั้น
5. **Given** task เสร็จสิ้น, **When** Hermes บันทึก session, **Then** เขียนลง SOUL.md ภายใน container เท่านั้น (ไม่ sync ลง repo)
---
### User Story 2 — Telegram Read-only DevOps Commands (Priority: P2)
DevOps engineer/Developer ส่ง read-only commands ผ่าน Telegram เช่น `/ci_status`, `/repo_summary`, `/status`, `/audit_summary` และรับผลลัพธ์กลับมาทันทีโดยไม่มีผลข้างเคียงต่อระบบ
**Why this priority**: ช่วยให้ทีมตรวจสอบสถานะ CI/repo จากมือถือโดยไม่ต้องเปิด Gitea UI — ลด context switching และเพิ่ม DevOps visibility
**Independent Test**: ส่ง `/ci_status` ใน Telegram → รับสถานะ CI ล่าสุดจาก Gitea กลับมาภายใน 10 วินาที พร้อม reference transactionId
**Acceptance Scenarios**:
1. **Given** Telegram user อยู่ใน allowlist, **When** ส่ง `/ci_status`, **Then** Hermes ดึงสถานะ CI ล่าสุดจาก Gitea แล้วตอบกลับพร้อม `[Ref: {transactionId}]`
2. **Given** Telegram user ไม่อยู่ใน allowlist, **When** ส่ง command ใดก็ตาม, **Then** Hermes ปฏิเสธ request และไม่ดำเนินการใดๆ
3. **Given** Telegram webhook request เข้ามา, **When** ตรวจสอบ `X-Telegram-Bot-Api-Secret-Token` ไม่ตรง, **Then** reject request ทันที
4. **Given** Telegram user ส่ง request เกิน rate limit (>10 ต่อนาที), **When** Hermes ตรวจสอบ Redis counter, **Then** ปฏิเสธ request และแจ้ง user
5. **Given** command ทุกประเภท, **When** รับ/ส่งข้อมูล, **Then** บันทึก inbound/outbound ใน `hermes_operations_log` พร้อม transactionId ทันที
---
### User Story 3 — Telegram Write-with-Confirmation DevOps Actions (Priority: P3)
DevOps engineer ส่ง action commands ผ่าน Telegram เช่น "เตรียม branch/PR proposal สำหรับ fix/ci-pnpm-cache" — Hermes ขอ explicit confirmation ก่อนดำเนินการ และบันทึก transactionId ทุกขั้นตอน
**Why this priority**: ช่วยให้ทีมสั่งงาน DevOps actions จากมือถือได้อย่างปลอดภัยด้วย human confirmation gate ป้องกัน accidental changes
**Independent Test**: ส่ง "สร้าง branch proposal สำหรับ fix/ci-cache" → Hermes แสดง summary + ขอ confirmation → ยืนยัน → Hermes สร้าง branch ใน Gitea + บันทึก hermes_operations_log + แจ้ง PR created
**Acceptance Scenarios**:
1. **Given** Developer ส่ง write action command, **When** Hermes รับ, **Then** แสดง action summary และขอ explicit confirmation ก่อนดำเนินการ
2. **Given** Developer ยืนยัน action, **When** Hermes ดำเนิน, **Then** ใช้ Gitea write token ที่แยกและมี scope แคบ (ไม่ใช่ admin token) สำหรับ create branch/issue/PR/trigger CI เท่านั้น
3. **Given** action สำเร็จหรือล้มเหลว, **When** สิ้นสุด, **Then** บันทึก `transactionId`, token identity, target repo/branch, และผลลัพธ์ใน `hermes_operations_log`
4. **Given** command ที่เป็น forbidden action (push main/develop, production deploy, schema migration, destructive ops, direct DB write), **When** รับ command ดังกล่าว, **Then** Hermes ปฏิเสธทุกกรณี ไม่ว่าจะผ่าน confirmation หรือไม่
5. **Given** Developer ยืนยัน create branch, **When** สร้างสำเร็จ, **Then** branch pattern ต้องเป็น `hermes/feat-*`, `hermes/fix-*`, หรือ `hermes/refactor-*` เท่านั้น
---
### User Story 4 — Developer AI Proxy (hermes proxy) (Priority: P4)
Developer บน laptop ใช้ Codex CLI หรือ agy โดยชี้ `OPENAI_BASE_URL` ไปยัง `hermes proxy` (port 8766 บน ASUSTOR) เพื่อใช้ Hermes เป็น Developer AI Proxy สำหรับ coding/devops assistance เท่านั้น
**Why this priority**: ช่วยให้ CLI tools บน laptop (Codex, agy via MCP) เชื่อมกับ Hermes context บน ASUSTOR ได้ โดยใช้ infrastructure ที่มีอยู่แล้ว
**Independent Test**: บน Windows PowerShell ตั้ง `$env:OPENAI_BASE_URL = "http://<ASUSTOR_IP>:8766/v1"` → รัน `codex "scaffold NestJS module"` → ได้รับ response ที่มี DMS context
**Acceptance Scenarios**:
1. **Given** Developer ตั้ง OPENAI_BASE_URL ชี้ไป hermes proxy, **When** ส่ง coding/devops request, **Then** hermes proxy รับและ forward ไป Cloud AI พร้อม DMS context
2. **Given** proxy รับ payload ที่คล้าย production document content, secret, token, password, หรือ storage path, **When** ตรวจพบ, **Then** ถือเป็น security incident, redact log ทันที, และ reject request
3. **Given** hermes proxy ใช้ port 8766, **When** deploy, **Then** ต้องไม่ conflict กับ PaddleOCR sidecar (port 8765) ตาม ADR-023A
4. **Given** hermes proxy รับ request ใดก็ตาม, **When** ประมวลผล, **Then** expose เฉพาะ LAN/VPN เท่านั้น ห้ามเปิด public internet
5. **Given** Developer ใช้ agy กับ Hermes MCP, **When** เรียก `mcp_hermes-memory_recall`, **Then** Hermes ส่ง DMS context กลับมาโดยไม่มี production document payload หรือ DB query results
---
### User Story 5 — Staged Rollout & Health Monitoring (Priority: P5)
Admin deploy Hermes ผ่าน staged rollout (Stage 0-5) โดยแต่ละ stage มี acceptance gate ที่ต้องผ่านก่อนขึ้น stage ถัดไป และมี monitoring ที่แยก Hermes health ออกจาก DMS production health
**Why this priority**: รับประกันว่า Hermes ถูก deploy อย่างปลอดภัยแบบ incremental และการล่มของ Hermes ไม่ส่งผลกระทบต่อ DMS production ทุกกรณี
**Independent Test**: ปิด Hermes container แล้วตรวจสอบว่า DMS frontend/backend/Workflow Engine/AI pipeline ยังทำงานปกติ 100%
**Acceptance Scenarios**:
1. **Given** Admin ต้องการ deploy Hermes, **When** เริ่ม Stage 1, **Then** Hermes container รันแบบ LAN/VPN-only ด้วย Redis/log store แยกจาก DMS production Redis
2. **Given** Stage acceptance gate ยังไม่ผ่าน, **When** Admin พยายาม deploy Stage ถัดไป, **Then** ระบบหรือ process บล็อกไว้จน gate ผ่าน
3. **Given** Hermes container ล่ม, **When** ตรวจสอบ DMS production, **Then** DMS frontend/backend/Workflow Engine/AI pipeline ทำงานตามปกติ 100% (failure isolation)
4. **Given** Hermes down หรือ Telegram Bridge down, **When** Monitoring แจ้งเตือน, **Then** alert เป็น DevOps warning ไม่ใช่ production DMS outage alert
5. **Given** resource limits กำหนดไว้ใน Docker Compose (CPU 2.0, RAM 4GB limit / 2GB reservation), **When** deploy บน ASUSTOR, **Then** verified ด้วย `docker inspect` และ `docker stats` ว่า runtime enforce จริง
---
### Edge Cases
- Hermes sub-agent ล้มเหลวหลัง 3 iterations — หยุดงานและแจ้ง Developer ผ่าน Telegram พร้อม error detail; ไม่สร้าง PR ที่มีโค้ดผิด
- SOUL.md ขนาดใหญ่เกินไปหลัง 30 วัน — Rotate/clear ตาม schedule; Hermes resume context จาก SOUL.md ต้น session
- hermes-bot ถูก revoke token — ทุก write action ล้มเหลว gracefully พร้อมแจ้ง Developer; read-only commands ยังใช้ token แยกได้
- ASUSTOR restart — Hermes Redis (AOF persistence) recover queue jobs; SOUL.md อยู่ใน container volume ปลอดภัย
- Telegram API ล่ม — BullMQ retry 3 ครั้งด้วย exponential backoff ก่อน dead-letter
- Developer ส่ง secret/token จริงผ่าน Telegram command — Hermes redact ออกจาก log ทันที ไม่ forward ไป Cloud AI
- Dev Qdrant (ASUSTOR) ล่ม — Hermes fallback ไป context-only mode (ไม่มี semantic search) โดย DMS Qdrant ไม่ถูกแตะ
- hermes proxy รับ production document payload — Security incident: redact, reject, alert
- inter-VLAN routing ยังไม่เปิด (ASUSTOR → QNAP) — Stage 2+ ไม่สามารถ deploy ได้; Hermes แสดง error ชัดเจนว่า network path blocked
- hermes-bot พยายาม push ตรง main/develop — Git server-side branch protection block ทุกกรณี
---
## Requirements _(mandatory)_
### Functional Requirements
- **FR-001**: Hermes MUST run as an isolated Docker container on ASUSTOR NAS (CPU ≤ 2 cores, RAM ≤ 4GB) within LAN/VPN boundary เท่านั้น
- **FR-002**: Hermes MUST implement Autonomous Dev Orchestration loop: load selective context → plan → delegate to Cloud sub-agents → self-correction (lint/tsc/test, max 3 iterations) → commit via hermes-bot → create PR
- **FR-003**: Hermes MUST use Cloud AI (Claude/GPT-4o for orchestration, Claude Haiku/GPT-4o-mini for sub-agents) เฉพาะ dev orchestration layer — ไม่ใช่ DMS document processing
- **FR-004**: Data Classification Policy MUST be enforced: Code/Config/ADR/Stack trace ส่ง Cloud AI ได้ — Production runtime data (document content, user info, project business data จาก DB) ห้ามส่งออกทุกกรณี
- **FR-005**: Hermes MUST maintain a separate Dev Qdrant instance on ASUSTOR (collection: `lcbp3_code_chunks`, indexed by `repoName`+`moduleName`) ห้ามใช้ DMS Qdrant instance
- **FR-006**: Hermes MUST maintain SOUL.md working journal ภายใน container volume เท่านั้น (ไม่ sync ลง repo, rotate ทุก 30 วัน)
- **FR-007**: Hermes MUST load selective context ตาม task type: DevOps → CONTEXT-ADR-031+AGENTS.md; DMS feature → +CONTEXT.md; Schema/DB → +schema SQL; Bug fix → +Dev Qdrant
- **FR-008**: Hermes MUST enforce Git Identity rules: ใช้ `hermes-bot` service account, push เฉพาะ `hermes/*` branches, ห้าม push main/develop/release ทุกกรณี, ทุก change ต้องผ่าน PR ที่ human approve
- **FR-009**: Hermes Telegram MUST verify `X-Telegram-Bot-Api-Secret-Token` ทุก webhook request
- **FR-010**: Hermes Telegram MUST enforce allowlist (`HERMES_TELEGRAM_ALLOWED_USER_IDS`) สำหรับ DevOps commands ทุกระดับ
- **FR-011**: Hermes Telegram MUST apply Redis-based rate limiting (default: 10 requests/minute/user)
- **FR-012**: Hermes MUST queue all outbound Telegram notifications ผ่าน BullMQ queue `hermes-notification-queue` พร้อม retry 3 ครั้ง exponential backoff
- **FR-013**: Hermes MUST record every inbound/outbound operation ใน `hermes_operations_log` ด้วย transactionId (UUIDv7), operator identity, command type, target system, status, timestamps — ห้ามเขียนลง DMS `audit_logs`
- **FR-014**: Hermes operations log MUST redact command payload ที่อาจมี secret, token, sensitive file path, หรือ production document content
- **FR-015**: Hermes MUST implement 6-stage gated rollout (Stage 05) โดยห้ามข้ามไปยัง stage ที่สูงกว่าโดยยังไม่ผ่าน acceptance gate
- **FR-016**: Hermes failure MUST NOT affect DMS production: frontend, backend, Workflow Engine, AI pipeline, and user-facing app ต้องทำงานตามปกติเมื่อ Hermes ล่ม
- **FR-017**: Hermes MUST NOT add or modify any DMS production schema (no SQL delta, no migration, no `user_telegram_mapping` creation)
- **FR-018**: `hermes proxy` MUST expose OpenAI-compatible API (port 8766) สำหรับ Developer AI Proxy เท่านั้น (ห้ามใช้ port 8765 ที่ PaddleOCR sidecar ใช้อยู่)
- **FR-019**: Hermes MUST use separate Redis instance/volume จาก DMS production Redis; queue names ต้องขึ้นต้นด้วย `hermes-`
- **FR-020**: All secrets (Telegram bot token, webhook secret, Gitea token, DB credential, proxy API key) MUST be stored ภายนอก repo ใน ASUSTOR secret store พร้อม rotation plan
### Key Entities
- **HermesAgent**: Docker container orchestrator รันบน ASUSTOR ควบคุม Development Loop ทั้งหมด
- **HermesTelegramGateway**: รับ inbound Telegram webhook, ตรวจสอบ allowlist + webhook secret + rate limit, forward ไปยัง DevOps Command Router
- **HermesTelegramDispatcher**: BullMQ Worker ดึงงานจาก `hermes-notification-queue` เพื่อส่ง outbound Telegram message พร้อม transactionId reference
- **HermesDevOpsCommandRouter**: Route และ execute DevOps commands ตาม permission tier (read-only / write-with-confirmation / forbidden)
- **HermesOperationsLog**: Hermes-owned log store (SQLite หรือ structured log) บันทึก inbound/outbound DevOps operations พร้อม transactionId และ redacted payload
- **HermesSubAgent**: Cloud AI delegate (Claude Haiku / GPT-4o-mini) รับ code generation task จาก Orchestrator และส่ง code diff กลับ
- **SOUL.md**: Container-local working journal บันทึก per-session task context, delegated sub-agents, iterations, PR results
- **DevQdrant**: Qdrant instance บน ASUSTOR (port 6334) สำหรับ codebase embeddings เท่านั้น — collection `lcbp3_code_chunks`
- **HermesProxy**: OpenAI-compatible API proxy (port 8766) สำหรับ Codex CLI / agy MCP integration
---
## Success Criteria _(mandatory)_
### Measurable Outcomes
- **SC-001**: Developer สามารถรับ PR link จาก Hermes ภายใน 30 นาที สำหรับ typical feature scaffolding task (เมื่อ sub-agent ผ่าน lint/tsc ใน iteration แรก)
- **SC-002**: Self-correction loop แก้ lint/tsc/test failures ได้ภายใน 3 iterations ≥ 80% ของกรณีก่อนที่จะ escalate ไป Developer
- **SC-003**: Telegram read-only commands (`/ci_status`, `/repo_summary`, `/status`) ตอบกลับภายใน 10 วินาที ≥ 95% ของ requests
- **SC-004**: DMS production availability (frontend/backend/Workflow Engine) ไม่ได้รับผลกระทบเมื่อ Hermes container ล่ม (0% downtime attributable to Hermes)
- **SC-005**: 100% ของ Telegram requests จาก non-allowlisted users ถูก reject โดยไม่มีการดำเนินการใดๆ
- **SC-006**: 100% ของ DevOps write actions มี transactionId บันทึกใน `hermes_operations_log` ก่อนดำเนิน action
- **SC-007**: All 6 rollout stage acceptance gates ผ่าน verification ก่อน advance ไปยัง stage ถัดไป ไม่มีกรณี skip gate
- **SC-008**: ไม่พบ production document content, DB query results, secrets, หรือ storage paths ใน Cloud AI request payloads (verified จาก proxy request logs)
- **SC-009**: hermes-bot ไม่มี push access ไปยัง `main`, `develop`, หรือ `release/*` branches (verified โดย Gitea branch protection + token scope test)
- **SC-010**: `hermes_operations_log` redacts ทุก payload ที่ตรวจพบ secret/token/sensitive-path ก่อนบันทึก (verified โดย secret scan ของ log output)
---
## Assumptions
- ADR-031 v2.0 Locked Decisions ทั้งหมดใช้บังคับและไม่อยู่ในขอบเขตที่เปลี่ยนได้โดย spec นี้
- Cloud AI exception (Claude/GPT-4o) สำหรับ Hermes dev orchestration layer ได้รับการอนุมัติแล้วใน ADR-031 v2.0
- ASUSTOR NAS มี Docker รองรับ resource limits (cpus/mem_limit); verified ด้วย `docker inspect`/`docker stats` ตาม ADR note
- Gitea `hermes-bot` service account และ Telegram bot ต้องถูกสร้างแยกต่างหากก่อน Stage 1/3
- inter-VLAN routing จาก ASUSTOR ไปยัง QNAP (MariaDB :3306, Gitea :3000) ต้องเปิดก่อน Stage 2
- DMS production Qdrant (ADR-023A, port 6333) และ Dev Qdrant (Hermes, port 6334) เป็นคนละ instance
## Out of Scope
- Production DMS Telegram commands (query/mutate documents, Workflow Engine actions) — ต้องเป็น ADR/spec แยก
- `user_telegram_mapping` table สำหรับ DMS — ห้ามสร้างใน ADR-031 rollout
- DMS production schema changes ทุกกรณี
- Direct integration ระหว่าง Hermes และ DMS BullMQ/Redis/Qdrant/Ollama
- Hermes เป็น DMS AI runtime path (ใช้ DMS Ollama pipeline ตาม ADR-023/023A)
@@ -0,0 +1,274 @@
// File: specs/200-fullstacks/231-hermes-agent/tasks.md
// Change Log:
// - 2026-05-29: Initial task list for Hermes Agent (ADR-031 v2.0)
# Tasks: Hermes Agent — Autonomous Dev Orchestrator & Telegram DevOps Bridge
**Input**: Design documents from `specs/200-fullstacks/231-hermes-agent/`
**Prerequisites**: plan.md ✅ | spec.md ✅ | research.md ✅ | data-model.md ✅ | contracts/ ✅ | quickstart.md ✅
**Organization**: Tasks grouped by user story (US1US5) for independent implementation and testing
**Staged Rollout**: US5 tasks map to Stage gates — do not skip stages
---
## Format: `[ID] [P?] [Story] Description`
- **[P]**: Can run in parallel (different files, no dependencies on incomplete tasks)
- **[Story]**: Which user story this task belongs to (US1US5)
- Paths below are relative to `hermes/` monorepo package root (standalone NestJS project)
---
## Phase 1: Setup (Hermes Project Initialization)
**Purpose**: Bootstrap `hermes/` project structure and Docker infrastructure
- [ ] T001 Create `hermes/` NestJS project: `package.json`, `tsconfig.json`, `nest-cli.json`, `.env.example` with TypeScript strict mode and all dependencies from plan.md
- [ ] T002 [P] Create `hermes/Dockerfile` — multi-stage Node.js 22 Alpine build for ASUSTOR deployment
- [ ] T003 [P] Create `specs/04-Infrastructure-OPS/04-00-docker-compose/ASUSTOR/hermes/docker-compose.hermes.yml` — hermes-agent container with CPU 2.0 / mem 4096M limits (fallback + deploy.resources per ADR-031 note)
- [ ] T004 [P] Create `specs/04-Infrastructure-OPS/04-00-docker-compose/ASUSTOR/hermes/docker-compose.hermes-redis.yml` — hermes-redis container with `hermes.redis.conf` (AOF persistence, maxmemory 512mb, isolated from DMS Redis)
- [ ] T005 [P] Create `specs/04-Infrastructure-OPS/04-00-docker-compose/ASUSTOR/hermes/docker-compose.hermes-qdrant.yml` — hermes-qdrant container on port 6334 (separated from DMS Qdrant port 6333)
- [ ] T006 Create `hermes/src/config/hermes.config.ts` — typed env vars (all secrets via env; no hardcoded values; ห้าม commit secret จริง)
- [ ] T007 Create `hermes/src/app.module.ts` — root module wiring all feature modules
**Checkpoint**: `docker compose -f docker-compose.hermes.yml up -d` รัน hermes container ได้; `docker inspect` แสดง resource limits ถูกต้อง
---
## Phase 2: Foundational (Core Infrastructure — Blocks All User Stories)
**Purpose**: Cross-cutting concerns ทุก user story ต้องอาศัย
**⚠️ CRITICAL**: No user story work can begin until this phase is complete
- [ ] T008 Create `hermes/src/common/utils/uuid.util.ts` — UUIDv7 generation ตาม ADR-019 (`generateTransactionId()` returns UUIDv7 string)
- [ ] T009 [P] Create `hermes/src/common/utils/secret-redactor.util.ts` — scan command payload สำหรับ secret/token/password/storage-path patterns แล้ว redact ก่อน log (FR-014)
- [ ] T010 [P] Create `hermes/src/common/guards/api-key.guard.ts` — validate `X-API-Key` header ต่อทุก non-webhook endpoint; return 401 ถ้าไม่ถูกต้อง
- [ ] T011 [P] Create `hermes/src/common/interceptors/transaction.interceptor.ts` — auto-generate UUIDv7 transactionId ต่อทุก request และ attach ลง response headers + request context
- [ ] T012 Create `hermes/src/operations/operations-log.service.ts` — SQLite CRUD สำหรับ `hermes_operations_log` (create entry, update status, find by transactionId); ใช้ `better-sqlite3`
- [ ] T013 [P] Create `hermes/src/operations/operations.module.ts` และ `hermes/src/operations/operations.controller.ts` — GET `/operations/logs` + GET `/operations/logs/:transactionId` (ตาม contracts/hermes-api.yaml)
- [ ] T014 Create `hermes/src/health/health.controller.ts` — GET `/health` returns `HermesStatus` with queue counts; no auth required (security: [])
- [ ] T015 [P] Write unit tests `hermes/test/unit/secret-redactor.spec.ts` — test cases: token patterns, password= patterns, storage paths, ไม่ redact code snippets / ADR content
- [ ] T054 [P] Write unit tests `hermes/test/unit/operations-log.spec.ts` — test cases: create entry, update status, findByTransactionId, redaction enforcement, retention boundary
**Checkpoint**: API Key guard ทำงาน; Operations log บันทึก/query ได้; Secret redactor pass tests; Health endpoint ตอบกลับ
---
## Phase 3: User Story 1 — Autonomous Dev Orchestrator (Priority: P1) 🎯 MVP
**Goal**: Developer ส่ง coding task → Hermes orchestrate sub-agents → self-correction loop → PR created
**Independent Test**: POST `/orchestration/tasks` ด้วย `{description: "scaffold NestJS health module", taskType: "DMS_FEATURE", telegramChatId: "test"}` → GET `/orchestration/tasks/:id` แสดง `status: PR_CREATED` + `prUrl` populated ภายใน expected timeout
### Implementation for User Story 1
- [ ] T016 [P] [US1] Create `hermes/src/qdrant/dev-qdrant.service.ts` — Qdrant JS client สำหรับ Dev Qdrant (ASUSTOR port 6334); collection `lcbp3_code_chunks`; search by `repoName`+`moduleName` (ไม่ใช้ `projectPublicId` filter)
- [ ] T017 [P] [US1] Create `hermes/src/orchestrator/context-loader.service.ts` — selective context loading ตาม task type (DEVOPS/DMS_FEATURE/SCHEMA_DB/BUG_FIX); โหลด CONTEXT-ADR-031.md + AGENTS.md เสมอ; เพิ่ม CONTEXT.md สำหรับ DMS_FEATURE; ห้าม load production DB query results
- [ ] T018 [P] [US1] Create `hermes/src/orchestrator/sub-agent.service.ts` — Cloud AI delegation: Claude Haiku/GPT-4o-mini สำหรับ code generation; Data Classification enforcement (ห้าม production data ใน prompt payload)
- [ ] T019 [US1] Create `hermes/src/orchestrator/self-correction.service.ts` — รัน lint/tsc/test ผ่าน MCP hermes-tools; วนซ้ำสูงสุด 3 iterations; ถ้า > 3 → escalate notification ผ่าน BullMQ (depends on T018)
- [ ] T020 [US1] Create `hermes/src/orchestrator/soul.service.ts` — read/append/rotate SOUL.md ที่ `/volume1/docker/hermes/SOUL.md`; rotate ทุก 30 วัน; ไม่ sync ลง repo
- [ ] T021 [US1] Create `hermes/src/orchestrator/orchestrator.service.ts` — main dev loop: context load → plan → sub-agent delegate → self-correction → commit via hermes-bot → create PR → record SOUL.md + operations log (depends on T016T020)
- [ ] T022 [US1] Create `hermes/src/orchestrator/orchestrator.controller.ts` — POST `/orchestration/tasks`, GET `/orchestration/tasks/:id` ตาม OpenAPI contract; ใช้ hermes-orchestration-queue (BullMQ)
- [ ] T023 [US1] Create `hermes/src/orchestrator/orchestrator.module.ts` — wire all orchestrator providers
- [ ] T024 [P] [US1] Write unit tests `hermes/test/unit/orchestrator.spec.ts` — test context loader (correct files per task type), sub-agent delegation call, self-correction loop iteration count enforcement
**Checkpoint**: POST orchestration task ได้รับ taskId; GET task แสดง status transitions; SOUL.md มี session entry; Dev Qdrant query ไม่แตะ DMS Qdrant
---
## Phase 4: User Story 2 — Telegram Read-only DevOps Commands (Priority: P2)
**Goal**: DevOps engineer ส่ง `/ci_status`, `/repo_summary`, `/status` ผ่าน Telegram และรับผลลัพธ์กลับ ≤ 10 วินาที
**Independent Test**: ส่ง webhook payload `/ci_status` พร้อม valid secret token + allowlisted user → ตรวจสอบ operations log entry + Telegram outbound message queued + BullMQ job created
### Implementation for User Story 2
- [ ] T025 [P] [US2] Create `hermes/src/integrations/gitea/gitea.service.ts` — read-only Gitea API methods: getLatestCI(), getRepoSummary(), getIssues(), getPRs(); ใช้ read-only token; ห้าม write operations ใน phase นี้
- [ ] T026 [P] [US2] Create `hermes/src/integrations/telegram/telegram-rate-limiter.service.ts` — Redis-based rate limit: `hermes:telegram:{userId}` key, incr + expire 60s, threshold 10 req/min (FR-011)
- [ ] T027 [US2] Create `hermes/src/integrations/telegram/hermes-telegram-gateway.ts` — inbound webhook handler: verify `X-Telegram-Bot-Api-Secret-Token` → check allowlist → check rate limit → record inbound to operations log → dispatch to command router (depends on T025, T026)
- [ ] T028 [US2] Create `hermes/src/integrations/telegram/hermes-devops-command-router.ts` — route read-only commands (/status, /ci_status, /repo_summary, /audit_summary, /help); queue outbound response via BullMQ hermes-notification-queue (depends on T027)
- [ ] T029 [US2] Create `hermes/src/integrations/telegram/hermes-telegram-dispatcher.ts` — BullMQ Worker @Processor('hermes-notification-queue'): @Process('telegram-devops-outbound') — send via Telegram Bot API; record outbound to operations log; retry 3x exponential backoff (ADR-007, FR-012)
- [ ] T030 [US2] Create `hermes/src/integrations/telegram/telegram.module.ts` — wire all telegram providers + BullMQ queue registration
- [ ] T031 [P] [US2] Write unit tests `hermes/test/unit/telegram-gateway.spec.ts` — webhook secret verification, allowlist rejection, rate limit enforcement, operations log inbound record (depends on T027)
- [ ] T032 [P] [US2] Write unit tests `hermes/test/unit/command-router.spec.ts` — command routing (/ prefix parsing), forbidden command detection, outbound job queuing (depends on T028)
**Checkpoint**: POST `/telegram/webhook` ด้วย wrong secret → 401; non-allowlisted user → rejected; valid read-only command → operations log entry + BullMQ job created
---
## Phase 5: User Story 3 — Telegram Write-with-Confirmation (Priority: P3)
**Goal**: DevOps engineer สั่ง write action → Hermes ขอ confirmation → ดำเนิน action → บันทึก operations log
**Independent Test**: ส่ง "สร้าง branch proposal สำหรับ fix/test" → รับ confirmation prompt → ยืนยัน → Gitea branch `hermes/fix-test` ถูกสร้าง + operations log มี git write entry + forbidden action blocklist ทำงาน
### Implementation for User Story 3
- [ ] T033 [P] [US3] Extend `hermes/src/integrations/gitea/gitea.service.ts` — เพิ่ม write methods: createBranch(), createIssue(), createPR(), triggerCI() ใช้ write token แยก (least privilege, ไม่ใช่ admin token); branch pattern validation (hermes/*)
- [ ] T034 [US3] Extend `hermes/src/integrations/telegram/hermes-devops-command-router.ts` — เพิ่ม write-with-confirmation flow: (1) parse write intent → (2) show action summary → (3) wait for explicit confirmation → (4) execute → (5) record operations log; forbidden action blocklist (push main/develop, production deploy, schema migration, direct DB write, storage delete) → reject immediately
- [ ] T035 [US3] Integrate `hermes-bot` Git identity ใน `hermes/src/orchestrator/orchestrator.service.ts``simple-git` config: user.name "Hermes Bot", user.email "hermes-bot@np-dms.work"; push เฉพาะ `hermes/*` branches; commit message format: `"feat(hermes): {task description}\n\nOrchestrated by Hermes ADR-031 v2.0"`
- [ ] T036 [P] [US3] Write operations log record ใน `hermes/src/operations/operations-log.service.ts` สำหรับ Git write actions — บันทึก `gitea_token_identity`, `target_repo`, `target_branch`, status ก่อนและหลัง action (depends on T033)
**Checkpoint**: Write command ต้องการ confirmation; hermes-bot branch creation ใช้ pattern `hermes/fix-*`; forbidden actions ถูก blocked; operations log มี token identity record
---
## Phase 6: User Story 4 — Developer AI Proxy (Priority: P4)
**Goal**: Developer ใช้ Codex CLI / agy โดยชี้ `OPENAI_BASE_URL``hermes proxy` port 8766 รับ request สำหรับ coding/devops assistance เท่านั้น
**Independent Test**: ตั้ง OPENAI_BASE_URL → hermes proxy → ส่ง coding request → รับ response พร้อม DMS context; ส่ง payload ที่มี password/token → ถูก reject + redact log
### Implementation for User Story 4
- [ ] T037 [US4] Create `hermes/src/proxy/proxy.service.ts` — OpenAI-compatible API (port 8766); forward coding/devops requests ไป Cloud AI พร้อม DMS context injection; validate payload ไม่มี production data (ใช้ secret-redactor.util.ts); ห้าม forward ถ้าตรวจพบ production data
- [ ] T038 [US4] Create `hermes/src/proxy/proxy.module.ts` + controller — bind ที่ port 8766 แยกจาก main API port 8080; API Key auth; LAN/VPN-only note ใน config
- [ ] T039 [P] [US4] Create `hermes/src/integrations/mcp/mcp-server.service.ts` — expose `/mcp` endpoint สำหรับ agy + Windsurf integration; implement `hermes-memory` tool (recall DMS context); implement `hermes-tools` tool (bash/git execution on ASUSTOR)
- [ ] T040 [P] [US4] Create `hermes/src/integrations/mcp/mcp.module.ts` — wire MCP server providers
- [ ] T041 [P] [US4] Verify port isolation: proxy port 8766 ≠ PaddleOCR sidecar port 8765 (ADR-023A) — add port validation assertion ใน `hermes/src/config/hermes.config.ts` ที่ startup
**Checkpoint**: `curl http://<ASUSTOR_IP>:8766/v1/models` returns models list; payload ที่มี "password:" ถูก reject; `/mcp` endpoint accessible; port 8765 ไม่ถูก bind โดย Hermes
---
## Phase 7: User Story 5 — Staged Rollout & Health Monitoring (Priority: P5)
**Goal**: Admin deploy Hermes ผ่าน 6-stage gated rollout พร้อม monitoring ที่แยก Hermes health จาก DMS
**Independent Test**: ปิด hermes container → ตรวจสอบ DMS frontend/backend/workflow-engine response 200; Hermes down alert ≠ DMS production outage alert
### Implementation for User Story 5
- [ ] T042 [P] [US5] Create `specs/04-Infrastructure-OPS/04-00-docker-compose/ASUSTOR/hermes/stage-gates/` — checklist files per stage (stage-0.md → stage-5.md) ตาม quickstart.md acceptance gates; แต่ละ gate มี verification commands และ pass/fail criteria
- [ ] T043 [US5] Extend `hermes/src/health/health.controller.ts` (extends T014) — เพิ่ม subsystem health: Redis status, Dev Qdrant status, Operations log status, hermes proxy status, BullMQ queue depths; return `HermesStatus` object ครบถ้วนตาม contracts/hermes-api.yaml
- [ ] T044 [P] [US5] Create monitoring alert configuration: Hermes down / Telegram Bridge down / MCP unavailable / hermes proxy down = DevOps warning (ไม่ใช่ DMS production outage); repeated auth failure / rate limit spike = security alert; document ใน `specs/04-Infrastructure-OPS/04-00-docker-compose/ASUSTOR/hermes/monitoring-alerts.md`
- [ ] T045 [P] [US5] Write failure isolation verification script `specs/04-Infrastructure-OPS/04-00-docker-compose/ASUSTOR/hermes/verify-isolation.sh``docker stop hermes_agent_lcbp3` แล้ว check DMS endpoints return 200; ใช้ใน Stage 1 acceptance gate
- [ ] T046 [P] [US5] Create SOUL.md rotation cron job: เพิ่ม cron schedule ใน `hermes/src/orchestrator/soul.service.ts` สำหรับ rotate ทุก 30 วัน (archive + clear SOUL.md)
**Checkpoint**: Health endpoint แสดง subsystem status ครบถ้วน; Stage gate checklists ครบ 6 stages; Failure isolation test pass (DMS ยังทำงานเมื่อ Hermes ล่ม)
---
## Phase 8: Polish & Cross-Cutting Concerns
**Purpose**: Quality, security, và documentation finalization
- [ ] T047 [P] Verify all TypeScript files have `// File:` header and `// Change Log:` comments ตาม AGENTS.md; JSDoc สำหรับ public classes (Thai comments)
- [ ] T048 [P] Replace all `console.log` ด้วย NestJS Logger (`this.logger.log/warn/error`) ทั่วทั้ง `hermes/src/`
- [ ] T049 Secret scan validation: ตรวจสอบว่าไม่มี secret จริงใน `hermes/` source tree, compose files, `.env.example`, หรือ spec files; เพิ่ม pre-commit hook (mandatory — FR-020)
- [ ] T050 [P] Resource limit verification: สร้าง `specs/04-Infrastructure-OPS/04-00-docker-compose/ASUSTOR/hermes/verify-resources.sh``docker inspect` + `docker stats` แล้วเปรียบเทียบกับ expected limits (CPU 2.0 / RAM 4096MB)
- [ ] T051 [P] Data Classification audit: review hermes proxy + sub-agent service code ว่าไม่มี production DB query results หรือ document content ใน Cloud AI request payloads
- [ ] T052 Run `quickstart.md` staged verification (Stage 0 → Stage 5) และ update checklist results; document final rollout status
- [ ] T053 [P] Create `specs/04-Infrastructure-OPS/04-00-docker-compose/ASUSTOR/hermes/secret-rotation.md` — Secret rotation runbook สำหรับ `HERMES_PROXY_API_KEY`, Telegram bot token, Gitea read-only + write tokens, read-only DB credential; include rotation schedule, revocation steps, และ operator offboarding procedure (FR-020)
---
## Dependencies & Execution Order
### Phase Dependencies
- **Phase 1 (Setup)**: ไม่มี dependency — เริ่มทันที
- **Phase 2 (Foundational)**: ต้องการ Phase 1 — **BLOCKS ทุก user story**
- **Phase 3 (US1)**: ต้องการ Phase 2 เสร็จ — เป็น MVP
- **Phase 4 (US2)**: ต้องการ Phase 2 เสร็จ — สามารถขนาน Phase 3 ได้
- **Phase 5 (US3)**: ต้องการ Phase 4 เสร็จ (extends Telegram dispatcher) + Phase 3 บางส่วน (hermes-bot git)
- **Phase 6 (US4)**: ต้องการ Phase 2 เสร็จ — สามารถขนาน Phase 3/4 ได้
- **Phase 7 (US5)**: ต้องการ Phase 3+4 เสร็จเพื่อ health checks ครบถ้วน
- **Phase 8 (Polish)**: ต้องการทุก user story phase เสร็จ
### User Story Dependencies
- **US1 (P1)**: Phase 2 เสร็จ; ไม่ขึ้นกับ US2/US3/US4/US5
- **US2 (P2)**: Phase 2 เสร็จ; ไม่ขึ้นกับ US1/US3/US4/US5
- **US3 (P3)**: US2 (Phase 4) เสร็จ + US1 hermes-bot integration บางส่วน
- **US4 (P4)**: Phase 2 เสร็จ; ไม่ขึ้นกับ US1/US2/US3
- **US5 (P5)**: US1+US2 เสร็จสำหรับ health checks; สามารถเริ่ม stage-gate docs ขนานได้ตั้งแต่ Phase 1
### Within Each User Story
- Utilities/Guards (T008-T015) ก่อน feature implementation
- Service → Controller → Module ordering
- Unit tests [P] สามารถเขียนขนานกับ implementation ที่ไม่มี circular dependency
---
## Parallel Execution Examples
### Phase 2 (Foundational — parallel within phase):
```bash
# รันพร้อมกัน:
T008: uuid.util.ts
T009: secret-redactor.util.ts
T010: api-key.guard.ts
T011: transaction.interceptor.ts
T014: health.controller.ts
T015: secret-redactor.spec.ts
```
### Phase 3 US1 (parallel foundations before orchestrator):
```bash
# รันพร้อมกัน:
T016: dev-qdrant.service.ts
T017: context-loader.service.ts
T018: sub-agent.service.ts
# รอ T016-T018 เสร็จ → T019, T020
# รอ T019-T020 เสร็จ → T021, T022
```
### Phase 4+6 (US2 และ US4 ขนานกับ US1):
```bash
# ขณะที่ทีม A ทำ US1 (Phase 3):
# ทีม B ทำ US2 (Phase 4): T025, T026 ก่อน → T027 → T028, T029
# ทีม C ทำ US4 (Phase 6): T037, T038, T039 ขนานกัน
```
---
## Implementation Strategy
### MVP First (US1 Only — Autonomous Dev Orchestrator)
1. Complete Phase 1: Setup
2. Complete Phase 2: Foundational (CRITICAL)
3. Complete Phase 3: US1 — Autonomous Dev Orchestrator
4. **STOP + VALIDATE**: ส่ง coding task → ตรวจสอบ PR created in Gitea
5. Demo to developer team
### Incremental Delivery
1. Setup + Foundational → Foundation ready (Stage 1 acceptance gate ✅)
2. Add US1 → Autonomous coding loop (MVP) → demo
3. Add US2 → Telegram read-only DevOps (Stage 3 acceptance gate ✅)
4. Add US3 → Write-with-confirmation (Stage 4 acceptance gate ✅)
5. Add US4 → Developer AI Proxy (Stage 5 acceptance gate ✅)
6. Add US5 → Full monitoring + staged rollout docs complete
### Staged Rollout Alignment
| Deployment Stage | Prerequisite Tasks |
|------------------|--------------------|
| Stage 0 (Docs) | T001T007 (Setup) |
| Stage 1 (LAN container) | T008T015 (Foundational) + T042, T045 |
| Stage 2 (Read-only DB/Gitea) | T025 (Gitea read-only) |
| Stage 3 (Telegram read-only) | T026T032 (US2 complete) |
| Stage 4 (Write-with-confirmation) | T033T036 (US3 complete) |
| Stage 5 (Proxy) | T037T041 (US4 complete) |
---
## Notes
- [P] tasks = different files, no dependency conflicts — safe to parallelize
- hermes-bot Gitea token ต้องสร้างก่อน T033/T035
- Telegram bot token ต้องสร้างก่อน T027
- ห้าม commit secret จริงใน `.env.example` หรือ compose files — placeholder only
- ทุก TypeScript file ต้องขึ้นต้นด้วย `// File: hermes/src/...` ตาม AGENTS.md
- ห้ามใช้ DMS production Redis, DMS Qdrant, DMS `audit_logs` ทุกกรณี
- ADR-031 Stage gate ต้องผ่านก่อน deploy stage ถัดไป — ห้าม skip