docs: fix stale-live docs and drop obsolete Obsidian spec
Refreshes the docs that were actively misleading about the current FastAPI + React + service-registry app, and deletes one obsolete design. - CONTRIBUTING.md: full rewrite — Streamlit-era guidance replaced with the current backend (ruff/pytest, src/ layout) + frontend (npm lint/build/test) workflow, service-registry model, and shadcn/Tailwind stack. Mirrors AGENTS.md. - README.md: removed the non-existent /addons/:addonId route (Services page is current); fixed the per-machine Jellyfin wording; replaced the py_compile dev snippet with ruff + pytest / npm lint+build+test. - backend/README.md: updated the structure tree (removed deleted clients/resources.py; added routers backups/services/tasks/widgets, integrations/, models/, widgets/, workers/); dropped the "starts the collector" sentence (MonitoringPoller is decommissioned). - frontend/README.md: corrected the uvicorn module path (main:app -> media_library_viewer_api.main:app). - Deleted docs/superpowers/specs/2026-05-08-obsidian-documentation-design.md (Obsidian vault never built; stack refs MUI/D3/AG Grid all removed). Historical docs (MIGRATION_PLAN, superpowers backup-monitoring, the bannered design/runbook/context files) deferred to a later banner pass.
This commit is contained in:
+77
-20
@@ -1,55 +1,114 @@
|
|||||||
# Contributing
|
# Contributing
|
||||||
|
|
||||||
Thanks for considering a contribution.
|
Thanks for considering a contribution to Manage.
|
||||||
|
|
||||||
|
Manage is a media and server-operations dashboard built from two subprojects:
|
||||||
|
|
||||||
|
- **`backend/`** — FastAPI (Python 3.11) REST API using a `src/` layout.
|
||||||
|
- **`frontend/`** — Vite + React + TypeScript SPA.
|
||||||
|
- **`archive/`** — the original Streamlit prototype, preserved for reference only. Do **not** use it as a guide; the app is FastAPI + React now.
|
||||||
|
|
||||||
|
The authoritative contributor quick-reference is [`AGENTS.md`](./AGENTS.md). This document mirrors it for human contributors.
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
|
### Backend
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
cd backend
|
||||||
python -m venv .venv
|
python -m venv .venv
|
||||||
source .venv/bin/activate
|
source .venv/bin/activate
|
||||||
pip install -e '.[dev]'
|
pip install -e '.[dev]'
|
||||||
```
|
```
|
||||||
|
|
||||||
Copy env template:
|
### Frontend
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cp .env.example .env
|
cd frontend
|
||||||
|
npm install
|
||||||
```
|
```
|
||||||
|
|
||||||
Then set real values in `.env` and run:
|
### Local stack (optional)
|
||||||
|
|
||||||
|
For a full local dev stack with hot reload (auth disabled):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
streamlit run app.py
|
docker compose -f docker-compose.dev.yml up --build
|
||||||
```
|
```
|
||||||
|
|
||||||
## Development guidelines
|
The dev compose deploys only the backend and frontend; Manage never deploys an
|
||||||
|
observability stack. For the optional standalone observability example, see
|
||||||
|
`docker-compose.observability.yml` and `docs/observability-runbooks.md`.
|
||||||
|
|
||||||
|
## Development commands
|
||||||
|
|
||||||
|
Run backend checks from `backend/` and frontend checks from `frontend/`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Backend: lint + tests
|
||||||
|
cd backend && ruff check . && python -m pytest
|
||||||
|
|
||||||
|
# Run the API locally (if the package is installed as above)
|
||||||
|
uvicorn media_library_viewer_api.main:app --reload --port 8000
|
||||||
|
# Otherwise, without installing: PYTHONPATH=src uvicorn media_library_viewer_api.main:app --reload --port 8000
|
||||||
|
|
||||||
|
# Focused backend tests
|
||||||
|
pytest tests/test_api.py
|
||||||
|
pytest -k <expr>
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Frontend: dev server (proxies /api to http://localhost:8000)
|
||||||
|
cd frontend && npm run dev
|
||||||
|
|
||||||
|
# Frontend: lint + typecheck/build (build runs tsc -b + vite build) + tests
|
||||||
|
npm run lint
|
||||||
|
npm run build
|
||||||
|
npm run test
|
||||||
|
```
|
||||||
|
|
||||||
|
## Guidelines
|
||||||
|
|
||||||
- Keep architecture boundaries clear:
|
- Keep architecture boundaries clear:
|
||||||
- `clients/` for external integrations
|
- `clients/` for external service transports (Jellyfin, Jellyseerr, SSH, local shell).
|
||||||
- `domain/` for normalization/business logic
|
- `integrations/` for service-registry definitions (config schema, secrets, widget kinds).
|
||||||
- `services/` for app services/indexing
|
- `domain/` for normalization/business logic.
|
||||||
- `ui/` for Streamlit rendering
|
- `services/` for app services, indexing, persistence, and background workers.
|
||||||
|
- `routers/` for FastAPI route handlers.
|
||||||
|
- `models/` for Pydantic request/response schemas.
|
||||||
|
- Prefer small, focused functions and explicit names.
|
||||||
|
- Preserve safe SSH behavior and shell quoting — job templates must quote all interpolated values.
|
||||||
|
- External services (Jellyfin, Grafana, Prometheus, Alertmanager, …) are configured at runtime via the **service registry** in the UI, not environment variables. The only observability env var is `PROMETHEUS_ENABLED` (Manage's own `/metrics` toggle).
|
||||||
- Avoid introducing optional fallback paths unless required.
|
- Avoid introducing optional fallback paths unless required.
|
||||||
- Prefer small, focused functions and explicit session-state keys.
|
|
||||||
- Preserve safe SSH behavior and path quoting.
|
|
||||||
|
|
||||||
## Validation
|
### Backend style
|
||||||
|
|
||||||
Before opening a merge request, run:
|
Backend linting/format is Ruff (line length 120, Python 3.11); config lives in `backend/pyproject.toml`.
|
||||||
|
|
||||||
|
### Frontend style
|
||||||
|
|
||||||
|
The frontend uses **shadcn/ui + Tailwind CSS v4 + lucide-react + TanStack Query + TanStack Table**. Do not introduce MUI, Emotion, recharts, d3, or AG Grid — those were removed and are not coming back.
|
||||||
|
|
||||||
|
## Validation before opening a merge request
|
||||||
|
|
||||||
|
Before opening a merge request, run and ensure green:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
PYTHONPATH=src python -m py_compile app.py src/media_library_viewer/*.py src/media_library_viewer/clients/*.py src/media_library_viewer/domain/*.py src/media_library_viewer/services/*.py src/media_library_viewer/ui/*.py
|
cd backend && ruff check . && python -m pytest
|
||||||
|
cd frontend && npm run lint && npm run build && npm run test
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If behavior, UX, or architecture changed, also update `docs/REQUIREMENTS.md`.
|
||||||
|
|
||||||
## Security / secrets
|
## Security / secrets
|
||||||
|
|
||||||
Never commit:
|
Never commit:
|
||||||
|
|
||||||
- `.env`
|
- `.env`
|
||||||
- `.streamlit/secrets.toml`
|
|
||||||
- private keys or API tokens
|
- private keys or API tokens
|
||||||
|
- service secrets
|
||||||
|
|
||||||
Use `.env.example` for documented placeholders only.
|
Service secrets are encrypted at rest with `MANAGE_ENCRYPTION_KEY` (required to start the backend). Use `.env.example` for documented placeholders only.
|
||||||
|
|
||||||
## Pull requests
|
## Pull requests
|
||||||
|
|
||||||
@@ -57,6 +116,4 @@ Please include:
|
|||||||
|
|
||||||
- what changed
|
- what changed
|
||||||
- why it changed
|
- why it changed
|
||||||
- how it was tested
|
- how it was tested (commands run / tests added)
|
||||||
|
|
||||||
If behavior/requirements changed, also update `docs/REQUIREMENTS.md`.
|
|
||||||
|
|||||||
@@ -20,15 +20,15 @@ The project consists of two subprojects:
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Configurable dashboard with persisted widgets (Jellyfin activity, backups summary, Grafana deep-links, Prometheus metrics, SSH task output, static text) and shortcuts
|
- Configurable dashboard with persisted widgets (Jellyfin activity, backups summary, Grafana deep-links, Prometheus metrics, Alertmanager alerts, SSH task output, static text) and shortcuts
|
||||||
- Thin-dashboard observability: Alertmanager alerts, Prometheus target health, machine status, and Grafana deep-links (no in-app charting)
|
- Thin-dashboard observability: Alertmanager alerts, Prometheus target health, machine status, and Grafana deep-links (no in-app charting)
|
||||||
- Per-machine settings for Jellyfin, Jellyseerr, SSH, and monitoring targets
|
- Service registry: configure Jellyfin, Jellyseerr, Alertmanager, Grafana, Prometheus, Nextcloud, and SSH task runner instances in the UI
|
||||||
|
- Per-machine settings for SSH, monitoring targets, and file browsing
|
||||||
- SQLite-indexed media table with full-library sort/filter
|
- SQLite-indexed media table with full-library sort/filter
|
||||||
- Read-only Users tab with Jellyfin as the base source and optional Jellyseerr enrichment
|
- Read-only Users tab with Jellyfin as the base source and optional Jellyseerr enrichment
|
||||||
- Remote file browser with ffprobe preview and job execution
|
- Remote file browser with ffprobe preview and job execution
|
||||||
- Jellyfin API integration for library metadata and user identity data
|
- Jellyfin API integration for library metadata and user identity data
|
||||||
- SSH-based file inspection and safe remote job templates
|
- SSH-based file inspection and safe remote job templates
|
||||||
- Addon pages for Grafana, Prometheus, and SSH tasks at `/addons/:addonId`
|
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
@@ -172,13 +172,15 @@ ssh user@host
|
|||||||
## Development
|
## Development
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Backend
|
# Backend (lint + tests)
|
||||||
cd backend && PYTHONPATH=src python -m py_compile src/media_library_viewer_api/main.py
|
cd backend && .venv/bin/ruff check . && .venv/bin/python -m pytest
|
||||||
|
|
||||||
# Frontend
|
# Frontend (lint + typecheck/build + tests)
|
||||||
cd frontend && npx tsc --noEmit && npm run build
|
cd frontend && npm run lint && npm run build && npm run test
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Focused frontend typecheck: `npx tsc --noEmit`.
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
- Jellyfin server root URL required (not `/web`). The client strips trailing `/web` defensively.
|
- Jellyfin server root URL required (not `/web`). The client strips trailing `/web` defensively.
|
||||||
|
|||||||
+27
-10
@@ -13,29 +13,46 @@ backend/
|
|||||||
│ ├── __init__.py
|
│ ├── __init__.py
|
||||||
│ ├── main.py # FastAPI app entrypoint
|
│ ├── main.py # FastAPI app entrypoint
|
||||||
│ ├── config.py # pydantic-settings config
|
│ ├── config.py # pydantic-settings config
|
||||||
|
│ ├── auth.py # OIDC/JWT + API key auth
|
||||||
│ ├── dependencies.py # Dependency injection
|
│ ├── dependencies.py # Dependency injection
|
||||||
|
│ ├── observability.py # Prometheus metrics + request IDs
|
||||||
|
│ ├── logging_utils.py # Structured JSON/text logging
|
||||||
│ ├── path_utils.py # Jellyfin→SSH path resolution
|
│ ├── path_utils.py # Jellyfin→SSH path resolution
|
||||||
│ ├── jobs.py # Job templates
|
│ ├── jobs.py # Job templates
|
||||||
│ ├── utils.py # Formatting helpers
|
│ ├── utils.py # Formatting helpers
|
||||||
│ ├── routers/
|
│ ├── routers/
|
||||||
|
│ │ ├── backups.py
|
||||||
│ │ ├── dashboard.py
|
│ │ ├── dashboard.py
|
||||||
│ │ ├── monitoring.py
|
|
||||||
│ │ ├── media.py
|
|
||||||
│ │ ├── users.py
|
|
||||||
│ │ ├── settings.py
|
|
||||||
│ │ ├── files.py
|
│ │ ├── files.py
|
||||||
│ │ └── jobs.py
|
│ │ ├── jobs.py
|
||||||
|
│ │ ├── media.py
|
||||||
|
│ │ ├── monitoring.py
|
||||||
|
│ │ ├── services.py
|
||||||
|
│ │ ├── settings.py
|
||||||
|
│ │ ├── tasks.py
|
||||||
|
│ │ ├── users.py (+ users_impl.py)
|
||||||
|
│ │ └── widgets.py
|
||||||
│ ├── clients/
|
│ ├── clients/
|
||||||
│ │ ├── jellyfin.py
|
│ │ ├── jellyfin.py
|
||||||
│ │ ├── jellyseerr.py
|
│ │ ├── jellyseerr.py
|
||||||
│ │ ├── local.py
|
│ │ ├── local.py
|
||||||
│ │ ├── resources.py
|
|
||||||
│ │ └── ssh.py
|
│ │ └── ssh.py
|
||||||
|
│ ├── integrations/ # Service-registry definitions
|
||||||
│ ├── domain/
|
│ ├── domain/
|
||||||
│ │ └── media.py
|
│ │ └── media.py
|
||||||
│ └── services/
|
│ ├── models/ # Pydantic request/response models
|
||||||
│ ├── media_index.py
|
│ ├── services/
|
||||||
│ └── settings_store.py
|
│ │ ├── media_index.py (+ _impl.py)
|
||||||
|
│ │ ├── settings_store.py
|
||||||
|
│ │ ├── secrets.py # Fernet encryption at rest
|
||||||
|
│ │ ├── targets.py # Node Exporter target discovery
|
||||||
|
│ │ ├── task_runner.py
|
||||||
|
│ │ ├── mail_queue.py (+ mailer.py/_impl.py)
|
||||||
|
│ │ ├── backup_alert_engine.py (+ backup_poller.py)
|
||||||
|
│ │ ├── known_hosts.py
|
||||||
|
│ │ └── db_maintenance.py
|
||||||
|
│ ├── widgets/ # Widget sources (dashboard data adapters)
|
||||||
|
│ └── workers/ # Background workers (media index)
|
||||||
└── tests/
|
└── tests/
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -127,7 +144,7 @@ docker compose up --build
|
|||||||
- **Local**: monitors the API host itself without SSH.
|
- **Local**: monitors the API host itself without SSH.
|
||||||
- **SSH**: monitors another machine using a host, username, and a private key pasted directly into the machine settings, with an optional passphrase.
|
- **SSH**: monitors another machine using a host, username, and a private key pasted directly into the machine settings, with an optional passphrase.
|
||||||
- The machine editor groups Connection, Monitoring / Files, Jellyfin, Jellyseerr, and Notes under separate headings so each service area is easier to scan.
|
- The machine editor groups Connection, Monitoring / Files, Jellyfin, Jellyseerr, and Notes under separate headings so each service area is easier to scan.
|
||||||
- Saving a monitoring machine now validates the banner/auth flow, records the first trusted host key into the backend-managed `known_hosts` file, and starts the collector so charts populate without a separate manual step.
|
- Saving a monitoring machine validates the banner/auth flow and records the first trusted host key into the backend-managed `known_hosts` file.
|
||||||
- If the host cannot be reached or authenticated, the save flow surfaces the SSH error directly in the dialog.
|
- If the host cannot be reached or authenticated, the save flow surfaces the SSH error directly in the dialog.
|
||||||
- Use **Validate SSH + trust host** in the machine editor before saving if you want to test the banner/auth flow explicitly.
|
- Use **Validate SSH + trust host** in the machine editor before saving if you want to test the banner/auth flow explicitly.
|
||||||
- The first successful SSH connection uses trust-on-first-use: the backend records that machine's host key into its managed `known_hosts` file automatically, then continues verifying it strictly on later connects.
|
- The first successful SSH connection uses trust-on-first-use: the backend records that machine's host key into its managed `known_hosts` file automatically, then continues verifying it strictly on later connects.
|
||||||
|
|||||||
@@ -1,53 +0,0 @@
|
|||||||
# Obsidian Documentation Structure for Manage (Media Library Viewer)
|
|
||||||
|
|
||||||
**Date:** 2026-05-08
|
|
||||||
**Status:** Approved
|
|
||||||
|
|
||||||
## Purpose
|
|
||||||
|
|
||||||
Create a comprehensive, interconnected Obsidian documentation vault for the Manage project (media library viewer application). The documentation targets all audiences: future developers, contributors, operators, and deployers.
|
|
||||||
|
|
||||||
## Structure
|
|
||||||
|
|
||||||
### Map of Content (MOC)
|
|
||||||
- `manage/Overview.md` — Central hub with wikilinks to all documentation areas
|
|
||||||
|
|
||||||
### Architecture & Overview
|
|
||||||
- `manage/Architecture.md` — System design, data flow, tech stack
|
|
||||||
- `manage/Directory Structure.md` — Annotated codebase layout
|
|
||||||
|
|
||||||
### Backend
|
|
||||||
- `manage/Backend/API Endpoints.md` — Complete REST endpoint map
|
|
||||||
- `manage/Backend/Configuration.md` — Settings, env vars, OIDC
|
|
||||||
- `manage/Backend/Services.md` — Core services: settings store, media index, poller, mail
|
|
||||||
- `manage/Backend/Clients.md` — External integrations: Jellyfin, Jellyseerr, SSH
|
|
||||||
|
|
||||||
### Frontend
|
|
||||||
- `manage/Frontend/Pages & Routing.md` — Routes, page components
|
|
||||||
- `manage/Frontend/Components.md` — Reusable components
|
|
||||||
- `manage/Frontend/State & Data.md` — Hooks, QueryClient, data fetching
|
|
||||||
- `manage/Frontend/Auth & Theme.md` — OIDC auth, MUI theme
|
|
||||||
|
|
||||||
### Deployment
|
|
||||||
- `manage/Deployment/Production.md` — Docker Compose, Traefik, TLS
|
|
||||||
- `manage/Deployment/Development.md` — Dev workflow, hot reload
|
|
||||||
|
|
||||||
### Operations
|
|
||||||
- `manage/Operations/Machine Management.md` — SSH keys, collectors
|
|
||||||
- `manage/Operations/Monitoring.md` — Poller, metrics
|
|
||||||
- `manage/Operations/Tasks & Jobs.md` — Saved tasks, job templates
|
|
||||||
|
|
||||||
### Development
|
|
||||||
- `manage/Development/Setup.md` — Getting started for backend + frontend
|
|
||||||
- `manage/Development/Testing.md` — Test structure and commands
|
|
||||||
- `manage/Development/Contributing.md` — Conventions, PR workflow
|
|
||||||
|
|
||||||
## Cross-Linking Conventions
|
|
||||||
- Every note uses YAML frontmatter with `tags` and `aliases`
|
|
||||||
- Related docs linked via `[[wikilinks]]`
|
|
||||||
- Callouts for warnings, tips, and notes
|
|
||||||
|
|
||||||
## Technologies Referenced
|
|
||||||
- Backend: Python 3.11+, FastAPI, SQLite, Paramiko, PyJWT
|
|
||||||
- Frontend: React 19, TypeScript 6, Vite 8, MUI 9, D3 7, AG Grid
|
|
||||||
- Infra: Docker, Traefik, Authentik/OIDC
|
|
||||||
+1
-1
@@ -31,7 +31,7 @@ Make sure the backend is running:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd ../backend
|
cd ../backend
|
||||||
uvicorn main:app --reload --port 8000
|
uvicorn media_library_viewer_api.main:app --reload --port 8000
|
||||||
```
|
```
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|||||||
@@ -1077,7 +1077,10 @@ export function Settings() {
|
|||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<FormField label="Local hint">
|
<FormField label="Local hint">
|
||||||
<Input value="Uses the API host directly" disabled />
|
<Input
|
||||||
|
value="Uses the API host directly"
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
</FormField>
|
</FormField>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user