update
This commit is contained in:
412
docs/SYSTEM_ARCHITECTURE.md
Normal file
412
docs/SYSTEM_ARCHITECTURE.md
Normal file
@@ -0,0 +1,412 @@
|
||||
# Munich News Daily - System Architecture
|
||||
|
||||
## 📊 Complete System Overview
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Munich News Daily System │
|
||||
│ Fully Automated Pipeline │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
|
||||
Daily Schedule
|
||||
┌──────────────────────┐
|
||||
│ 6:00 AM Berlin │
|
||||
│ News Crawler │
|
||||
└──────────┬───────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ News Crawler │
|
||||
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐│
|
||||
│ │ Fetch RSS │→ │ Extract │→ │ Summarize │→ │ Save to ││
|
||||
│ │ Feeds │ │ Content │ │ with AI │ │ MongoDB ││
|
||||
│ └────────────┘ └────────────┘ └────────────┘ └────────────┘│
|
||||
│ │
|
||||
│ Sources: Süddeutsche, Merkur, BR24, etc. │
|
||||
│ Output: Full articles + AI summaries │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
│ Articles saved
|
||||
▼
|
||||
┌──────────────────────┐
|
||||
│ MongoDB │
|
||||
│ (Data Storage) │
|
||||
└──────────┬───────────┘
|
||||
│
|
||||
│ Wait for crawler
|
||||
▼
|
||||
┌──────────────────────┐
|
||||
│ 7:00 AM Berlin │
|
||||
│ Newsletter Sender │
|
||||
└──────────┬───────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ Newsletter Sender │
|
||||
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐│
|
||||
│ │ Wait for │→ │ Fetch │→ │ Generate │→ │ Send to ││
|
||||
│ │ Crawler │ │ Articles │ │ Newsletter │ │ Subscribers││
|
||||
│ └────────────┘ └────────────┘ └────────────┘ └────────────┘│
|
||||
│ │
|
||||
│ Features: Tracking pixels, link tracking, HTML templates │
|
||||
│ Output: Personalized newsletters with engagement tracking │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
│ Emails sent
|
||||
▼
|
||||
┌──────────────────────┐
|
||||
│ Subscribers │
|
||||
│ (Email Inboxes) │
|
||||
└──────────┬───────────┘
|
||||
│
|
||||
│ Opens & clicks
|
||||
▼
|
||||
┌──────────────────────┐
|
||||
│ Tracking System │
|
||||
│ (Analytics API) │
|
||||
└──────────────────────┘
|
||||
```
|
||||
|
||||
## 🔄 Data Flow
|
||||
|
||||
### 1. Content Acquisition (6:00 AM)
|
||||
|
||||
```
|
||||
RSS Feeds → Crawler → Full Content → AI Summary → MongoDB
|
||||
```
|
||||
|
||||
**Details**:
|
||||
- Fetches from multiple RSS sources
|
||||
- Extracts full article text
|
||||
- Generates concise summaries using Ollama
|
||||
- Stores with metadata (author, date, source)
|
||||
|
||||
### 2. Newsletter Generation (7:00 AM)
|
||||
|
||||
```
|
||||
MongoDB → Articles → Template → HTML → Email
|
||||
```
|
||||
|
||||
**Details**:
|
||||
- Waits for crawler to finish (max 30 min)
|
||||
- Fetches today's articles with summaries
|
||||
- Applies Jinja2 template
|
||||
- Injects tracking pixels
|
||||
- Replaces links with tracking URLs
|
||||
|
||||
### 3. Engagement Tracking (Ongoing)
|
||||
|
||||
```
|
||||
Email Open → Pixel Load → Log Event → Analytics
|
||||
Link Click → Redirect → Log Event → Analytics
|
||||
```
|
||||
|
||||
**Details**:
|
||||
- Tracks email opens via 1x1 pixel
|
||||
- Tracks link clicks via redirect URLs
|
||||
- Stores engagement data in MongoDB
|
||||
- Provides analytics API
|
||||
|
||||
## 🏗️ Component Architecture
|
||||
|
||||
### Docker Containers
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Docker Network │
|
||||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||||
│ │ MongoDB │ │ Crawler │ │ Sender │ │
|
||||
│ │ │ │ │ │ │ │
|
||||
│ │ Port: 27017 │←─│ Schedule: │←─│ Schedule: │ │
|
||||
│ │ │ │ 6:00 AM │ │ 7:00 AM │ │
|
||||
│ │ Storage: │ │ │ │ │ │
|
||||
│ │ - articles │ │ Depends on: │ │ Depends on: │ │
|
||||
│ │ - subscribers│ │ - MongoDB │ │ - MongoDB │ │
|
||||
│ │ - tracking │ │ │ │ - Crawler │ │
|
||||
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
||||
│ │
|
||||
│ All containers auto-restart on failure │
|
||||
│ All use Europe/Berlin timezone │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Backend Services
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Backend Services │
|
||||
│ │
|
||||
│ ┌──────────────────────────────────────────────────┐ │
|
||||
│ │ Flask API (Port 5001) │ │
|
||||
│ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ │
|
||||
│ │ │ Tracking │ │ Analytics │ │ Privacy │ │ │
|
||||
│ │ │ Endpoints │ │ Endpoints │ │ Endpoints │ │ │
|
||||
│ │ └────────────┘ └────────────┘ └────────────┘ │ │
|
||||
│ └──────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌──────────────────────────────────────────────────┐ │
|
||||
│ │ Services Layer │ │
|
||||
│ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ │
|
||||
│ │ │ Tracking │ │ Analytics │ │ Ollama │ │ │
|
||||
│ │ │ Service │ │ Service │ │ Client │ │ │
|
||||
│ │ └────────────┘ └────────────┘ └────────────┘ │ │
|
||||
│ └──────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 📅 Daily Timeline
|
||||
|
||||
```
|
||||
Time (Berlin) │ Event │ Duration
|
||||
───────────────┼──────────────────────────┼──────────
|
||||
05:59:59 │ System idle │ -
|
||||
06:00:00 │ Crawler starts │ ~10-20 min
|
||||
06:00:01 │ - Fetch RSS feeds │
|
||||
06:02:00 │ - Extract content │
|
||||
06:05:00 │ - Generate summaries │
|
||||
06:15:00 │ - Save to MongoDB │
|
||||
06:20:00 │ Crawler finishes │
|
||||
06:20:01 │ System idle │ ~40 min
|
||||
07:00:00 │ Sender starts │ ~5-10 min
|
||||
07:00:01 │ - Wait for crawler │ (checks every 30s)
|
||||
07:00:30 │ - Crawler confirmed done │
|
||||
07:00:31 │ - Fetch articles │
|
||||
07:01:00 │ - Generate newsletters │
|
||||
07:02:00 │ - Send to subscribers │
|
||||
07:10:00 │ Sender finishes │
|
||||
07:10:01 │ System idle │ Until tomorrow
|
||||
```
|
||||
|
||||
## 🔐 Security & Privacy
|
||||
|
||||
### Data Protection
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Privacy Features │
|
||||
│ │
|
||||
│ ┌──────────────────────────────────────────────────┐ │
|
||||
│ │ Data Retention │ │
|
||||
│ │ - Personal data: 90 days │ │
|
||||
│ │ - Anonymization: Automatic │ │
|
||||
│ │ - Deletion: On request │ │
|
||||
│ └──────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌──────────────────────────────────────────────────┐ │
|
||||
│ │ User Rights │ │
|
||||
│ │ - Opt-out: Anytime │ │
|
||||
│ │ - Data access: API available │ │
|
||||
│ │ - Data deletion: Full removal │ │
|
||||
│ └──────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌──────────────────────────────────────────────────┐ │
|
||||
│ │ Compliance │ │
|
||||
│ │ - GDPR compliant │ │
|
||||
│ │ - Privacy notice in emails │ │
|
||||
│ │ - Transparent tracking │ │
|
||||
│ └──────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 📊 Database Schema
|
||||
|
||||
### Collections
|
||||
|
||||
```
|
||||
MongoDB (munich_news)
|
||||
│
|
||||
├── articles
|
||||
│ ├── title
|
||||
│ ├── author
|
||||
│ ├── content (full text)
|
||||
│ ├── summary (AI generated)
|
||||
│ ├── link
|
||||
│ ├── source
|
||||
│ ├── published_at
|
||||
│ └── crawled_at
|
||||
│
|
||||
├── subscribers
|
||||
│ ├── email
|
||||
│ ├── active
|
||||
│ ├── tracking_enabled
|
||||
│ └── subscribed_at
|
||||
│
|
||||
├── rss_feeds
|
||||
│ ├── name
|
||||
│ ├── url
|
||||
│ └── active
|
||||
│
|
||||
├── newsletter_sends
|
||||
│ ├── tracking_id
|
||||
│ ├── newsletter_id
|
||||
│ ├── subscriber_email
|
||||
│ ├── opened
|
||||
│ ├── first_opened_at
|
||||
│ └── open_count
|
||||
│
|
||||
├── link_clicks
|
||||
│ ├── tracking_id
|
||||
│ ├── newsletter_id
|
||||
│ ├── subscriber_email
|
||||
│ ├── article_url
|
||||
│ ├── clicked
|
||||
│ └── clicked_at
|
||||
│
|
||||
└── subscriber_activity
|
||||
├── email
|
||||
├── status (active/inactive/dormant)
|
||||
├── last_opened_at
|
||||
├── last_clicked_at
|
||||
├── total_opens
|
||||
└── total_clicks
|
||||
```
|
||||
|
||||
## 🚀 Deployment Architecture
|
||||
|
||||
### Development
|
||||
|
||||
```
|
||||
Local Machine
|
||||
├── Docker Compose
|
||||
│ ├── MongoDB (no auth)
|
||||
│ ├── Crawler
|
||||
│ └── Sender
|
||||
├── Backend (manual start)
|
||||
│ └── Flask API
|
||||
└── Ollama (optional)
|
||||
└── AI Summarization
|
||||
```
|
||||
|
||||
### Production
|
||||
|
||||
```
|
||||
Server
|
||||
├── Docker Compose (prod)
|
||||
│ ├── MongoDB (with auth)
|
||||
│ ├── Crawler
|
||||
│ └── Sender
|
||||
├── Backend (systemd/pm2)
|
||||
│ └── Flask API (HTTPS)
|
||||
├── Ollama (optional)
|
||||
│ └── AI Summarization
|
||||
└── Nginx (reverse proxy)
|
||||
└── SSL/TLS
|
||||
```
|
||||
|
||||
## 🔄 Coordination Mechanism
|
||||
|
||||
### Crawler-Sender Synchronization
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Coordination Flow │
|
||||
│ │
|
||||
│ 6:00 AM → Crawler starts │
|
||||
│ ↓ │
|
||||
│ Crawling articles... │
|
||||
│ ↓ │
|
||||
│ Saves to MongoDB │
|
||||
│ ↓ │
|
||||
│ 6:20 AM → Crawler finishes │
|
||||
│ ↓ │
|
||||
│ 7:00 AM → Sender starts │
|
||||
│ ↓ │
|
||||
│ Check: Recent articles? ──→ No ──┐ │
|
||||
│ ↓ Yes │ │
|
||||
│ Proceed with send │ │
|
||||
│ │ │
|
||||
│ ← Wait 30s ← Wait 30s ← Wait 30s┘ │
|
||||
│ (max 30 minutes) │
|
||||
│ │
|
||||
│ 7:10 AM → Newsletter sent │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 📈 Monitoring & Observability
|
||||
|
||||
### Key Metrics
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Metrics to Monitor │
|
||||
│ │
|
||||
│ Crawler: │
|
||||
│ - Articles crawled per day │
|
||||
│ - Crawl duration │
|
||||
│ - Success/failure rate │
|
||||
│ - Summary generation rate │
|
||||
│ │
|
||||
│ Sender: │
|
||||
│ - Newsletters sent per day │
|
||||
│ - Send duration │
|
||||
│ - Success/failure rate │
|
||||
│ - Wait time for crawler │
|
||||
│ │
|
||||
│ Engagement: │
|
||||
│ - Open rate │
|
||||
│ - Click-through rate │
|
||||
│ - Active subscribers │
|
||||
│ - Dormant subscribers │
|
||||
│ │
|
||||
│ System: │
|
||||
│ - Container uptime │
|
||||
│ - Database size │
|
||||
│ - Error rate │
|
||||
│ - Response times │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 🛠️ Maintenance Tasks
|
||||
|
||||
### Daily
|
||||
- Check logs for errors
|
||||
- Verify newsletters sent
|
||||
- Monitor engagement metrics
|
||||
|
||||
### Weekly
|
||||
- Review article quality
|
||||
- Check subscriber growth
|
||||
- Analyze engagement trends
|
||||
|
||||
### Monthly
|
||||
- Archive old articles
|
||||
- Clean up dormant subscribers
|
||||
- Update dependencies
|
||||
- Review system performance
|
||||
|
||||
## 📚 Technology Stack
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Technology Stack │
|
||||
│ │
|
||||
│ Backend: │
|
||||
│ - Python 3.11 │
|
||||
│ - Flask (API) │
|
||||
│ - PyMongo (Database) │
|
||||
│ - Schedule (Automation) │
|
||||
│ - Jinja2 (Templates) │
|
||||
│ - BeautifulSoup (Parsing) │
|
||||
│ │
|
||||
│ Database: │
|
||||
│ - MongoDB 7.0 │
|
||||
│ │
|
||||
│ AI/ML: │
|
||||
│ - Ollama (Summarization) │
|
||||
│ - Phi3 Model (default) │
|
||||
│ │
|
||||
│ Infrastructure: │
|
||||
│ - Docker & Docker Compose │
|
||||
│ - Linux (Ubuntu/Debian) │
|
||||
│ │
|
||||
│ Email: │
|
||||
│ - SMTP (configurable) │
|
||||
│ - HTML emails with tracking │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2024-01-16
|
||||
**Version**: 1.0
|
||||
**Status**: Production Ready ✅
|
||||
Reference in New Issue
Block a user