nandi / dashboard

Clone: git clone http://git.latha.org/nandi/dashboard.git
📁 .direnv
📁 backend
📁 ClientApp
📁 wwwroot
📄 .envrc 10 B
📄 .gitignore 318 B
📄 Dockerfile 385 B
📄 flake.lock 2.4 KB
📄 flake.nix 4.8 KB
📄 fly.toml 356 B
📄 justfile 1.5 KB
📄 pyproject.toml 676 B
📄 README.md 4.4 KB
📄 requirements.txt 211 B
📄 result 53 B
📄 run.py 521 B
📄 uv.lock 212.9 KB

README.md

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

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

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