226 lines
8.2 KiB
Markdown
226 lines
8.2 KiB
Markdown
# Magent
|
|
|
|
Magent is a friendly, AI-assisted request tracker for Seerr + Arr services. It shows a clear timeline of where a request is stuck, explains what is happening in plain English, and offers safe actions to help fix issues.
|
|
|
|
## How it works
|
|
|
|
1) Requests are pulled from Seerr and stored locally.
|
|
2) Magent joins that request to Sonarr/Radarr, Prowlarr, qBittorrent, and Jellyfin using TMDB/TVDB IDs and download hashes.
|
|
3) A state engine normalizes noisy service statuses into a simple, user-friendly state.
|
|
4) The UI renders a timeline and a central status box for each request.
|
|
5) Optional AI triage summarizes the likely cause and safest next steps.
|
|
|
|
## Core features
|
|
|
|
- Request search by title/year or request ID.
|
|
- Recent requests list with posters and status.
|
|
- Timeline view across Seerr, Arr, Prowlarr, qBittorrent, Jellyfin.
|
|
- Central status box with clear reason + next steps.
|
|
- Safe action buttons (search, resume, re-add, etc.).
|
|
- Admin settings for service URLs, API keys, profiles, and root folders.
|
|
- Health status for each service in the pipeline.
|
|
- Cache and sync controls (full sync, delta sync, scheduled syncs).
|
|
- Local database for speed and audit history.
|
|
- Users and access control (admin vs user, block access).
|
|
- Local account password changes via "My profile".
|
|
- Personal viewing stats from Jellystat: minutes, movies, episodes, streaks, and recent plays alongside requests. See [Jellystat setup](docs/jellystat-integration.md).
|
|
- Admin review and confirmation of account IDs across Jellyfin, Seerr, Jellystat and Magent. See [user identities](docs/user-identities.md).
|
|
- Docker-first deployment for easy hosting.
|
|
|
|
## Quick start (Docker - primary)
|
|
|
|
Docker is the recommended way to run Magent. It includes the backend and frontend with sane defaults.
|
|
|
|
```bash
|
|
docker compose up --build
|
|
```
|
|
|
|
Then open:
|
|
|
|
- Frontend: http://localhost:3000
|
|
- Backend: http://localhost:8000
|
|
|
|
### Docker setup steps
|
|
|
|
1) Create `.env` with your service URLs and API keys.
|
|
2) Run `docker compose up --build`.
|
|
3) Log in at http://localhost:3000.
|
|
4) Visit Settings to confirm service health.
|
|
|
|
### Docker environment variables (sample)
|
|
|
|
```bash
|
|
JELLYSEERR_URL="http://localhost:5055"
|
|
JELLYSEERR_API_KEY="..."
|
|
SONARR_URL="http://localhost:8989"
|
|
SONARR_API_KEY="..."
|
|
SONARR_QUALITY_PROFILE_ID="1"
|
|
SONARR_ROOT_FOLDER="/tv"
|
|
RADARR_URL="http://localhost:7878"
|
|
RADARR_API_KEY="..."
|
|
RADARR_QUALITY_PROFILE_ID="1"
|
|
RADARR_ROOT_FOLDER="/movies"
|
|
PROWLARR_URL="http://localhost:9696"
|
|
PROWLARR_API_KEY="..."
|
|
QBIT_URL="http://localhost:8080"
|
|
QBIT_USERNAME="..."
|
|
QBIT_PASSWORD="..."
|
|
SQLITE_PATH="data/magent.db"
|
|
JWT_SECRET="replace-with-at-least-32-random-characters"
|
|
SETTINGS_ENCRYPTION_KEY="replace-with-a-fernet-key"
|
|
JWT_EXP_MINUTES="120"
|
|
ADMIN_USERNAME="set-a-real-admin-username"
|
|
ADMIN_PASSWORD="set-a-long-unique-admin-password"
|
|
```
|
|
|
|
## Screenshots
|
|
|
|
Add screenshots here once available:
|
|
|
|
- `docs/screenshots/home.png`
|
|
- `docs/screenshots/request-timeline.png`
|
|
- `docs/screenshots/settings.png`
|
|
- `docs/screenshots/profile.png`
|
|
|
|
## Local development (secondary)
|
|
|
|
Use this only when you need to modify code locally.
|
|
|
|
### Backend (FastAPI)
|
|
|
|
```bash
|
|
cd backend
|
|
python -m venv .venv
|
|
.\.venv\Scripts\Activate.ps1
|
|
pip install -r requirements.txt
|
|
uvicorn app.main:app --reload --port 8000
|
|
```
|
|
|
|
Environment variables (sample):
|
|
|
|
```bash
|
|
$env:JELLYSEERR_URL="http://localhost:5055"
|
|
$env:JELLYSEERR_API_KEY="..."
|
|
$env:SONARR_URL="http://localhost:8989"
|
|
$env:SONARR_API_KEY="..."
|
|
$env:SONARR_QUALITY_PROFILE_ID="1"
|
|
$env:SONARR_ROOT_FOLDER="/tv"
|
|
$env:RADARR_URL="http://localhost:7878"
|
|
$env:RADARR_API_KEY="..."
|
|
$env:RADARR_QUALITY_PROFILE_ID="1"
|
|
$env:RADARR_ROOT_FOLDER="/movies"
|
|
$env:PROWLARR_URL="http://localhost:9696"
|
|
$env:PROWLARR_API_KEY="..."
|
|
$env:QBIT_URL="http://localhost:8080"
|
|
$env:QBIT_USERNAME="..."
|
|
$env:QBIT_PASSWORD="..."
|
|
$env:SQLITE_PATH="data/magent.db"
|
|
$env:JWT_SECRET="replace-with-at-least-32-random-characters"
|
|
$env:SETTINGS_ENCRYPTION_KEY="replace-with-a-fernet-key"
|
|
$env:JWT_EXP_MINUTES="120"
|
|
$env:ADMIN_USERNAME="set-a-real-admin-username"
|
|
$env:ADMIN_PASSWORD="set-a-long-unique-admin-password"
|
|
```
|
|
|
|
### Frontend (Next.js)
|
|
|
|
```bash
|
|
cd frontend
|
|
npm install
|
|
npm run dev
|
|
```
|
|
|
|
Open http://localhost:3000
|
|
|
|
Admin panel: http://localhost:3000/admin
|
|
|
|
Login uses the admin credentials above (or any other local user you create in SQLite).
|
|
|
|
### Local quality checks
|
|
|
|
```bash
|
|
bash scripts/ci_backend_quality_gate.sh
|
|
cd frontend
|
|
npm ci
|
|
npm run lint
|
|
npm run format:check
|
|
npm run typecheck
|
|
npm test
|
|
npm run build
|
|
```
|
|
|
|
## Public Hosting Notes
|
|
|
|
The frontend proxies `/api/*` to the backend container. Set:
|
|
|
|
- `NEXT_PUBLIC_API_BASE=/api` (browser uses same-origin)
|
|
- `BACKEND_INTERNAL_URL=http://backend:8000` (container-to-container)
|
|
|
|
If you prefer the browser to call the backend directly, set `NEXT_PUBLIC_API_BASE` to your public backend URL and ensure CORS is configured.
|
|
|
|
## Gitea CI/CD
|
|
|
|
This repo now includes a Gitea Actions workflow at `.gitea/workflows/ci-cd.yml`.
|
|
|
|
- Push to `beta`: runs the complete quality gate and deploys the isolated beta environment to `AMS-DEV01`.
|
|
- Push to `main` or `prod`: runs the same verification without automatically changing production.
|
|
- Production releases are tagged from `main` and deployed to `GRZ-DKR01` using the checklist in `PRODUCTION.md`.
|
|
|
|
The beta deploy step ships tracked repository files over SSH, preserves beta's own `.env` and `data/`, rebuilds with `docker compose up -d --build`, and smoke-tests:
|
|
|
|
- `http://127.0.0.1:8000/health`
|
|
- `http://127.0.0.1:3000/login`
|
|
|
|
Configure these Gitea Actions secrets before enabling the deploy job:
|
|
|
|
The existing `PROD_*` names are retained for compatibility, but this workflow uses them only for the isolated beta host deployment.
|
|
|
|
- `PROD_SSH_PRIVATE_KEY`: private key for the deployment account.
|
|
- `PROD_SSH_HOST`: target host, for example `AMS-DEV01`.
|
|
- `PROD_SSH_USER`: target user, for example `zak`.
|
|
- `PROD_DEPLOY_PATH`: beta app path, for example `/home/zak/magent-beta`.
|
|
- `PROD_SSH_KNOWN_HOSTS`: required pinned `known_hosts` entry. Deployments reject unknown or changed hosts.
|
|
|
|
## Security and data handling
|
|
|
|
Generate independent signing and settings-encryption secrets before first startup:
|
|
|
|
```bash
|
|
python -c "import secrets; print(secrets.token_urlsafe(48))"
|
|
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
|
|
```
|
|
|
|
- `JWT_SECRET` must contain at least 32 characters. Access sessions expire after 120 minutes by default and are revoked after logout, password, role, or blocked-state changes.
|
|
- `SETTINGS_ENCRYPTION_KEY` protects service API keys, SMTP credentials, webhooks, and private keys stored in SQLite. Keep it in `.env`, outside the database and its backups. If omitted, Magent derives a migration-compatible key from `JWT_SECRET`; a dedicated key is recommended.
|
|
- Invite secrets are stored as one-way hashes. Existing invite links continue to work after migration, but the admin UI cannot reveal an old link. Copy a link when it is created, or generate a replacement link later; replacement immediately invalidates the prior link.
|
|
- Magent encrypts sensitive settings, not the entire SQLite database. Request metadata, account records, logs, the `data/` volume, and backups should live on encrypted host storage with access restricted to the deployment account.
|
|
- `REQUESTS_CLEANUP_DAYS` controls routine request-history retention (90 days by default). Account deletion removes authentication and subscription records and anonymizes retained request and portal history.
|
|
- Production and beta cookies require HTTPS and use `SameSite=Strict`. Keep the backend port bound to loopback and publish the frontend only through the intended reverse proxy.
|
|
|
|
## History endpoints
|
|
|
|
- `GET /requests/{id}/history?limit=10` recent snapshots
|
|
- `GET /requests/{id}/actions?limit=10` recent action logs
|
|
|
|
## Troubleshooting
|
|
|
|
### Login fails
|
|
|
|
- Make sure `ADMIN_USERNAME` and `ADMIN_PASSWORD` are set in `.env`.
|
|
- Confirm the backend is reachable: `http://localhost:8000/health` (or see container logs).
|
|
|
|
### Services show as down
|
|
|
|
- Check the URLs and API keys in Settings.
|
|
- Verify containers can reach each service (network/DNS).
|
|
|
|
### No recent requests
|
|
|
|
- Confirm Seerr credentials in Settings.
|
|
- Run a full sync from Settings -> Requests.
|
|
|
|
### Docker images not updating
|
|
|
|
- Run `docker compose up --build` again.
|
|
- If needed, run `docker compose down` first, then rebuild.
|