You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
139 lines
6.1 KiB
Markdown
139 lines
6.1 KiB
Markdown
# AI Weekly Synth
|
|
|
|
## Overview
|
|
AI Weekly Synth is a self-hosted web application that generates AI-powered weekly news syntheses. Users configure their topics, categories, and preferred LLM provider, then the app searches the web, validates sources, and produces structured summaries.
|
|
|
|
## Architecture
|
|
- **Backend**: Rust (Axum) — `backend/`
|
|
- **Frontend**: SolidJS + Tailwind CSS v4 — `frontend/`
|
|
- **Database**: PostgreSQL (via sqlx with compile-time checked queries)
|
|
- **Deployment**: Docker only (`docker-compose.yml`)
|
|
|
|
## Project Structure
|
|
```
|
|
ai_synth/
|
|
├── backend/ Rust/Axum backend
|
|
│ ├── src/
|
|
│ │ ├── main.rs Entry point, CLI (serve, create-admin)
|
|
│ │ ├── router.rs All API routes + middleware stack
|
|
│ │ ├── handlers/ HTTP handlers (auth, settings, sources, syntheses, admin, etc.)
|
|
│ │ ├── services/ Business logic (auth, email, encryption, scraper, LLM providers, synthesis pipeline)
|
|
│ │ ├── db/ Database queries (sqlx)
|
|
│ │ ├── models/ Data types + validation
|
|
│ │ ├── middleware/ Auth session extraction, CSRF check
|
|
│ │ └── util/ Token generation, hashing
|
|
│ ├── migrations/ SQL migrations (9 files)
|
|
│ ├── tests/ Integration tests (require Postgres)
|
|
│ ├── Cargo.toml
|
|
│ └── Dockerfile Multi-stage build
|
|
├── frontend/ SolidJS frontend
|
|
│ ├── src/
|
|
│ │ ├── App.tsx Router, layouts, route guards
|
|
│ │ ├── pages/ Login, Register, Home, Settings, Sources, GenerateSynthesis, SynthesisDetail, admin/*
|
|
│ │ ├── components/ Navbar, Layout, AdminLayout, Turnstile, ApiKeyManager, ui/*
|
|
│ │ ├── api/ API clients (auth, settings, sources, syntheses, admin, config, apiKeys)
|
|
│ │ ├── contexts/ AuthContext (session-based)
|
|
│ │ ├── i18n/ French translations (i18n-ready for future languages)
|
|
│ │ └── utils/ SSE client, date formatting, provider info
|
|
│ ├── package.json
|
|
│ └── vite.config.ts SolidJS + Tailwind + dev proxy
|
|
├── docs/ Analysis reports + implementation plans
|
|
├── docker-compose.yml App + Postgres
|
|
├── .env.example All required env vars documented
|
|
└── CLAUDE.md This file
|
|
```
|
|
|
|
## Key Features
|
|
- **Authentication**: Email + magic link (passwordless), Cloudflare Turnstile captcha, 30-day session cookies
|
|
- **LLM Providers**: Google Gemini, OpenAI, Anthropic — users bring their own API keys
|
|
- **Generation Pipeline**: 2-pass (search with web grounding → scrape/validate URLs → rewrite summaries), adaptive per provider
|
|
- **Admin Module**: Provider/model curation, rate limit config, user management
|
|
- **Security**: AES-256-GCM encryption for API keys at rest, SSRF prevention in scraper, CSRF via X-Requested-With, HttpOnly/SameSite cookies
|
|
- **Export**: Email via Resend, PDF, Markdown
|
|
- **Real-time**: SSE for generation progress streaming
|
|
|
|
## Running Locally
|
|
|
|
### Docker (production-like)
|
|
```bash
|
|
cp .env.example .env # Fill in values
|
|
docker compose up
|
|
```
|
|
|
|
### Development
|
|
```bash
|
|
# Backend (requires Postgres running)
|
|
cd backend && cargo run -- serve
|
|
|
|
# Frontend (proxies /api to backend)
|
|
cd frontend && npm install && npm run dev
|
|
```
|
|
|
|
### CLI
|
|
```bash
|
|
# Create first admin user
|
|
cd backend && cargo run -- create-admin admin@example.com
|
|
```
|
|
|
|
## Testing
|
|
```bash
|
|
# Backend unit tests (no Postgres needed)
|
|
cd backend && cargo test --lib
|
|
|
|
# Backend integration tests (requires Postgres)
|
|
TEST_DATABASE_URL=postgres://user:pass@localhost:5432/postgres cargo test
|
|
|
|
# Frontend unit tests
|
|
cd frontend && npx vitest run
|
|
|
|
# Frontend type check
|
|
cd frontend && npx tsc --noEmit
|
|
```
|
|
|
|
## API Endpoints
|
|
|
|
### Public
|
|
- `POST /api/v1/auth/register` — create account + magic link
|
|
- `POST /api/v1/auth/login` — request magic link
|
|
- `GET /api/v1/auth/verify` — verify token (email click)
|
|
- `POST /api/v1/auth/verify` — verify token (frontend API)
|
|
- `GET /api/v1/health` — health check
|
|
|
|
### Authenticated
|
|
- `GET/PUT /api/v1/settings` — user settings
|
|
- `GET/POST/DELETE /api/v1/sources` — sources CRUD + bulk/CSV import/export
|
|
- `GET/DELETE /api/v1/syntheses/:id` — syntheses CRUD
|
|
- `POST /api/v1/syntheses/generate` — trigger async generation
|
|
- `GET /api/v1/syntheses/generate/:job_id/progress` — SSE progress stream
|
|
- `POST /api/v1/syntheses/:id/send-email` — email synthesis
|
|
- `GET /api/v1/syntheses/:id/export/markdown` — Markdown download
|
|
- `GET /api/v1/syntheses/:id/export/pdf` — PDF download
|
|
- `GET/POST/DELETE /api/v1/user/api-keys` — LLM API key management
|
|
- `GET /api/v1/config/providers` — available providers/models
|
|
|
|
### Admin Only
|
|
- `GET/POST/PUT/DELETE /api/v1/admin/providers` — provider/model config
|
|
- `GET/PUT /api/v1/admin/rate-limits` — rate limit config
|
|
- `GET /api/v1/admin/users` — user list
|
|
- `PUT /api/v1/admin/users/:id/role` — role management
|
|
|
|
## Database (9 migrations)
|
|
Tables: `users`, `sessions`, `magic_link_tokens`, `user_settings`, `sources`, `syntheses`, `admin_providers`, `admin_rate_limits`, `user_api_keys`, `audit_log`
|
|
|
|
## Environment Variables
|
|
See `.env.example` for the complete list. Key ones:
|
|
- `DATABASE_URL` — Postgres connection string
|
|
- `MASTER_ENCRYPTION_KEY` — 64 hex chars for AES-256-GCM
|
|
- `SESSION_SECRET` — at least 64 chars
|
|
- `RESEND_API_KEY` — for email sending
|
|
- `TURNSTILE_SECRET_KEY` / `TURNSTILE_SITE_KEY` — captcha
|
|
- `APP_URL` — public URL (for CORS, magic links, cookies)
|
|
|
|
## Design Decisions
|
|
- Idiomatic Rust (learning project) — no unwrap() in production code
|
|
- Users bring their own LLM API keys (encrypted at rest)
|
|
- Admin curates available providers/models, users select from the list
|
|
- Single-tenant self-hosted (one instance per deployment)
|
|
- i18n-ready (French only for now, all strings in `frontend/src/i18n/fr.ts`)
|
|
- Adaptive generation pipeline: skips scrape+rewrite when native web grounding is sufficient
|