Extract 4 self-contained services into services/ module: - server/telegram_bot/ -> services/telegram_bot/ - server/ws_gateway/ -> services/ws_gateway/ - server/corporate_memory/ -> services/corporate_memory/ - server/session_collector.py -> services/session_collector/ Each service now has its own systemd/ directory with .service and .timer files. deploy.sh updated to auto-discover service units from services/*/systemd/*. server/ now contains only deployment infrastructure (deploy.sh, setup scripts, bin/ management tools, sudoers, nginx config). All imports updated: webapp/app.py, server/bin/ scripts, systemd ExecStart paths.
14 KiB
Corporate Memory Module - Implementation Plan
Overview
Server-side modul, který každých 30 minut sbírá znalosti z CLAUDE.local.md všech uživatelů, pomocí Claude HAIKU je extrahuje a filtruje, a vytváří sdílenou firemní knowledge base. Uživatelé mohou hlasovat a oblíbené znalosti se jim syncují do .claude/rules/.
Architecture
┌─────────────────────────────────────────────────────────────────┐
│ Cron (*/30 * * * *) │
│ └── /usr/local/bin/collect-knowledge │
│ 1. Čte /home/*/CLAUDE.local.md │
│ 2. Volá Claude HAIKU pro extrakci (AI filtering) │
│ 3. Ukládá do /data/corporate-memory/knowledge.json │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ /data/corporate-memory/ (deploy:data-ops 2770)│
│ ├── knowledge.json # {items: {id: {title, content, ...}}} │
│ ├── votes.json # {username: {item_id: 1|-1}} │
│ ├── user_hashes.json # {username: {file_hash, last_proc}} │
│ └── collection.log # Logy z HAIKU procesingu │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Webapp │
│ ├── Dashboard widget: stats (contributors, items, your rules) │
│ ├── /corporate-memory: sub-page s 👍/👎 hlasováním │
│ └── API: /api/corporate-memory/* │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ sync_data.sh │
│ └── Stáhne upvoted items do .claude/rules/*.md │
└─────────────────────────────────────────────────────────────────┘
Data Model
knowledge.json:
{
"items": {
"km_abc123": {
"id": "km_abc123",
"title": "DuckDB query optimization",
"content": "When querying large parquet files...",
"category": "data_analysis",
"tags": ["duckdb", "performance"],
"source_users": ["john.doe", "jane.smith", "bob"],
"votes_up": 5,
"votes_down": 1,
"score": 4,
"extracted_at": "2026-02-05T10:30:00Z",
"updated_at": "2026-02-05T12:00:00Z"
}
},
"metadata": {
"last_collection": "2026-02-05T10:30:00Z",
"total_users": 8
}
}
votes.json (kdo jak hlasoval - pro UI "already voted"):
{
"john.doe": {"km_abc123": 1, "km_def456": -1},
"jane.smith": {"km_abc123": 1}
}
Voting & Popularity
votes_up/votes_down- počet palců nahoru/dolů (viditelné v UI)score= votes_up - votes_down (pro řazení)- votes.json trackuje KDO hlasoval (pro zabránění dvojího hlasování)
- UI NEZOBRAZUJE jména hlasujících, jen počty
Řazení v UI:
- Nejoblíbenější (Most Popular): ORDER BY score DESC
- Nejméně oblíbené (Least Popular): ORDER BY score ASC
- Nejnovější (Recent): ORDER BY extracted_at DESC
- Nejvíc přispěvatelů (Most Contributors): ORDER BY len(source_users) DESC
user_hashes.json (tracking změn CLAUDE.local.md):
{
"john.doe": {
"file_hash": "a1b2c3d4e5f6...",
"last_processed": "2026-02-05T10:30:00Z"
},
"jane.smith": {
"file_hash": "f6e5d4c3b2a1...",
"last_processed": "2026-02-05T09:00:00Z"
}
}
Change Detection & Deduplication
Change Detection (šetření tokenů)
DŮLEŽITÉ: Každých 30 minut se zpracovávají POUZE změněné soubory!
┌─────────────────────────────────────────────────────────────────┐
│ Cron běží každých 30 min │
│ │
│ Pro každého uživatele: │
│ 1. Spočítej MD5 hash /home/$user/CLAUDE.local.md │
│ 2. Porovnej s uloženým hashem v user_hashes.json │
│ 3. Pokud STEJNÝ → PŘESKOČ (žádné API volání) │
│ 4. Pokud ZMĚNĚNÝ → zpracuj pomocí HAIKU API │
│ │
│ Typicky: 8 uživatelů, 1-2 změny denně = 2-4 API volání/den │
└─────────────────────────────────────────────────────────────────┘
def collect_all():
users_processed = 0
users_skipped = 0
for user_dir in Path("/home").iterdir():
claude_file = user_dir / "CLAUDE.local.md"
if not claude_file.exists():
continue
username = user_dir.name
current_hash = hashlib.md5(claude_file.read_bytes()).hexdigest()
stored_hash = user_hashes.get(username, {}).get("file_hash")
if current_hash == stored_hash:
users_skipped += 1
continue # ← PŘESKOČÍ - žádné API volání!
# Pouze změněné soubory volají HAIKU
new_knowledge = extract_knowledge(claude_file.read_text())
deduplicate_and_merge(new_knowledge, username)
update_user_hash(username, current_hash)
users_processed += 1
log(f"Processed: {users_processed}, Skipped: {users_skipped}")
Deduplikace znalostí
Při extrakci nových znalostí od změněného uživatele:
- HAIKU vrátí seznam znalostí
- Pro každou novou znalost:
- Hledej podobnou v CELÉ knowledge base (všichni uživatelé)
- Pokud existuje podobná → přidej uživatele do
source_users[] - Pokud neexistuje → vytvoř novou
def deduplicate_and_merge(new_items: list, username: str):
"""Deduplikuje nové znalosti proti celé knowledge base."""
for new_item in new_items:
similar_id = find_similar_knowledge(new_item, knowledge_base)
if similar_id:
# Existující znalost - přidej uživatele
knowledge_base["items"][similar_id]["source_users"].append(username)
knowledge_base["items"][similar_id]["updated_at"] = now()
else:
# Nová znalost
item_id = generate_id()
knowledge_base["items"][item_id] = {
**new_item,
"id": item_id,
"source_users": [username],
"extracted_at": now()
}
Příklad deduplikace
5 uživatelů má podobnou znalost o DuckDB:
- User A: "Pro rychlé dotazy v DuckDB použij WHERE před JOIN"
- User B: "DuckDB je rychlejší když filtruješ před joinem"
- User C: "Filtruj data před JOIN operací v DuckDB"
- User D: "WHERE klauzule před JOIN zrychlí DuckDB"
- User E: "V DuckDB dej WHERE před JOIN"
→ HAIKU rozpozná jako JEDNU znalost → source_users: ["user_a", "user_b", "user_c", "user_d", "user_e"]
Files to Create
1. Server-side Collector
server/corporate_memory/collector.py - Main collection logic:
collect_all()- iteruje přes /home/*/CLAUDE.local.mdshould_process_user(username)- kontrola hash změn (šetří tokeny)extract_knowledge(content)- volá HAIKU APIfind_similar_knowledge(new, existing)- hledá duplicitymerge_knowledge(existing, new, username)- sloučí a přidá uživatelesave_knowledge(data)- atomic JSON writeupdate_user_hash(username, hash)- uloží hash pro příští run
server/corporate_memory/prompts.py - HAIKU prompts:
- Prompt pro extrakci znalostí
- Prompt pro AI filtering citlivých dat
- Prompt pro merge podobných znalostí (optional)
server/bin/collect-knowledge - Shell wrapper:
#!/bin/bash
cd /opt/data-analyst/repo
/opt/data-analyst/.venv/bin/python -m services.corporate_memory
services/corporate_memory/systemd/corporate-memory.timer + services/corporate_memory/systemd/corporate-memory.service - Systemd timer (30 min)
2. Webapp Backend
webapp/corporate_memory_service.py (pattern: telegram_service.py):
get_knowledge(filter, page)- seznam znalostíget_stats()- pro dashboard widgetvote(username, item_id, vote)- +1/-1get_user_rules(username)- upvoted items pro syncgenerate_user_rules_file(username)- vytvoří JSON pro sync
webapp/app.py - nové routes:
GET /corporate-memory- sub-pageGET /api/corporate-memory/knowledge- list itemsGET /api/corporate-memory/stats- dashboard statsPOST /api/corporate-memory/vote- hlasováníGET /api/corporate-memory/my-rules- user's upvoted
3. Webapp Frontend
webapp/templates/corporate_memory.html - sub-page:
- Header se stats
- Řazení: Most Popular | Least Popular | Recent | Most Contributors
- Seznam znalostí s filtry (category, search)
- Každá položka:
- Title + content preview
- Tags (category badges)
- 👍 (count) / 👎 (count) buttons
- "From X contributors" badge
- "Synced to your rules" indicator (if user upvoted)
┌─────────────────────────────────────────────────────────────────┐
│ DuckDB query optimization [data_analysis] │
│ When querying large parquet files, filter before JOIN... │
│ │
│ 👍 5 👎 1 | From 3 contributors | ✓ In your rules │
└─────────────────────────────────────────────────────────────────┘
webapp/templates/dashboard.html - přidat widget:
<div class="card-v2 memory-card">
<h3>Corporate Memory</h3>
<div class="memory-stats">
<div class="stat">{{ stats.contributors }} contributors</div>
<div class="stat">{{ stats.knowledge_count }} knowledge items</div>
<div class="stat">{{ stats.your_rules }} your rules</div>
</div>
<a href="/corporate-memory">Browse Knowledge →</a>
</div>
4. Client Sync
Server generuje .md soubory přímo do /home/$user/.claude_rules/ pro každého uživatele.
Klient si je jen stáhne.
scripts/sync_data.sh - přidat:
# --- Sync corporate memory rules ---
echo "📚 Syncing corporate memory rules..."
mkdir -p .claude/rules
rsync -avz data-analyst:~/.claude_rules/ .claude/rules/ 2>/dev/null || \
scp -r data-analyst:~/.claude_rules/* .claude/rules/ 2>/dev/null || true
Server-side (v corporate_memory_service.py):
generate_user_rules(username)- při hlasování regeneruje .md soubory- Zapisuje do
/home/$user/.claude_rules/km_*.md - Webapp volá po každém vote změně
5. Deployment
server/deploy.sh - additions:
- Vytvořit /data/corporate-memory/ (2770 setgid)
- Nainstalovat collect-knowledge do /usr/local/bin/
- Deploy systemd timer
- Přidat ANTHROPIC_API_KEY do .env
server/sudoers-deploy - přidat práva pro /data/corporate-memory/
GitHub Secrets: ANTHROPIC_API_KEY
Implementation Phases
Phase 1: Server Infrastructure
server/corporate_memory/Python modulserver/bin/collect-knowledgewrapperserver/corporate-memory.service+.timer- Update
server/deploy.sh - Update sudoers
Phase 2: Webapp Backend
webapp/corporate_memory_service.py- API endpoints v
webapp/app.py - Update
webapp/config.py(ANTHROPIC_API_KEY, paths)
Phase 3: Webapp Frontend
- Dashboard widget v
dashboard.html - Sub-page
corporate_memory.html - CSS styles
Phase 4: Client Sync
- Update
scripts/sync_data.sh- přidat rsync pro.claude_rules/
Key Files to Modify
| File | Changes |
|---|---|
server/deploy.sh |
Add /data/corporate-memory/, ANTHROPIC_API_KEY, systemd timer |
server/sudoers-deploy |
Add permissions for corporate-memory dir |
webapp/app.py |
Add routes and API endpoints |
webapp/config.py |
Add ANTHROPIC_API_KEY, CORPORATE_MEMORY_DIR |
webapp/templates/dashboard.html |
Add Corporate Memory widget |
scripts/sync_data.sh |
Add corporate rules sync step |
Reusable Patterns (from codebase)
- JSON I/O:
webapp/telegram_service.py- atomic writes with tempfile - Dashboard widget:
webapp/templates/dashboard.html- KPI card pattern - Sub-page:
webapp/templates/catalog.html- route + template pattern - Systemd service:
server/notify-bot.service- timer pattern - Deploy:
server/deploy.sh- directory setup, script installation
Verification
- Collector:
ssh kids "/usr/local/bin/collect-knowledge --dry-run" - API:
curl https://your-instance.example.com/api/corporate-memory/stats - Widget: Check dashboard shows stats
- Voting: Click 👍/👎, verify votes.json updated
- Sync: Run
sync_data.sh, check.claude/rules/has .md files