6.0 KiB
6.0 KiB
title, updated, tags
| title | updated | tags | |||
|---|---|---|---|---|---|
| Outline Wiki | 2026-04-08 |
|
개요
Outline은 팀 위키/문서 관리 플랫폼. K3s 클러스터에 배포.
| 항목 | 값 |
|---|---|
| URL | https://outline.inouter.com |
| 네임스페이스 | outline |
| 이미지 | outlinewiki/outline:0.82.0 |
| 인증 | Gitea OAuth2 (OIDC) |
| 기본 언어 | 한국어 |
구성 요소
| 컴포넌트 | 설정 |
|---|---|
| DB | Patroni HA via OpenWrt HAProxy (192.168.9.1:5432), DB명: outline, 유저: outline |
| Redis | outline-redis (outline 네임스페이스 내 전용) |
| 파일 저장소 | 로컬 (Longhorn PVC 5Gi, /var/lib/outline/data) |
| TLS (Traefik) | wildcard-inouter-tls (*.inouter.com) |
| TLS (CDN) | Let's Encrypt via BunnyCDN |
| CDN | BunnyCDN iron-kr 존 (ID 5555227, 쿠키 허용) |
| DNS | outline.inouter.com CNAME → iron-kr.b-cdn.net (Cloudflare, proxied OFF) |
| Ingress | Traefik IngressRoute (CRD) |
인증 (Gitea OAuth2)
| 항목 | 값 |
|---|---|
| OIDC Provider | Gitea (gitea.inouter.com) |
| Client ID | cb804835-416c-4730-86b4-26d2c129b164 |
| Redirect URI | https://outline.inouter.com/auth/oidc.callback |
| OIDC Endpoints | authorize, access_token, userinfo (Gitea 표준) |
| Client Secret | Vault secret/apps/outline 참조 |
시크릿
Kubernetes Secret: outline-secrets (outline 네임스페이스)
- SECRET_KEY, UTILS_SECRET, DATABASE_URL, REDIS_URL
- OIDC_CLIENT_ID, OIDC_CLIENT_SECRET, OIDC 엔드포인트들
pgcat 연동
현재 pgcat 미사용 (직접 PostgreSQL 접속). 필요 시 pgcat pool 추가 가능.
MCP 연동
Outline MCP 서버 도입 시 헤임달이 직접 문서 CRUD 가능.
- 참고: https://github.com/Vortiago/mcp-outline
- heimdall
~/.claude.json/root프로젝트 mcpServers에outline항목 추가 (stdio,uvx mcp-outline,OUTLINE_API_KEY는 Vaultsecret/apps/outlinebrokkr-api-key,OUTLINE_API_URL=https://outline.inouter.com) - 새 컬렉션
agent-qna(idc3ab34ab-fae4-4642-8f4e-12728e293e1b) — 에이전트 간 장문 Q&A 교환 공간 (kappa↔heimdall이 tmux로 짧게 질문 → 답변은 여기에 작성)
DB endpoint는 OpenWrt HAProxy(192.168.9.1:5432) 경유. 과거 Patroni failover 사고 이력: 2026-04-08-patroni-failover-incident
Discord 통지 파이프라인
agent-qna 컬렉션에 새 문서가 만들어지면 heimdall Discord 채널(#heimdall, id 1488119168145555486)에 자동 알림이 뜬다. 다른 컬렉션은 무시한다.
Outline (documents.create webhook)
→ n8n webhook (https://n8n.inouter.com/webhook/outline-to-discord)
→ Code 노드 (collectionId 필터 + Discord embed 빌드)
→ HTTP Request 노드 (Discord Bot API: POST /channels/{id}/messages)
구성 요소 위치
| 항목 | 값 |
|---|---|
| n8n workflow id | 8P714i5oBs9HkZPK |
| n8n workflow 이름 | outline-to-discord (heimdall) |
| n8n webhook path | /webhook/outline-to-discord (POST, responseMode=onReceived) |
| n8n 노드 구성 | Webhook → Filter+Format(Code) → Discord POST(HTTP) |
| Outline webhook id | ede9327f-b09e-4f7e-ab56-c507d3d1b3a6 (documents.create 이벤트) |
| Outline collection 필터 | c3ab34ab-fae4-4642-8f4e-12728e293e1b (agent-qna) — Code 노드 안에 하드코딩 |
| Discord channel | guild 1469999069190557799 의 #heimdall 채널 (id 1488119168145555486) |
| Discord bot | username Heimdall (id 1487694864232611922) |
시크릿
| 비밀 | Vault 경로 |
|---|---|
| Discord bot token | secret/apps/discord → bot_token (현재는 n8n Code 노드에 하드코딩되어 있음 — Credentials로 분리하는 게 더 깔끔, 후속 작업) |
| Discord channel/guild ID | secret/apps/discord → heimdall_channel_id, heimdall_guild_id |
| n8n API key | secret/apps/n8n → api_key (label: heimdall-automation) |
| n8n owner login | secret/apps/n8n → email(kappa@inouter.com), password |
| Outline API token | secret/apps/outline → brokkr-api-key |
메시지 포맷 (Discord embed)
- title:
📝 <doc title> - url:
https://outline.inouter.com<payload.model.url> - description: 본문 앞 200자 (개행 → 공백)
- author.name:
outline / agent-qna · <createdBy.name> - color:
0x00bcd4(cyan) - timestamp:
payload.model.createdAt
트러블슈팅
증상별 점검 순서:
- 알림이 아예 안 옴
- Outline UI 또는 API로 webhook subscription 활성 확인
curl -sS -X POST https://outline.inouter.com/api/webhookSubscriptions.list \ -H "Authorization: Bearer $OL_TOKEN" -d '{}' | jq . - n8n에서 workflow active 여부 확인 (
/api/v1/workflows/8P714i5oBs9HkZPK) - n8n executions에 webhook 도달했는지 확인 (
/api/v1/executions?workflowId=8P714i5oBs9HkZPK&limit=10)
- Outline UI 또는 API로 webhook subscription 활성 확인
- n8n에 도달하나 Discord POST가 안 일어남
- 거의 항상 collectionId 필터 미스매치. Filter+Format Code 노드의
out items: 0이면 정상 (필터된 것) - 필터를 통과해야 하는데 0 items면 payload.event 또는 payload.model.collectionId 구조 확인
- 거의 항상 collectionId 필터 미스매치. Filter+Format Code 노드의
- n8n DB connection timeout
- n8n pod 재시작:
kubectl -n n8n delete pod -l app.kubernetes.io/name=n8n - pgcat → 192.168.9.1:5432 (Patroni leader) 경로 확인
- n8n pod 재시작:
- Discord 401/403
- bot token 재발급 필요 (
secret/apps/discord갱신, n8n Code 노드의 하드코딩도 함께 갱신) - bot이 채널에 access 권한 있는지:
GET /channels/{channel_id}200이면 OK
- bot token 재발급 필요 (
- Outline → n8n 호출이 BunnyCDN 508
- 일시적. 재시도하면 풀린다. BunnyCDN edge의
cdn-loopcount룰 (자세한 원인 불명, retry로 회피)
- 일시적. 재시도하면 풀린다. BunnyCDN edge의
후속 작업 (선택)
- Discord bot token을 n8n Credentials로 분리 (현재 Code 노드에 하드코딩)
- Outline signing secret 지원되면 HMAC 서명 검증 추가 (현재 미적용 — 같은 인프라 내부 호출이라 위험 낮음)
documents.update이벤트도 추가 (현재 create만)- 다른 컬렉션 (예: incident postmortem)도 동일 패턴으로 통지 추가