<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Cradicle Explorer</title>
    <link href="/css/bootstrap/bootstrap.min.css" rel="stylesheet">
    <style>
      .form-control-dark::placeholder {
          color: #aaa;
          opacity: 1;
      }
    </style>
    <link rel="stylesheet" href="/assets/fontawesome/css/all.min.css">
    <link rel="icon" type="image/png" href="/favicon.png">


                <link href="/css/dashboard.css" rel="stylesheet">
                </head>
                <body>
                <header class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0 shadow">
                  <a class="navbar-brand col-md-3 col-lg-2 me-0 px-3 fs-6" href="/">Cradicle Explorer</a>
                  <button class="navbar-toggler position-absolute d-md-none collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#sidebarMenu" aria-controls="sidebarMenu" aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                  </button>
                  <form method="get" action="/cgi-bin/main" style="width:100%;"><input class="form-control form-control-dark w-100 rounded-0 border-0" type="text" name="q" placeholder="Search repos" aria-label="Search"></form>
                  <div class="navbar-nav flex-row">
                    <div class="nav-item text-nowrap">
                      <a class="nav-link px-3 active" href="/cgi-bin/repo?id=zQN8AYPVAZrJuyANC8UCRRXZRiMK">storybench</a>
                    </div>
                  </div>
                </header>
                <div class="container-fluid">
                  <div class="row">
                    <nav id="sidebarMenu" class="col-md-3 col-lg-2 d-md-block bg-dark sidebar collapse">
                      <div class="position-sticky pt-3 sidebar-sticky">
                        <ul class="nav flex-column">
                          <li class="nav-item">
                            <a class="nav-link active" href="/cgi-bin/repo?id=zQN8AYPVAZrJuyANC8UCRRXZRiMK">
                              <i class="align-text-bottom fa-solid fa-info"></i>
                              Info
                            </a>
                          </li>
                          <li class="nav-item">
                            <a class="nav-link" href="/cgi-bin/repo?id=zQN8AYPVAZrJuyANC8UCRRXZRiMK&issue=list">
                              <i class="align-text-bottom fa-solid fa-layer-group"></i>
                              Issues
                            </a>
                          </li>
                          <li class="nav-item">
                            <a class="nav-link" href="/cgi-bin/repo?id=zQN8AYPVAZrJuyANC8UCRRXZRiMK&patch=list">
                              <i class="align-text-bottom fa-solid fa-vest-patches"></i>
                              Patches
                            </a>
                          </li>
                          <li class="nav-item">
                            <a class="nav-link" href="/cgi-bin/repo?id=zQN8AYPVAZrJuyANC8UCRRXZRiMK&wallet=list">
                              <i class="align-text-bottom fa-solid fa-wallet"></i>
                              Wallets
                            </a>
                          </li>
                          <li class="nav-item">
                            <a class="nav-link" href="/cgi-bin/repo?id=zQN8AYPVAZrJuyANC8UCRRXZRiMK&source=.">
                              <i class="align-text-bottom fa-solid fa-code"></i>
                              Source
                            </a>
                          </li>
                        <h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted text-uppercase">
                          <span></span>
                        </h6>
                        <ul class="nav flex-column mb-2">
                        
                        </ul>
                      </div>
                    </nav>
                <main class="col-md-9 ms-sm-auto col-lg-10">
                  <div class="container px-1 py-3">
        

    <div class="list-group">
    <div class="list-group-item">
    <div style="font-size:1.3rem;">storybench</div>
    <div class="repo-item">Interaktives Redaktions-Tool</div>
    <div>rad:zQN8AYPVAZrJuyANC8UCRRXZRiMK</div>
    </div>
    <div class="list-group-item">
    <div>Visibility</div>
    <div class="repo-item">public</div>
    </div>
    <div class="list-group-item">
    <div>Delegates</div><div class="repo-item">did:key:z6Mknf6Z2Vg3wZFHXsAQFzUQwUQRU59r3xWzqzwav96FcFQe</div>
    </div>
    <div class="list-group-item">
    <div>Default branch</div>
    <div><span class="repo-item">main &#8594 e6769f6ae93e4d248429549303974269056dad58</span> (Mon Mar 16 20:36:15 2026)</div>
    </div>
    <div class="list-group-item">
    <div>Threshold</div>
    <div class="repo-item">1</div>
    </div>
    </div>
    
        <div class="list-group mt-3">
        <div class="list-group-item">
        <div class="mb-2" style="font-weight:bold;"><i class="fa-solid fa-book"></i> README.md</div>
        <pre style="margin:0; font-size:0.85rem; overflow-x:auto; color:#fafafa;"># StoryBench

**Internes Redaktions-Tool für bundesstadt.com**

StoryBench aggregiert News aus relevanten Bonner Quellen, clustert zusammenhängende Themen und generiert automatisch Story-Vorschläge für die Redaktion.

## Features

- 📰 **News-Aggregation** - RSS-Feeds &amp; Web-Scraping
- 🔍 **Themen-Clustering** - Automatische Gruppierung zusammenhängender Meldungen
- 🎯 **Relevanz-Scoring** - KI-gestützte Priorisierung
- 📊 **Story-Vorschläge** - Automatische Generierung von Artikel-Ideen
- 🎨 **Dashboard** - HTMX-basiertes Interface
- 🔗 **Integrationen** - Taiga (Redaktionsplanung) &amp; Mattermost (Alerts)

## Technologie-Stack

- **Backend:** PocketBase 0.36.5
- **Frontend:** HTMX + Alpine.js
- **Database:** SQLite (embedded)
- **Testing:** Mocha + Playwright

## Lokale Entwicklung

### Voraussetzungen

- PocketBase Binary (bereits in `bin/pocketbase`)
- Node.js 18+ (für Tests)

### Installation

```bash
# 1. Dependencies installieren (für Tests)
cd storybench
npm install

# 2. Environment Variables konfigurieren
cp .env.example .env
# .env bearbeiten und Credentials eintragen
```

### Starten

```bash
# Option 1: Direkt
cd storybench
./bin/pocketbase serve --http=&quot;127.0.0.1:8090&quot;

# Option 2: Via Makefile (aus storybench/)
cd storybench
make dev

# Option 3: Via Makefile (aus Projekt-Root)
make storybench-dev
```

### Admin-UI

**URL:** http://127.0.0.1:8090/_/

Beim ersten Start:
1. Admin-Account erstellen
2. Collections werden automatisch angelegt (via Migrations)

### Dashboard-UI

**URL:** http://127.0.0.1:8090/dashboard

Login mit PocketBase-User-Account.

## Projektstruktur

```
storybench/
├── bin/
│   └── pocketbase              # PocketBase Binary
├── pb_data/                    # Datenbank &amp; Uploads (auto-generiert)
│   ├── data.db
│   └── storage/
├── pb_hooks/                   # JavaScript Hooks
│   ├── scanner_rss.pb.js       # RSS-Scanner
│   ├── processing_*.pb.js      # Processing-Pipeline
│   ├── clustering_*.pb.js      # Clustering-Engine
│   ├── story_generator.pb.js   # Story-Generator
│   ├── api_*.pb.js             # API-Endpoints
│   └── integration_*.pb.js     # Taiga &amp; Mattermost
├── pb_migrations/              # Datenbank-Migrationen
│   ├── 001_initial_schema.js
│   ├── 002_seed_ressorts.js
│   └── 003_seed_translations.js
├── pb_public/                  # Frontend
│   ├── _layout.html
│   ├── dashboard.html
│   └── assets/
│       └── dashboard.css
├── src/lib/                    # Utilities
├── test/                       # Tests
│   ├── unit/
│   ├── integration/
│   └── e2e/
├── README.md
├── package.json
└── .env.example
```

## Collections

### news_sources
News-Quellen (RSS, Scraper, API)

### news_items
Einzelne News-Meldungen

### news_clusters
Gruppierte Themen

### story_suggestions
Story-Vorschläge für Redaktion

### ressorts
Ressort-Konfiguration (Politik, Kultur, Sport, etc.)

### translations
i18n-Übersetzungen (DE/EN)

## Makefile Targets

StoryBench hat ein eigenes Makefile mit praktischen Shortcuts:

```bash
# Aus storybench/ Verzeichnis:
make dev              # Start PocketBase development server
make admin            # Open Admin UI in browser
make test             # Run all tests
make test-unit        # Run unit tests only
make test-integration # Run integration tests only
make test-e2e         # Run E2E tests
make coverage         # Run tests with coverage report
make backup           # Create database backup
make install          # Install npm dependencies
make status           # Show project status
make clean            # Clean generated files
make clean-all        # Clean everything including database (DANGEROUS!)
make help             # Show all available targets

# Aus Projekt-Root:
make storybench-dev   # Delegates to: cd storybench &amp;&amp; make dev
make storybench-test  # Delegates to: cd storybench &amp;&amp; make test
# etc.
```

## Development

### Tests ausführen

```bash
# Unit-Tests
npm test

# Watch-Mode
npm run test:watch

# Coverage
npm run test:coverage

# E2E-Tests
npm run test:e2e
```

### Neue Quelle hinzufügen

1. Admin-UI öffnen: http://127.0.0.1:8090/_/
2. Collection `news_sources` öffnen
3. Neuen Record erstellen:
   - **name:** Name der Quelle
   - **type:** rss, scraper, oder api
   - **url:** Feed-URL oder Webseiten-URL
   - **scan_interval:** Minuten zwischen Scans (Standard: 15)
   - **active:** true
   - **priority:** 1-10 (höher = wichtiger)
   - **default_ressort:** Politik, Kultur, Sport, etc.

### Manuellen Scan triggern

```bash
# Via API
curl -X POST http://127.0.0.1:8090/api/scanner/trigger/{source_id}

# Via Dashboard
Dashboard → Sources → &quot;Jetzt scannen&quot; Button
```

## Deployment

### Produktion (VPS)

**Domain:** bonn.storybench.de  
**Port:** 8090 (intern)  
**Reverse Proxy:** nginx  
**SSL:** Let&#x27;s Encrypt

Siehe [`plans/storybench-updat`](../plans/storybench-updat) für Details.

### Systemd-Service

```bash
# Service-Datei: /etc/systemd/system/storybench.service
sudo systemctl enable storybench
sudo systemctl start storybench
sudo systemctl status storybench
```

### Backup

```bash
# Manuell
./bin/pocketbase backup

# Automatisch (via Cron)
# Siehe plans/storybench-updat für Backup-Script
```

## Environment Variables

```bash
# PocketBase
PB_ADMIN_EMAIL=admin@bundesstadt.com
PB_ADMIN_PASSWORD=

# Taiga Integration
TAIGA_URL=https://taiga.bundesstadt.com
TAIGA_TOKEN=
TAIGA_PROJECT_ID=

# Mattermost Integration
MATTERMOST_WEBHOOK_URL=

# Development
NODE_ENV=development
```

## Troubleshooting

### PocketBase startet nicht

```bash
# Port bereits belegt?
lsof -i :8090

# Logs prüfen
./bin/pocketbase serve --http=&quot;127.0.0.1:8090&quot; --debug
```

### Scanner läuft nicht

1. Admin-UI → Logs prüfen
2. Quelle aktiv? (`active = true`)
3. URL erreichbar?
4. Cron-Jobs laufen? (siehe Logs)

### Dashboard zeigt keine Daten

1. Sind Quellen konfiguriert?
2. Wurde bereits gescannt? (siehe `last_scan` in `news_sources`)
3. Sind Items vorhanden? (Admin-UI → `news_items`)
4. User eingeloggt?

## Dokumentation

- **Build-Plan:** [`plans/storybench-build-plan.md`](../plans/storybench-build-plan.md)
- **News-Aggregation:** [`plans/redaktions-tool-newsaggregation.md`](../plans/redaktions-tool-newsaggregation.md)
- **Implementation:** [`plans/redaktions-tool-implementation.md`](../plans/redaktions-tool-implementation.md)
- **Deployment:** [`plans/storybench-updat`](../plans/storybench-updat)

## Lizenz

Internes Tool für bundesstadt.com - Nicht für öffentliche Nutzung bestimmt.

## Kontakt

**Projekt:** Hub Bonn  
**Repository:** /home/olav/Dokumente/Hub-Bonn
</pre>
        </div>
        </div>

</div>
</main>
</div>
</div>


</body>
</html>

