Bluesky Feed Dashboard
A personalized Bluesky feed generator with a Python (FastAPI) backend and Preact frontend.
Architecture
- Backend: Python 3.11+ with FastAPI
- Frontend: Preact (React alternative) with TypeScript
- Database: SQLite with embeddings storage
- ML: Scikit-learn for TF-IDF text embeddings
Quick Start
Prerequisites
- Python 3.11+
- Node.js 20+
- Nix (optional, for reproducible dev environment)
Development Setup
Using Nix (Recommended)
# Enter development shell
nix develop
# Install frontend dependencies
cd ClientApp && npm install && cd ..
# Build frontend
cd ClientApp && npm run build && cd ..
# Start backend
python run.py
Using pip
# Install Python dependencies
pip install -r requirements.txt
# Install frontend dependencies
cd ClientApp && npm install && cd ..
# Build frontend
cd ClientApp && npm run build && cd ..
# Start backend
python run.py
The server will start on http://localhost:5000.
Development with hot reload
# Terminal 1: Backend with hot reload
python run.py
# Terminal 2: Frontend with hot reload
cd ClientApp && npm run dev
The frontend dev server runs on http://localhost:3000 and proxies API requests to the backend.
Project Structure
.
├── backend/ # Python FastAPI backend
│ ├── main.py # FastAPI app and routes
│ ├── models/ # Pydantic models
│ └── services/ # Business logic
│ ├── catalog.py # Feed catalog
│ ├── feed_store.py # SQLite storage
│ ├── feed_generator.py # Bluesky feed protocol
│ ├── ranking.py # Feed ranking algorithm
│ ├── text_embedding.py # TF-IDF embeddings
│ ├── import_service.py # Feed import
│ └── identity.py # OAuth/identity resolution
├── ClientApp/ # Preact frontend
│ ├── src/
│ │ ├── main.tsx # Entry point
│ │ ├── App.tsx # Router
│ │ ├── store.ts # Global state
│ │ ├── types/ # TypeScript types
│ │ ├── services/ # API clients
│ │ ├── components/ # UI components
│ │ └── pages/ # Page components
│ └── package.json
├── wwwroot/ # Static files
│ ├── app.css # Legacy styles
│ ├── preact-app.css # New Preact styles
│ └── js/ # Built JS bundles
├── app_data/ # SQLite database (created at runtime)
├── run.py # Entry point
├── requirements.txt # Python deps
├── pyproject.toml # Poetry config
└── flake.nix # Nix dev environment
API Endpoints
Feed Generator (AT Protocol)
GET /.well-known/did.json- DID DocumentGET /oauth/client-metadata.json- OAuth client metadataGET /xrpc/app.bsky.feed.describeFeedGenerator- Feed descriptionGET /xrpc/app.bsky.feed.getFeedSkeleton?feed=...- Feed posts
Dashboard API
GET /api/oauth/config- OAuth configurationGET /api/feed-generators- List available generatorsGET /api/feed-generator-info- Feed generator infoGET /api/feed-state?actor_did=...&generator_id=...- Get ranked feedGET /api/like-feed?actor_did=...- Get liked networkPOST /api/feed-import- Import liked networkPOST /api/feed-signals- Add feedback signal
Environment Variables
# Required for published feed
FEED_GENERATOR_SERVICE_DID=did:web:yourdomain.com
FEED_GENERATOR_SERVICE_URL=https://yourdomain.com
FEED_GENERATOR_FEED_KEY=main-feed
FEED_GENERATOR_DISPLAY_NAME="My Smart Feed"
FEED_GENERATOR_DESCRIPTION="Personalized feed based on your likes"
# OAuth
BLUESKY_OAUTH_PUBLIC_ORIGIN=https://yourdomain.com
# Server
PORT=5000
HOST=0.0.0.0
Migration from .NET
This project was ported from .NET/Blazor Server to Python/FastAPI + Preact:
- Backend: C# services → Python services with identical logic
- Frontend: Blazor Razor components → Preact functional components
- State: Blazor component state → Preact signals
- Routing: Blazor router → Preact router
- API: Minimal API → FastAPI with same endpoints
The SQLite schema remains compatible with existing data.
License
MIT