SignalStack is a high-performance, backend-driven signal intelligence system. It monitors high-trust RSS streams, processes them through a dedicated scoring engine, and surfaces critical events in a real-time dashboard.
This is a monorepo containing the entire SignalStack ecosystem:
/backend: NestJS API, PostgreSQL data layer, and the automated Signal Crawler./frontend: Next.js 16 Dashboard with triple-column desktop views and mobile optimization./models: Local AI GGUF models (llama.cpp) - not committed to git.DOCS.md: Full technical documentation, scoring rules, and architecture deep-dive.
Local development:
- Infrastructure:
docker compose up postgres -d - Backend:
cd backendnpm installnpm run db:pushnpm run start:dev
- Frontend:
cd frontendnpm installnpm run dev
Access the system at http://localhost:3001.
Production VPS deploy (zero-downtime):
./scripts/deploy.shBy default, this script builds new images while old containers serve traffic, then fast-swaps (~3β5s downtime) and auto-rolls back if health checks fail.
Diagnostic & Health Check:
./scripts/test-endpoints.shRuns a premium diagnostic suite against all API endpoints to verify system integrity and latency.
Updating (one command):
git push origin main && deploy-signalThe deploy-signal shell alias SSHs into the VPS and runs deploy.sh automatically. See DOCS.md for alias setup.
To run zero-cost local AI inference with llama.cpp:
# 1. Download Qwen2.5-0.5B model (~497MB) - recommended for clean summaries
mkdir -p models
curl -L -o models/qwen.gguf "https://huggingface.co/unsloth/Qwen2.5-0.5B-GGUF/resolve/main/Qwen2.5-0.5B-Q4_K_M.gguf"
# 2. Start llama.cpp
docker compose up -d llama
# 3. Enable local AI (edit .env)
LOCAL_AI_ENABLED=trueSummarization chain: Groq β OpenRouter β Local llama.cpp (auto-retry with 60s cooldown on 429)
Translation chain (localized feed): Groq β PicoClaw/Mac llama.cpp β OpenRouter β Local llama.cpp
PicoClaw is a lightweight LXC router (192.168.0.213:9000) that forwards translation requests to Mac llama.cpp via Tailscale (100.84.207.28:8081), providing free local inference without cloud quota.
In production (docker-compose.prod.yml), llama is constrained to 0.5 CPU and 1GB RAM to prevent idle CPU starvation on small VPS instances.
The admin panel at /admin provides:
- AI Health β real-time status of all AI providers with latency
- Model Selection β searchable dropdowns to switch Groq/OpenRouter models on the fly
- Signal Stats β total signals, severity breakdown, category counts, AI processing metrics
- AI Retry β re-queue failed AI signals with one click
- Source Management β CRUD for RSS feed sources with bulk select and health checks
- Category Management β manage intelligence categories
- Jobs Feed β remote/tech job listings from RSS with Discord filter config
- Company Radar β find local IT companies via OpenStreetMap + career page auto-detection
- Logs β live log viewer via
signalstack-logscontainer - Settings β API keys (Groq/OpenRouter), Discord webhooks, dark/light mode toggle
- Database Backup β manual and automated daily backups
- Worker Dashboard β per-signal AI processing stats with read/unread state tracking
Save signals for later review. Bookmarks are persisted in the database and synced across sessions.
- Bookmark button on each signal card and in the detail modal with loading state and toast feedback
- Share button β copy signal URL to clipboard
- Bookmarks filter in the column control bar to view only saved signals
- API:
GET /api/bookmarks(list IDs),POST /api/bookmarks/{signalId}(toggle),GET /api/bookmarks/signals(full data with pagination)
The main dashboard features:
- Localized feed β Bengali (and other language) translation via AI; signals without an AI summary fall back to translating the raw content so no English leaks into localized views
- Triple-column layout β Geopolitics, Technology, and Artificial Intelligence streams side by side (tabbed on mobile, persisted)
- Visibility controls β Toggle any of the three streams on/off to customize your view, with state persisted locally
- Mobile bottom nav β fixed Feed / Trends / Saved / Admin tabs with safe-area padding
- Grid & List modes β dense list view or expanded card grid with severity color stripes
- Signal Detail Modal β scrollable dialog with full title, AI summary, content preview (HTML-stripped), and metadata
- Bookmark/Save Signals β save signals with loading feedback and toast notifications, persisted in database
- Saved deep-link β
/supports?bookmarks=trueto open directly in bookmark mode - Share Signal β copy source URL to clipboard with one click
- Search β debounced server-side search across titles, sources, and content
- Severity filters β score-based All / High (β₯8) / Medium (5β7) / Low (<5) toggles
- Source & sort controls β filter by feed source, sort by newest/oldest/score
- Infinite scroll β signals auto-load as you scroll
- Skeleton loading β shimmer placeholder cards for smoother perceived performance
The Trends page at /trends provides 30-day analytics with interactive charts:
- KPI Cards β Total Signals, High Severity, Last 24h, Top Source
- Signal Volume β Stacked area chart with gradient fills and glow effects by severity
- Top Sources β Ranked list with animated gradient progress bars and average scores
- Category Breakdown β Bar chart with gradient fills
- Severity Distribution β Donut chart with center total label
- AI Provider Stats β Per-provider gradient bar chart with processed/failed counts
- Geographic Heatmap β World map showing signal counts by country (click to filter)
Open-access page with 5-minute auto-refresh. Theme-aware chart labels for correct contrast in both dark and light modes.
A public RSS 2.0 feed is available at /api/feed.xml for consuming signals programmatically.
Endpoints:
GET /api/feed.xmlβ Full feed (last 50 signals with score >= 5)GET /api/feed.xml?category=geopoliticsβ Filter by categoryGET /api/feed.xml?severity=highβ Filter by minimum severityGET /api/feed.xml?category=technology&severity=mediumβ Combined filters
Response headers:
Content-Type: application/rss+xmlCache-Control: public, max-age=900(15 min cache)
Feed items are sorted chronologically by published_at DESC (newest first) for RSS reader compatibility.
Each item includes custom signal:score and signal:source elements.
Discord alerts send clean, HTML-free embeds with severity-based color coding (red/orange/green). RSS content and titles are fully sanitized during feed ingestion β all HTML entities (including numeric like ’) are decoded and all tags (including <script>/<style>) are stripped before storing in the database.
Alerts are filtered by category and severity to reduce noise:
- Technology: Medium (Score 7-9) and High (Score 10+) alerts.
- Geopolitics: High (Score 10+) alerts only.
Configure via environment variables:
DISCORD_WEBHOOK_URL=your-webhook-url
DISCORD_ALERT_CATEGORIES=technology,geopolitics
DISCORD_FILTER_TECH=false # Set to false to bypass unpopulated AI categories- Global API throttle:
100 requests / minute / IPfor public API endpoints via NestJS throttler - Admin throttle bypass: authenticated admin controllers use
@SkipThrottle() - Retention cleanup cron: daily
2:00 AMjob deletes signals older thanSIGNAL_RETENTION_DAYS(default90) and removes orphaned bookmarks
SIGNAL_RETENTION_DAYS=90The admin portal (/admin) uses email/password authentication with bcrypt-hashed passwords and JWT sessions.
- Credentials stored in a
userstable with bcrypt password hashing - JWT tokens issued as HTTP-only secure cookies (15m access + 7d refresh)
- Default credentials:
admin@signalstack.local/changeme123 - Configure via
ADMIN_EMAILandADMIN_PASSWORDenv vars before first deploy
Private / Internal Protocol