# 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)

```bash
# 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

```bash
# 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

```bash
# 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 Document
- `GET /oauth/client-metadata.json` - OAuth client metadata
- `GET /xrpc/app.bsky.feed.describeFeedGenerator` - Feed description
- `GET /xrpc/app.bsky.feed.getFeedSkeleton?feed=...` - Feed posts

### Dashboard API

- `GET /api/oauth/config` - OAuth configuration
- `GET /api/feed-generators` - List available generators
- `GET /api/feed-generator-info` - Feed generator info
- `GET /api/feed-state?actor_did=...&generator_id=...` - Get ranked feed
- `GET /api/like-feed?actor_did=...` - Get liked network
- `POST /api/feed-import` - Import liked network
- `POST /api/feed-signals` - Add feedback signal

## Environment Variables

```bash
# 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:

1. **Backend**: C# services → Python services with identical logic
2. **Frontend**: Blazor Razor components → Preact functional components
3. **State**: Blazor component state → Preact signals
4. **Routing**: Blazor router → Preact router
5. **API**: Minimal API → FastAPI with same endpoints

The SQLite schema remains compatible with existing data.

## License

MIT
An unhandled error has occurred. Reload 🗙