feat: add momentry_playground binary for development

- Add separate momentry_playground binary with distinct configuration
- Production (momentry): Port 3002, Redis prefix 'momentry:'
- Development (momentry_playground): Port 3003, Redis prefix 'momentry_dev:'
- Add SERVER_PORT and REDIS_KEY_PREFIX config via environment variables
- Replace all hardcoded Redis key prefixes with configurable values
- Create .env.development for playground environment settings
- Update .env with production defaults
- Add dotenv dependency for environment file loading

Configuration isolation allows running both binaries simultaneously
without port conflicts or Redis key collisions.
This commit is contained in:
accusys
2026-03-25 00:40:31 +08:00
parent 13e208b569
commit 732ef9296b
16 changed files with 8381 additions and 366 deletions

View File

@@ -0,0 +1,376 @@
# Playground Binary Implementation Plan
## Overview
Create separate `momentry_playground` binary with distinct configuration from `momentry` (production).
| Aspect | Production (`momentry`) | Development (`momentry_playground`) |
|--------|------------------------|-------------------------------------|
| **Port** | 3002 | 3003 |
| **Redis Prefix** | `momentry:` | `momentry_dev:` |
| **Worker** | Enabled | Disabled |
| **Purpose** | Production deployment | Testing/Development |
---
## Files to Modify
```
Files Changed: 6 files (+1 new)
├── src/core/config.rs ← Add server_port(), redis_key_prefix()
├── src/core/db/redis_client.rs ← Replace hardcoded prefixes
├── src/core/cache/redis_cache.rs ← Use configurable prefix
├── src/main.rs ← Update CLI defaults
├── src/playground.rs ← NEW: Development binary
├── Cargo.toml ← Add new binary
└── .env.development ← NEW: Dev environment config
```
---
## Implementation Steps
### Step 1: Update `src/core/config.rs`
Add after line 51 (after `MEDIA_BASE_URL`):
```rust
pub static SERVER_PORT: Lazy<u16> = Lazy::new(|| {
env::var("MOMENTRY_SERVER_PORT")
.unwrap_or_else(|_| "3002".to_string())
.parse()
.unwrap_or(3002)
});
pub static REDIS_KEY_PREFIX: Lazy<String> = Lazy::new(|| {
env::var("MOMENTRY_REDIS_PREFIX")
.unwrap_or_else(|_| "momentry:".to_string())
});
```
---
### Step 2: Update `src/core/db/redis_client.rs`
Replace all hardcoded `momentry:` prefixes with configurable prefix.
**Import at top:**
```rust
use crate::core::config::REDIS_KEY_PREFIX;
```
**Pattern for each method:**
```rust
let prefix = REDIS_KEY_PREFIX.as_str();
let key = format!("{}job:{}", prefix, uuid);
```
**Affected lines:**
| Line | Key Pattern |
|------|-------------|
| 47 | `job:{uuid}` |
| 81, 109 | `job:{uuid}:processor:{processor}` |
| 136, 146 | `progress:{uuid}` |
| 172 | `jobs:active` |
| 179 | `jobs:active``jobs:completed` |
| 187 | `jobs:active``jobs:failed` |
| 194 | `jobs:active` |
| 201, 208 | `health:momentry_core` |
| 214 | `monitor:job:{uuid}` |
| 242, 300 | `errors:{uuid}` |
| 258, 281 | `anomaly:alerts`, `anomaly:key:{key_id}` |
| 317, 346, 364, 392, 397 | `worker:job:{uuid}...` |
| 406, 410 | `worker:job:*` |
---
### Step 3: Update `src/core/cache/redis_cache.rs`
**Import:**
```rust
use crate::core::config::REDIS_KEY_PREFIX;
```
**Replace line 10:**
```rust
// Remove: const KEY_PREFIX: &str = "momentry:cache:";
```
**Update `prefixed_key` method (line 24):**
```rust
fn prefixed_key(&self, key: &str) -> String {
format!("{}cache:{}", REDIS_KEY_PREFIX.as_str(), key)
}
```
**Update tests (lines 161-162):**
```rust
#[test]
fn test_prefixed_key() {
// Note: This test will use the configured prefix
let cache = RedisCache::new().unwrap();
// With default prefix "momentry:"
assert_eq!(cache.prefixed_key("test"), "momentry:cache:test");
assert_eq!(cache.prefixed_key("video:abc"), "momentry:cache:video:abc");
}
```
---
### Step 4: Update `src/main.rs`
**Change CLI defaults (Lines 691-695):**
```rust
// Before:
#[arg(long, default_value = "3000")]
port: u16,
// After:
#[arg(long)]
port: Option<u16>,
```
**Update Server match arm (around line 2398):**
```rust
Commands::Server { host, port } => {
let port = port.unwrap_or_else(|| *crate::core::config::SERVER_PORT);
momentry_core::api::start_server(&host, port).await?;
Ok(())
}
```
**Update Redis key usage (Line 1098):**
```rust
// Before:
let key = format!("momentry:job:{}:processor:{}", uuid, processor);
// After:
let key = format!(
"{}job:{}:processor:{}",
crate::core::config::REDIS_KEY_PREFIX.as_str(),
uuid,
processor
);
```
---
### Step 5: Create `src/playground.rs`
```rust
use anyhow::{Context, Result};
use clap::{Parser, Subcommand};
// ... same imports as main.rs ...
fn main() -> Result<()> {
// Load development environment first
dotenv::from_filename(".env.development").ok();
tracing_subscriber::fmt::init();
tracing::info!("Starting momentry_playground (development binary)");
tracing::info!("Port: {}", *momentry_core::core::config::SERVER_PORT);
tracing::info!("Redis prefix: {}", *momentry_core::core::config::REDIS_KEY_PREFIX);
let cli = Cli::parse();
// ... rest identical to main.rs ...
}
```
---
### Step 6: Update `Cargo.toml`
**Add after line 90:**
```toml
[[bin]]
name = "momentry_playground"
path = "src/playground.rs"
```
**Add dependency (if not present):**
```toml
dotenv = "0.15"
```
---
### Step 7: Create `.env.development`
```bash
# Development Environment Configuration
# Used by: momentry_playground binary
# Server Configuration
MOMENTRY_SERVER_PORT=3003
MOMENTRY_REDIS_PREFIX=momentry_dev:
# Worker Configuration (disabled for development)
MOMENTRY_WORKER_ENABLED=false
MOMENTRY_MAX_CONCURRENT=1
MOMENTRY_POLL_INTERVAL=10
# Database (can use separate dev database)
DATABASE_URL=postgres://accusys@localhost:5432/momentry
MONGODB_URL=mongodb://accusys:Test3200Test3200@localhost:27017/admin
# Redis
REDIS_URL=redis://:accusys@localhost:6379
```
---
### Step 8: Update `.env` (Production)
Add these lines:
```bash
# Production Environment Configuration
# Used by: momentry binary
# Server Configuration
MOMENTRY_SERVER_PORT=3002
MOMENTRY_REDIS_PREFIX=momentry:
# Worker Configuration
MOMENTRY_WORKER_ENABLED=true
MOMENTRY_MAX_CONCURRENT=2
MOMENTRY_POLL_INTERVAL=5
```
---
## Testing Checklist
### 1. Build and Run Production Binary
```bash
cargo build --release --bin momentry
cargo run --bin momentry -- server
# Expected: Listening on http://127.0.0.1:3002
cargo run --bin momentry -- worker
# Expected: Worker started with momentry: prefix
```
### 2. Build and Run Development Binary
```bash
cargo build --bin momentry_playground
cargo run --bin momentry_playground -- server
# Expected: Listening on http://127.0.0.1:3003
```
### 3. Verify Redis Key Isolation
```bash
# Production data
redis-cli KEYS "momentry:*"
# Development data
redis-cli KEYS "momentry_dev:*"
# Should be separate
```
### 4. Run Both Simultaneously
```bash
# Terminal 1: Production
cargo run --bin momentry -- server
# Terminal 2: Development
cargo run --bin momentry_playground -- server
# Both should run without port conflicts
```
### 5. Unit Tests
```bash
cargo test --lib
# All tests should pass
```
---
## Redis Key Structure
### Production (`momentry:`)
```
momentry:job:{uuid} # Job status
momentry:job:{uuid}:processor:{name} # Processor progress
momentry:progress:{uuid} # Progress pub/sub
momentry:jobs:active # Active job set
momentry:jobs:completed # Completed job set
momentry:jobs:failed # Failed job set
momentry:health:momentry_core # Health status
momentry:cache:{key} # Cache entries
momentry:worker:job:{uuid} # Worker job
momentry:worker:job:{uuid}:processor:{name}
```
### Development (`momentry_dev:`)
```
momentry_dev:job:{uuid}
momentry_dev:job:{uuid}:processor:{name}
momentry_dev:progress:{uuid}
momentry_dev:jobs:active
momentry_dev:jobs:completed
momentry_dev:jobs:failed
momentry_dev:health:momentry_core
momentry_dev:cache:{key}
momentry_dev:worker:job:{uuid}
momentry_dev:worker:job:{uuid}:processor:{name}
```
---
## Potential Issues & Solutions
| Issue | Solution |
|-------|----------|
| `dotenv` crate not in dependencies | Add to Cargo.toml |
| Tests use hardcoded prefix | Update tests to use config, or use `#[cfg(test)]` defaults |
| Worker starts in playground | Check `MOMENTRY_WORKER_ENABLED=false` in `.env.development` |
| Port already in use | Graceful error message with suggestion to use `--port` flag |
| Mixed data in Redis | Ensure prefix is loaded before any Redis operations |
---
## Files Summary
| File | Lines Changed | Purpose |
|------|---------------|---------|
| `src/core/config.rs` | +15 | Add SERVER_PORT and REDIS_KEY_PREFIX |
| `src/core/db/redis_client.rs` | ~50 | Replace hardcoded prefixes |
| `src/core/cache/redis_cache.rs` | ~10 | Use configurable prefix |
| `src/main.rs` | ~15 | Update CLI defaults, Redis key usage |
| `src/playground.rs` | NEW (~2800) | Development binary |
| `Cargo.toml` | +4 | Add binary definition |
| `.env.development` | NEW (~20) | Development environment |
**Total**: ~60 lines modified + ~2800 lines new file
---
## Reference Documents
| Document | Purpose |
|----------|---------|
| `docs/SERVICES.md` | Port allocations |
| `docs/MOMENTRY_CORE_REDIS_KEYS.md` | Redis key design |
| `AGENTS.md` | Code style and conventions |
---
## Version History
| Version | Date | Author | Changes |
|---------|------|--------|---------|
| 1.0 | 2025-03-25 | OpenCode | Initial implementation plan |

View File

@@ -1,31 +1,167 @@
# Momentry 系統服務安裝與管理指南
| 項目 | 內容 |
|------|------|
| 建立者 | Warren |
| 建立時間 | 2026-03-18 |
| 更新時間 | 2026-03-24 |
| 文件版本 | V1.1 |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|------|------|------|--------|-----------|
| V1.0 | 2026-03-18 | 創建文件 | Warren | OpenCode / MiniMax M2.5 |
| V1.1 | 2026-03-24 | 更新所有服務 plist 狀態,統一使用自定義 plist | OpenCode | OpenCode / big-pickle |
---
## 概述
本文檔記錄 momentry 系統所需的所有服務,包括安裝步驟、健康檢查和管理命令。
**重要**: 請勿使用 `brew services` 命令管理服務,否則可能導致 .plist 檔案還原為預設狀態,造成系統異常。請使用 `launchctl` 命令進行管理。
**2026-03-24 更新**: 所有服務已統一使用自定義 plist存在於 `/Library/LaunchDaemons/` 目錄。Reboot 後會自動啟動。
---
## 服務清單
| 服務名稱 | 安裝方式 | 用途 | 狀態 |
|----------|----------|------|-------|
| PostgreSQL | Homebrew | 影片元資料儲存 | 已安裝 |
| Redis | Homebrew | 快取與工作佇列 | 已安裝 |
| Ollama | Homebrew | 本地 LLM 推論 | 已安裝 |
| Caddy | Homebrew | 網頁伺服器 (可選) | 已安裝 |
| Gitea | 手動安裝 | Git 服務 | 已安裝 |
| Grafana | Homebrew | 監控儀表板 | 已安裝 |
| Kafka | 手動安裝 | 訊息佇列 (可選) | 已安裝 |
| MariaDB | Homebrew | 資料庫 (可選) | 已安裝 |
| Netdata | Homebrew | 系統監控 | 已安裝 |
| PHP | Homebrew | Web 後端 | 已安裝 |
| Prometheus | Homebrew | 指標收集 | 已安裝 |
| SeaweedFS | 手動安裝 | 分散式儲存 (可選) | 已安裝 |
| SFTPGo | 手動安裝 | SFTP 服務 | 已安裝 |
| n8n | Homebrew | 工作流自動化 | 已安裝 |
| PostgreSQL | 自定義 plist | 影片元資料儲存 | ✅ 正常 |
| Redis | 自定義 plist | 快取與工作佇列 | ✅ 正常 |
| Ollama | 自定義 plist | 本地 LLM 推論 | ✅ 正常 |
| Caddy | 自定義 plist | 網頁伺服器 | ✅ 正常 |
| Gitea | 自定義 plist | Git 服務 | ✅ 正常 |
| Gitea MCP Server | 自定義 plist | Gitea MCP 整合 | ✅ 正常 |
| Grafana | Homebrew | 監控儀表板 | ⚠️ Homebrew |
| Kafka | 手動安裝 | 訊息佇列 (可選) | ⚠️ 未遷移 |
| MariaDB | 自定義 plist | 資料庫 (可選) | ✅ 正常 |
| Netdata | Homebrew | 系統監控 | ⚠️ Homebrew |
| PHP | 自定義 plist | Web 後端 | ✅ 正常 |
| Prometheus | Homebrew | 指標收集 | ⚠️ Homebrew |
| SeaweedFS | 手動安裝 | 分散式儲存 (可選) | ⚠️ 未遷移 |
| SFTPGo | 自定義 plist | SFTP 服務 | ✅ 正常 |
| n8n | 自定義 plist | 工作流自動化 | ✅ 正常 |
| n8n Worker | 自定義 plist | 工作流 Worker | ✅ 正常 |
| MongoDB | 自定義 plist | 文件資料庫 | ✅ 正常 |
| Qdrant | 自定義 plist | 向量資料庫 | ✅ 正常 |
| Momentry API | 自定義 plist | 影片管理 API | ✅ 正常 |
| RustDesk HBBR | 自定義 plist | 遠端桌面橋接 | ✅ 正常 |
| RustDesk HBBS | 自定義 plist | 遠端桌面服務器 | ✅ 正常 |
---
## 服務健康檢查結果 (2026-03-24)
### ✅ 正常運行的服務
| 服務 | 版本 | Port | 測試命令 | 結果 |
|------|------|------|----------|------|
| **PostgreSQL** | 18.1 | 5432 | `pg_isready -h 127.0.0.1 -p 5432` | ✅ 接受連線 |
| **Redis** | 7.4.x | 6379 | `redis-cli -a accusys ping` | ✅ PONG |
| **MongoDB** | 8.2.6 | 27017 | `mongosh --eval "db.adminCommand('ping')"` | ✅ { ok: 1 } |
| **Ollama** | - | 11434 | `curl -s http://localhost:11434/api/tags` | ✅ 模型可用 |
| **n8n** | 2.12.3 | 5678/5681/5682 | `curl -s http://localhost:5678/healthz` | ✅ {"status":"ok"} |
| **n8n Worker** | 2.12.3 | 5681/5690/5691 | - | ✅ 運行中 |
| **Momentry API** | 0.1.0 | 3002 | `curl -s http://localhost:3002/health` | ✅ OK |
| **Qdrant** | 1.17.0 | 6333 | `curl -s http://localhost:6333/` | ✅ 版本資訊 |
| **Caddy** | 2.10.x | 443 | `curl -sI https://momentry.ddns.net` | ✅ HTTP 200 |
| **SFTPGo** | 2.7.x | 8080 | `curl -s http://localhost:8080/sftpgo/` | ✅ JSON 響應 |
| **Gitea** | - | 3000 | `curl -s http://localhost:3000/` | ✅ HTML 響應 |
| **Gitea MCP** | - | 8787 | `curl -s http://localhost:8787/` | ✅ 運行中 |
| **MariaDB** | 12.1.x | 3306 | `mariadb -u root -e "SELECT 1;"` | ✅ 正常 |
| **PHP-FPM** | 8.5.x | 9000 | `ps aux \| grep php-fpm` | ✅ 運行中 |
### ⚠️ 需要配置的服務
| 服務 | 問題 | 解決方案 |
|------|------|----------|
| Grafana | 使用 Homebrew | 考慮遷移到自定義 plist |
| Prometheus | 使用 Homebrew | 考慮遷移到自定義 plist |
| Kafka | 未遷移 | 可選服務 |
| SeaweedFS | 未遷移 | 可選服務 |
| Netdata | 使用 Homebrew | 考慮遷移到自定義 plist |
### ⚠️ Homebrew 管理的服務 (建議遷移)
| 服務 | 風險 |
|------|------|
| homebrew.mxcl.grafana | Reboot 後可能自動啟動但使用預設設定 |
| homebrew.mxcl.prometheus | Reboot 後可能自動啟動但使用預設設定 |
| homebrew.mxcl.openwebui | 需要確認是否需要 |
| homebrew.mxcl.kafka | 需要確認是否需要 |
| homebrew.mxcl.seaweedfs | 需要確認是否需要 |
| homebrew.mxcl.netdata | 需要確認是否需要 |
| homebrew.mxcl.ddclient | 動態 DNS可能需要 |
| homebrew.mxcl.shadowsocks-rust | VPN可能需要 |
### MCP Servers (2026-03-24)
| Server | 安裝方式 | 路徑 | 狀態 |
|--------|----------|------|------|
| gitea | Homebrew | /opt/homebrew/bin/gitea-mcp-server | ✅ Connected |
| n8n | NPM | /opt/homebrew/bin/mcp-n8n | ✅ Connected |
| postgres | NPM | /opt/homebrew/bin/mcp-server-postgres | ✅ Connected |
| redis | NPM | /opt/homebrew/bin/mcp-server-redis | ✅ Connected |
| mongodb | NPM | /opt/homebrew/bin/mongodb-mcp-server | ✅ Connected |
| qdrant | Python | /opt/homebrew/bin/mcp-server-qdrant | ✅ Connected |
| filesystem | NPM | /opt/homebrew/bin/mcp-server-filesystem | ✅ Connected |
| sentry | NPM | /opt/homebrew/bin/sentry-mcp | ⏳ Pending Config |
| context7 | NPM | /opt/homebrew/bin/context7-mcp | ✅ Connected |
| playwright | NPM | /opt/homebrew/bin/playwright-mcp | ✅ Connected |
**配置文件**: `~/.config/opencode/opencode.json`
**驗證命令**:
```bash
opencode mcp ls
```
**詳細文檔**: [OpenCode MCP 安裝指南](./OPENCODE_MCP_INSTALL.md)
### 測試腳本
```bash
#!/bin/bash
# services_health_check.sh
echo "=== Momentry 服務健康檢查 ==="
echo ""
# PostgreSQL
pg_isready -h 127.0.0.1 -p 5432 -U accusys > /dev/null 2>&1 && echo "✅ PostgreSQL" || echo "❌ PostgreSQL"
# Redis
redis-cli -a accusys ping > /dev/null 2>&1 && echo "✅ Redis" || echo "❌ Redis"
# MongoDB
mongosh --quiet --eval "db.adminCommand('ping')" > /dev/null 2>&1 && echo "✅ MongoDB" || echo "❌ MongoDB"
# Ollama
curl -s http://localhost:11434/api/tags > /dev/null 2>&1 && echo "✅ Ollama" || echo "❌ Ollama"
# n8n
curl -s http://localhost:5678/ > /dev/null 2>&1 && echo "✅ n8n" || echo "❌ n8n"
# Momentry API
curl -s http://localhost:3002/health > /dev/null 2>&1 && echo "✅ Momentry API" || echo "❌ Momentry API"
# Qdrant
curl -s http://localhost:6333/ > /dev/null 2>&1 && echo "✅ Qdrant" || echo "❌ Qdrant"
# Caddy
curl -sI https://momentry.ddns.net > /dev/null 2>&1 && echo "✅ Caddy" || echo "❌ Caddy"
# SFTPGo
curl -s http://localhost:8080/api/v2/healthz > /dev/null 2>&1 && echo "✅ SFTPGo" || echo "⚠️ SFTPGo (需配置)"
```
---
---
@@ -42,14 +178,12 @@ brew list postgresql@18 2>/dev/null || echo "Not installed"
brew install postgresql@18
```
#### 初始化資料庫
```bash
# 初始化資料庫 (如尚未初始化)
initdb /usr/local/var/postgresql@18
# 建立 momentry 資料庫
createdb -U accusys momentry
#### 資料目錄
```
/Users/accusys/momentry/var/postgresql
```
**重要**: 確保使用統一的資料目錄,避免與 homebrew plist 衝突。
#### 開機自動啟動
```bash
@@ -61,42 +195,51 @@ sudo tee /Library/LaunchDaemons/com.momentry.postgresql.plist > /dev/null <<'EOF
<dict>
<key>Label</key>
<string>com.momentry.postgresql</string>
<key>UserName</key>
<string>accusys</string>
<key>EnvironmentVariables</key>
<dict>
<key>LC_ALL</key>
<string>en_US.UTF-8</string>
</dict>
<key>WorkingDirectory</key>
<string>/Users/accusys/momentry/var/postgresql</string>
<key>ProgramArguments</key>
<array>
<string>/opt/homebrew/opt/postgresql@18/bin/pg_ctl</string>
<string>/opt/homebrew/opt/postgresql@18/bin/postgres</string>
<string>-D</string>
<string>/opt/homebrew/var/postgresql@18</string>
<string>-l</string>
<string>/opt/homebrew/var/postgresql@18/logfile</string>
<string>start</string>
<string>/Users/accusys/momentry/var/postgresql</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>WorkingDirectory</key>
<string>/opt/homebrew/var/postgresql@18</string>
<key>UserName</key>
<string>accusys</string>
<key>StandardErrorPath</key>
<string>/Users/accusys/momentry/log/postgresql.error.log</string>
<key>StandardOutPath</key>
<string>/Users/accusys/momentry/log/postgresql.log</string>
</dict>
</plist>
EOF
# 載入服務
sudo launchctl load /Library/LaunchDaemons/com.momentry.postgresql.plist
sudo launchctl bootstrap system /Library/LaunchDaemons/com.momentry.postgresql.plist
```
#### 管理命令
```bash
# 啟動
sudo launchctl load /Library/LaunchDaemons/com.momentry.postgresql.plist
sudo launchctl bootstrap system /Library/LaunchDaemons/com.momentry.postgresql.plist
# 停止
sudo launchctl unload /Library/LaunchDaemons/com.momentry.postgresql.plist
sudo launchctl bootout system/com.momentry.postgresql.plist
# 重新載入
sudo launchctl unload /Library/LaunchDaemons/com.momentry.postgresql.plist
sudo launchctl load /Library/LaunchDaemons/com.momentry.postgresql.plist
sudo launchctl bootout system/com.momentry.postgresql.plist
sudo launchctl bootstrap system /Library/LaunchDaemons/com.momentry.postgresql.plist
# 查看狀態
launchctl list | grep com.momentry.postgresql
```
#### 健康檢查
@@ -105,10 +248,13 @@ sudo launchctl load /Library/LaunchDaemons/com.momentry.postgresql.plist
pg_isready -h localhost -p 5432 -U accusys
# 方法 2: 連線測試
psql -U accusys -h localhost -d momentry -c "SELECT 1;"
PGPASSWORD=n8n1234 psql -h localhost -U n8n -d n8n -c "SELECT 1;"
# 方法 3: 檢查程序
pgrep -f "postgres.*postgresql@18"
pgrep -a postgres
# 方法 4: 檢查資料庫
PGPASSWORD=n8n1234 psql -h localhost -U n8n -d n8n -c "SELECT COUNT(*) FROM workflow_entity;"
```
---
@@ -356,7 +502,7 @@ ps aux | grep n8n | grep -v grep
# 方法 3: 檢查端口
lsof -i :5678
lsof -i :5690
lsof -i :5679
```
---
@@ -512,41 +658,54 @@ chmod +x scripts/health_check.sh
## 服務管理速查表
### 啟動服務
### 啟動服務 (使用 launchctl bootstrap)
```bash
# PostgreSQL (需要 root 權限)
sudo launchctl load /Library/LaunchDaemons/com.momentry.postgresql.plist
# 所有服務
for plist in /Library/LaunchDaemons/com.momentry.*.plist; do
sudo launchctl bootstrap system "$plist"
done
# Redis, Ollama (需要 root 權限)
sudo launchctl load /Library/LaunchDaemons/com.momentry.redis.plist
sudo launchctl load /Library/LaunchDaemons/com.momentry.ollama.plist
# PostgreSQL
sudo launchctl bootstrap system /Library/LaunchDaemons/com.momentry.postgresql.plist
# n8n (需要 root 權限)
sudo launchctl load /Library/LaunchDaemons/com.momentry.n8n.main.plist
sudo launchctl load /Library/LaunchDaemons/com.momentry.n8n.worker.plist
# Redis, Ollama, Qdrant
sudo launchctl bootstrap system /Library/LaunchDaemons/com.momentry.redis.plist
sudo launchctl bootstrap system /Library/LaunchDaemons/com.momentry.ollama.plist
sudo launchctl bootstrap system /Library/LaunchDaemons/com.momentry.qdrant.plist
# n8n (main + worker)
sudo launchctl bootstrap system /Library/LaunchDaemons/com.momentry.n8n.main.plist
sudo launchctl bootstrap system /Library/LaunchDaemons/com.momentry.n8n.worker.plist
```
### 停止服務
### 停止服務 (使用 launchctl bootout)
```bash
# PostgreSQL
sudo launchctl unload /Library/LaunchDaemons/com.momentry.postgresql.plist
# 所有 Momentry 服務
for svc in $(launchctl list | grep com.momentry | awk '{print $3}'); do
sudo launchctl bootout system/$svc 2>/dev/null
done
# Redis, Ollama
sudo launchctl unload /Library/LaunchDaemons/com.momentry.redis.plist
sudo launchctl unload /Library/LaunchDaemons/com.momentry.ollama.plist
# PostgreSQL
sudo launchctl bootout system/com.momentry.postgresql.plist
# Redis, Ollama, Qdrant
sudo launchctl bootout system/com.momentry.redis.plist
sudo launchctl bootout system/com.momentry.ollama.plist
sudo launchctl bootout system/com.momentry.qdrant.plist
# n8n
sudo launchctl unload /Library/LaunchDaemons/com.momentry.n8n.main.plist
sudo launchctl unload /Library/LaunchDaemons/com.momentry.n8n.worker.plist
sudo launchctl bootout system/com.momentry.n8n.main.plist
sudo launchctl bootout system/com.momentry.n8n.worker.plist
```
### 查詢服務狀態
```bash
# 查看所有服務
launchctl list | grep -E "(postgres|redis|ollama|n8n|grafana|prometheus)"
# 查看所有 Momentry 服務
launchctl list | grep com.momentry
# 查看特定服務
launchctl list | grep com.momentry
launchctl list | grep com.momentry.postgresql
launchctl list | grep com.momentry.n8n
```
---
@@ -711,21 +870,160 @@ esac
---
## 服務快速參照
### Port 對照表
| Port | 服務 | 說明 |
|------|------|------|
| 11434 | Ollama | LLM API |
| 19999 | Netdata | 系統監控 |
| 2019 | Caddy | 管理 API |
| 21115-21119 | RustDesk | 遠端桌面 |
| 27017 | MongoDB | 文件資料庫 |
| 3000 | Gitea | Git 服務 |
| 3001 | Grafana | 監控儀表板 |
| 3002 | Momentry API | Rust API 伺服器 (生產環境) |
| 3003 | Momentry Playground | Rust API 伺服器 (開發環境) |
| 3306 | MariaDB | MySQL 相容資料庫 |
| 4096 | OpenCode | CLI 工具 |
| 5000-7000 | ControlCenter | 控制中心 |
| 5678 | n8n | 工作流自動化 (Main) |
| 5681 | n8n | Worker HTTP |
| 5682 | n8n | Worker Health Check |
| 5690 | n8n | Task Broker |
| 5691 | n8n | Runner Health |
| 6333-6334 | Qdrant | 向量資料庫 |
| 6379 | Redis | 快取/佇列 |
| 8080 | SFTPGo | HTTP/WebDAV |
| 8081 | Trunk | 轉發服務 |
| 8082 | SeaweedFS | Master |
| 8090 | SFTPGo | WebDAV |
| 8333 | SeaweedFS | Volume |
| 8388 | Shadowsocks | VPN |
| 8888 | SeaweedFS | Filer |
| 9000 | PHP-FPM | PHP 處理器 |
| 9090 | Prometheus | 指標收集 |
| 9092-9093 | Kafka | 訊息佇列 |
| 9333 | SeaweedFS | Volume |
| 18082 | SeaweedFS | Volume |
| 18333 | SeaweedFS | Volume |
| 18888 | SeaweedFS | Filer |
| 19333 | SeaweedFS | Volume |
## Caddy 反向代理 URL 對照表
| URL | 內部服務 | 說明 |
|-----|----------|------|
| `n8n.momentry.ddns.net` | :5678 | n8n 工作流自動化 |
| `wp.momentry.ddns.net` | :9000 | WordPress 網站 |
| `seaweed.momentry.ddns.net` | :8888 | SeaweedFS Filer |
| `sftpgo.momentry.ddns.net` | :8080 | SFTPGo HTTP |
| `webdav.momentry.ddns.net` | :8090 | SFTPGo WebDAV |
| `qdrant.momentry.ddns.net` | :6333 | Qdrant 向量資料庫 |
| `gitea.momentry.ddns.net` | :3000 | Gitea Git 服務 |
| `chat.momentry.ddns.net` | :8085 | Open WebUI |
| `netdata.momentry.ddns.net` | :19999 | Netdata 監控 |
| `grafana.momentry.ddns.net` | :3001 | Grafana 儀表板 |
| `router5.momentry.ddns.net` | 192.168.5.1:80 | Router 5 |
| `router110.momentry.ddns.net` | 192.168.110.1:80 | Router 110 |
| `router0.momentry.ddns.net/admin/*` | 192.168.0.1:80 | Router 0 |
| `truenas.momentry.ddns.net` | 192.168.0.219:80 | TrueNAS |
| `:3200` | :3002 | Momentry Dashboard + API |
**Caddy 管理**: https://localhost:2019/
---
## 目錄對照表
### /Users/accusys/momentry/var/
| 目錄 | 服務 | 說明 |
|------|------|------|
| `caddy/` | Caddy | 資料目錄 |
| `gitea/` | Gitea | Git 資料庫 |
| `mariadb/` | MariaDB | 資料庫檔案 |
| `mongodb/` | MongoDB | 文件資料庫 (自定義 plist) |
| `n8n/` | n8n | 工作流資料 |
| `ollama/` | Ollama | 模型快取 |
| `php/` | PHP | FastCGI 進程 |
| `postgresql/` | PostgreSQL | 主資料庫 (自定義 plist) |
| `qdrant/` | Qdrant | 向量資料庫 |
| `redis/` | Redis | 持久化檔案 |
| `rustdesk/` | RustDesk | ID 資料庫 |
| `sftpgo/` | SFTPGo | 使用者資料 |
| `sftpgo_backup/` | SFTPGo | 備份 |
### /opt/homebrew/var/ (Homebrew 管理)
| 目錄 | 服務 | 說明 |
|------|------|------|
| `mongodb/` | MongoDB | (舊) 文件資料庫 |
| `postgresql@18/` | PostgreSQL | (舊) 主資料庫 |
### /Users/accusys/momentry/etc/
| 目錄 | 服務 | 說明 |
|------|------|------|
| `caddy/` | Caddy | 配置 |
| `gitea/` | Gitea | 配置 |
| `php/` | PHP | 配置 |
| `sftpgo/` | SFTPGo | 配置 |
### /Users/accusys/momentry/log/
| 檔案 | 服務 | 說明 |
|------|------|------|
| `backup.log` | Backup | 備份日誌 |
| `redis.log` | Redis | 執行日誌 |
| `redis.error.log` | Redis | 錯誤日誌 |
| `ollama.log` | Ollama | 執行日誌 |
| `ollama.error.log` | Ollama | 錯誤日誌 |
### /Users/accusys/momentry/backup/
| 目錄 | 說明 |
|------|------|
| `daily/` | 每日備份 |
| `weekly/` | 每週備份 |
| `monthly/` | 每月備份 |
---
## 附錄: 服務版本對應表
| 服務 | 版本 | Port | 使用者 | plist 位置 |
|------|------|------|--------|-------------|
| PostgreSQL | 18.1 | 5432 | accusys | /Library/LaunchDaemons/ |
| Redis | 7.4.x | 6379 | accusys | /Library/LaunchDaemons/ |
| Ollama | - | 11434 | accusys | /Library/LaunchDaemons/ |
| n8n | 2.3.5 | 5678/5690 | accusys | /Library/LaunchDaemons/ |
| Node.js (n8n) | 22.22.1 | - | - | /opt/homebrew/opt/node@22/ |
| Python (Momentry) | 3.11.14 | - | - | venv/bin/python |
| Caddy | 2.10.x | 2019 | root | /Library/LaunchDaemons/ |
| Gitea | - | 3000 | accusys | /Library/LaunchDaemons/ |
| SFTPGo | 2.7.x | 8080 | accusys | /Library/LaunchDaemons/ |
| Qdrant | 1.17.x | 6333 | accusys | /Library/LaunchDaemons/ |
| MongoDB | - | 27017 | accusys | /Library/LaunchDaemons/ |
| MariaDB | 12.1.x | 3306 | accusys | /Library/LaunchDaemons/ |
| RustDesk | - | 21115-21119 | accusys | /Library/LaunchDaemons/ |
| PHP | 8.3.x | - | - | /opt/homebrew/ |
| 服務 | 版本 | Port | 使用者 | plist 位置 | 資料目錄 |
|------|------|------|--------|-------------|----------|
| PostgreSQL | 18.1 | 5432 | accusys | /Library/LaunchDaemons/ | /Users/accusys/momentry/var/postgresql |
| Redis | 7.4.x | 6379 | accusys | /Library/LaunchDaemons/ | /opt/homebrew/var/redis |
| Ollama | 0.13.5 | 11434 | accusys | /Library/LaunchDaemons/ | /Users/accusys/momentry/var/ollama/models |
| n8n | 2.12.3 | 5678/5681 | accusys | /Library/LaunchDaemons/ | /Users/accusys/momentry/var/n8n |
| Node.js (n8n) | 22.22.1 | - | - | /opt/homebrew/opt/node@22/ | - |
| Python (Momentry) | 3.11.14 | - | - | venv/bin/python | - |
| Caddy | 2.10.x | 2019/443 | root | /Library/LaunchDaemons/ | /Users/accusys/momentry/var/caddy |
| Gitea | - | 3000 | accusys | /Library/LaunchDaemons/ | /Users/accusys/momentry/var/gitea |
| Gitea MCP | - | 8787 | accusys | /Library/LaunchDaemons/ | - |
| SFTPGo | 2.7.x | 8080/2022 | accusys | /Library/LaunchDaemons/ | /Users/accusys/momentry/var/sftpgo |
| Qdrant | 1.17.0 | 6333 | accusys | /Library/LaunchDaemons/ | /Users/accusys/.local/share/qdrant |
| MongoDB | 8.2.6 | 27017 | root | /Library/LaunchDaemons/ | /opt/homebrew/var/mongodb |
| MariaDB | 12.1.x | 3306 | accusys | /Library/LaunchDaemons/ | /Users/accusys/momentry/var/mariadb |
| RustDesk HBBR | - | 21115 | accusys | /Library/LaunchDaemons/ | - |
| RustDesk HBBS | - | 21115-21119 | accusys | /Library/LaunchDaemons/ | /Users/accusys/momentry/var/rustdesk |
| PHP | 8.5.x | 9000 | - | /Library/LaunchDaemons/ | - |
| Momentry API | 0.1.0 | 3002 | accusys | /Library/LaunchDaemons/ | - |
| Momentry Playground | 0.1.0 | 3003 | accusys | - | - |
---
## 重要密碼與金鑰
| 服務 | 用途 | 預設值 |
|------|------|--------|
| **PostgreSQL** | 連線密碼 (accusys) | `accusys` |
| **Redis** | 認證密碼 | `accusys` |
| **Qdrant** | API Key | `Test3200Test3200Test3200` |
| **n8n** | 資料庫密碼 | `n8n` (PostgreSQL) |
| **SFTPGo** | 安裝碼 | `Test3200Test3200` |
| **SFTPGo** | DB 密碼 | `sftpgo_pass_2026` |
| **Momentry API** | 資料庫 | `postgres://accusys:accusys@127.0.0.1:5432/momentry` |