feat(release): prepare first public preview
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
!Dockerfile
|
!Dockerfile
|
||||||
!.dockerignore
|
!.dockerignore
|
||||||
!LICENSE
|
!LICENSE
|
||||||
|
!THIRD_PARTY_NOTICES.md
|
||||||
!backend/
|
!backend/
|
||||||
!backend/requirements.txt
|
!backend/requirements.txt
|
||||||
!backend/app/
|
!backend/app/
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
*.png binary
|
*.png binary
|
||||||
*.jpg binary
|
*.jpg binary
|
||||||
*.jpeg binary
|
*.jpeg binary
|
||||||
|
*.webp binary
|
||||||
*.gif binary
|
*.gif binary
|
||||||
*.ico binary
|
*.ico binary
|
||||||
*.pdf binary
|
*.pdf binary
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Report reproducible behavior that looks wrong
|
||||||
|
title: "[Bug] "
|
||||||
|
labels: ""
|
||||||
|
---
|
||||||
|
|
||||||
|
## What happened?
|
||||||
|
|
||||||
|
<!-- Describe the visible problem. -->
|
||||||
|
|
||||||
|
## What did you expect?
|
||||||
|
|
||||||
|
<!-- Describe the expected result. -->
|
||||||
|
|
||||||
|
## How can we reproduce it?
|
||||||
|
|
||||||
|
1.
|
||||||
|
2.
|
||||||
|
3.
|
||||||
|
|
||||||
|
## Environment
|
||||||
|
|
||||||
|
- Magent version/tag:
|
||||||
|
- Container image digest, if applicable:
|
||||||
|
- Installation method (Compose, Portainer, docker run, native):
|
||||||
|
- Host OS and CPU architecture:
|
||||||
|
- Browser and version:
|
||||||
|
- Reverse proxy, if applicable:
|
||||||
|
- Connected app and version involved:
|
||||||
|
|
||||||
|
## Sanitized diagnostics
|
||||||
|
|
||||||
|
<!-- Paste the smallest relevant error/log excerpt. Redact private addresses and user data. -->
|
||||||
|
|
||||||
|
- [ ] I searched existing issues and the troubleshooting guides.
|
||||||
|
- [ ] I reproduced this on the current public preview.
|
||||||
|
- [ ] I removed passwords, tokens, API keys, cookies, email addresses, private URLs and personal data.
|
||||||
|
- [ ] I did not attach an `.env`, database, backup or generated secrets file.
|
||||||
|
- [ ] This is not a security vulnerability. Security reports follow `SECURITY.md`.
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest an improvement to Magent
|
||||||
|
title: "[Feature] "
|
||||||
|
labels: ""
|
||||||
|
---
|
||||||
|
|
||||||
|
## Problem
|
||||||
|
|
||||||
|
<!-- Who has this problem, and what are they trying to do? -->
|
||||||
|
|
||||||
|
## Desired outcome
|
||||||
|
|
||||||
|
<!-- Describe the user-visible result. -->
|
||||||
|
|
||||||
|
## Current workaround
|
||||||
|
|
||||||
|
<!-- How do you handle it today? -->
|
||||||
|
|
||||||
|
## Relevant integration
|
||||||
|
|
||||||
|
<!-- If this needs another app, include its name, version and public API docs. -->
|
||||||
|
|
||||||
|
## Additional context
|
||||||
|
|
||||||
|
<!-- Mockups and synthetic examples are welcome. Remove private data. -->
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
---
|
||||||
|
name: Installation help
|
||||||
|
about: Ask for help with a documented installation path
|
||||||
|
title: "[Install] "
|
||||||
|
labels: ""
|
||||||
|
---
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
<!-- What are you trying to install, and where? -->
|
||||||
|
|
||||||
|
## Method and environment
|
||||||
|
|
||||||
|
- Installation guide followed:
|
||||||
|
- Host OS and CPU architecture:
|
||||||
|
- Docker/Compose/Portainer/Python/Node versions, as applicable:
|
||||||
|
- Browser-facing URL scheme (`http` or `https`; redact private hostnames if needed):
|
||||||
|
- Reverse proxy, if applicable:
|
||||||
|
|
||||||
|
## Where it stopped
|
||||||
|
|
||||||
|
<!-- Include the exact command/step and sanitized output. -->
|
||||||
|
|
||||||
|
## Checks already tried
|
||||||
|
|
||||||
|
- [ ] I checked the matching troubleshooting table.
|
||||||
|
- [ ] I confirmed the container/service health and retained the same data path.
|
||||||
|
- [ ] I removed credentials, tokens, cookies, private URLs and personal data.
|
||||||
|
- [ ] I did not attach an `.env`, database, backup or generated secrets file.
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
## What and why
|
||||||
|
|
||||||
|
<!-- Explain the user problem and the change. -->
|
||||||
|
|
||||||
|
## Validation
|
||||||
|
|
||||||
|
<!-- List exact commands/checks run and any skipped platform checks. -->
|
||||||
|
|
||||||
|
- [ ] Backend tests pass or are not affected.
|
||||||
|
- [ ] Frontend tests, lint, format, typecheck and build pass or are not affected.
|
||||||
|
- [ ] Documentation and changelog are updated where needed.
|
||||||
|
- [ ] New behavior has regression coverage.
|
||||||
|
- [ ] No credentials, user data, databases, backups or private deployment details are included.
|
||||||
|
|
||||||
|
## Compatibility
|
||||||
|
|
||||||
|
<!-- Note database, configuration, container, API or upgrade effects. -->
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
This file records public Magent releases. The in-application changelog contains
|
||||||
|
the shorter user-facing highlights.
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
|
||||||
|
- No unreleased changes recorded.
|
||||||
|
|
||||||
|
## 0.1.0-preview.1 — 2026-09-22
|
||||||
|
|
||||||
|
First public preview.
|
||||||
|
|
||||||
|
### Included
|
||||||
|
|
||||||
|
- Guided first-install setup for the administrator, application URL and optional integrations.
|
||||||
|
- Request discovery, submission and status tracking across Seerr and Arr services.
|
||||||
|
- Jellyfin playback links, issue reporting and repair follow-up.
|
||||||
|
- Jellystat viewing insights, monthly reports and optional email recaps.
|
||||||
|
- Local/Jellyfin sign-in, invitations, account linking and feature controls.
|
||||||
|
- Encrypted configuration/database backups with staged, restart-only restore.
|
||||||
|
- Docker Compose, Docker CLI, Portainer, native Linux and foreground setup guides.
|
||||||
|
- Hardened non-root container defaults and a documented release smoke harness.
|
||||||
|
|
||||||
|
### Known limits
|
||||||
|
|
||||||
|
- The published image is validated for Linux/amd64 only.
|
||||||
|
- One writable SQLite instance and one backend worker are supported; HA is not.
|
||||||
|
- Native Linux services have static systemd validation, not broad distribution certification.
|
||||||
|
- This preview does not promise an LTS window or security-response SLA.
|
||||||
|
|
||||||
|
### Upgrade note
|
||||||
|
|
||||||
|
Existing installations must retain their data mount and signing/encryption keys.
|
||||||
|
Create an encrypted backup, record the running image digest, and follow the
|
||||||
|
[upgrade guidance](docs/DOCKER.md#updates-and-rollback).
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# Repository guide
|
||||||
|
|
||||||
|
Magent combines a FastAPI backend, Next.js frontend and SQLite database. Read
|
||||||
|
`CONTRIBUTING.md` before changing code and `docs/INSTALLATION.md` before changing
|
||||||
|
deployment behavior.
|
||||||
|
|
||||||
|
## Important paths
|
||||||
|
|
||||||
|
- `backend/app/`: API, integrations, setup, persistence and background work.
|
||||||
|
- `frontend/app/`: application routes and interface components.
|
||||||
|
- `backend/tests/` and frontend `*.test.*`: synthetic regression coverage.
|
||||||
|
- `compose.yml`: public prebuilt-image deployment.
|
||||||
|
- `Dockerfile`: pinned multi-stage production build.
|
||||||
|
|
||||||
|
## Working rules
|
||||||
|
|
||||||
|
- Never read, commit or print real `.env`, database, backup or credential data.
|
||||||
|
- Keep SQLite to one backend worker and one writable application instance.
|
||||||
|
- Preserve origin checks, CSP nonces, non-root execution and persistent key/data paths.
|
||||||
|
- Add regression tests and run the checks in `CONTRIBUTING.md`.
|
||||||
|
- Use synthetic fixtures; do not call live media services from tests.
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# Community Code of Conduct
|
||||||
|
|
||||||
|
Magent's community should be practical, welcoming and safe for people with
|
||||||
|
different backgrounds and levels of experience.
|
||||||
|
|
||||||
|
## Expected behavior
|
||||||
|
|
||||||
|
- Be respectful and specific when discussing code, ideas or mistakes.
|
||||||
|
- Assume good intent while accepting corrections and evidence.
|
||||||
|
- Give useful context and protect other people's privacy.
|
||||||
|
- Welcome questions without mocking a person's experience level.
|
||||||
|
- Keep feedback about the work, not the person.
|
||||||
|
|
||||||
|
Harassment, threats, discrimination, sexualized attention, deliberate exposure
|
||||||
|
of private information, and repeated disruptive behavior are not acceptable.
|
||||||
|
|
||||||
|
Maintainers may edit or remove contributions and temporarily or permanently
|
||||||
|
restrict participation when needed to protect the community. Non-sensitive
|
||||||
|
conduct concerns can be raised through the issue tracker. The public preview
|
||||||
|
does not yet publish a monitored private conduct-reporting channel; do not put
|
||||||
|
private evidence or personal information in a public issue.
|
||||||
|
|
||||||
|
This code applies in project spaces and when representing the project elsewhere.
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
# Contributing to Magent
|
||||||
|
|
||||||
|
Thanks for helping improve Magent. Small, reviewable changes with a clear reason
|
||||||
|
are the easiest to test and merge.
|
||||||
|
|
||||||
|
## Before opening an issue
|
||||||
|
|
||||||
|
- Use [SUPPORT.md](SUPPORT.md) to choose the right report type.
|
||||||
|
- Search existing issues and read the relevant installation guide.
|
||||||
|
- Remove credentials, tokens, email addresses, database content and private URLs.
|
||||||
|
- Use [SECURITY.md](SECURITY.md) for vulnerabilities; do not publish exploit details.
|
||||||
|
|
||||||
|
## Development setup
|
||||||
|
|
||||||
|
Use Python 3.14 and Node.js 24. Follow
|
||||||
|
[the foreground development guide](docs/LOCAL_DEVELOPMENT.md), use synthetic
|
||||||
|
data, and never connect tests to someone else's services.
|
||||||
|
|
||||||
|
## Quality checks
|
||||||
|
|
||||||
|
Backend:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
python -m venv .venv
|
||||||
|
. .venv/bin/activate
|
||||||
|
pip install -r backend/requirements-dev.txt
|
||||||
|
python -m unittest discover -s backend/tests -p 'test_*.py'
|
||||||
|
python scripts/check_environment_docs.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Frontend:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cd frontend
|
||||||
|
npm ci
|
||||||
|
npm test
|
||||||
|
npm run lint
|
||||||
|
npm run format:check
|
||||||
|
npm run typecheck
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
Container changes should also pass both isolated smoke modes:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
docker build -t magent:review .
|
||||||
|
bash scripts/ci_container_smoke.sh magent:review
|
||||||
|
MAGENT_SMOKE_MANAGED=true bash scripts/ci_container_smoke.sh magent:review
|
||||||
|
```
|
||||||
|
|
||||||
|
The smoke harness creates disposable containers, networks and volumes. Do not
|
||||||
|
aim it at a live instance or reuse a production volume.
|
||||||
|
|
||||||
|
## Pull requests
|
||||||
|
|
||||||
|
1. Base public work on the `release` branch.
|
||||||
|
2. Keep each pull request focused and explain the user-visible reason.
|
||||||
|
3. Add or update tests for behavior changes.
|
||||||
|
4. Update documentation and `CHANGELOG.md` when behavior or setup changes.
|
||||||
|
5. State exactly which checks ran and any platform limits or skipped checks.
|
||||||
|
6. Do not commit generated builds, `.env` files, logs, databases, backups or secrets.
|
||||||
|
|
||||||
|
By contributing, you agree that your contribution is licensed under the project's
|
||||||
|
[MIT License](LICENSE). Participation must follow the
|
||||||
|
[Code of Conduct](CODE_OF_CONDUCT.md).
|
||||||
+8
-2
@@ -54,6 +54,8 @@ RUN node --version
|
|||||||
|
|
||||||
ARG MAGENT_UID=1000
|
ARG MAGENT_UID=1000
|
||||||
ARG MAGENT_GID=1000
|
ARG MAGENT_GID=1000
|
||||||
|
ARG MAGENT_VERSION=0.1.0-preview.1
|
||||||
|
ARG MAGENT_REVISION=unknown
|
||||||
RUN addgroup -g ${MAGENT_GID} magent \
|
RUN addgroup -g ${MAGENT_GID} magent \
|
||||||
&& adduser -D -u ${MAGENT_UID} -G magent -s /sbin/nologin magent \
|
&& adduser -D -u ${MAGENT_UID} -G magent -s /sbin/nologin magent \
|
||||||
&& install -d -o magent -g magent -m 0700 /app/data \
|
&& install -d -o magent -g magent -m 0700 /app/data \
|
||||||
@@ -76,12 +78,16 @@ COPY --chown=magent:magent --from=frontend-builder /frontend/.next/static /app/f
|
|||||||
COPY --chown=magent:magent --from=frontend-builder /frontend/public /app/frontend/public
|
COPY --chown=magent:magent --from=frontend-builder /frontend/public /app/frontend/public
|
||||||
|
|
||||||
COPY docker/supervisord.conf /etc/supervisor/conf.d/magent.conf
|
COPY docker/supervisord.conf /etc/supervisor/conf.d/magent.conf
|
||||||
COPY LICENSE /usr/share/licenses/magent/LICENSE
|
COPY --chown=magent:magent LICENSE /usr/share/licenses/magent/LICENSE
|
||||||
|
COPY --chown=magent:magent THIRD_PARTY_NOTICES.md /usr/share/licenses/magent/THIRD_PARTY_NOTICES.md
|
||||||
COPY --from=frontend-builder /licenses /usr/share/licenses/magent/frontend
|
COPY --from=frontend-builder /licenses /usr/share/licenses/magent/frontend
|
||||||
|
|
||||||
LABEL org.opencontainers.image.title="Magent" \
|
LABEL org.opencontainers.image.title="Magent" \
|
||||||
org.opencontainers.image.description="Self-hosted media requests, issues and viewing insights" \
|
org.opencontainers.image.description="Self-hosted media requests, issues and viewing insights" \
|
||||||
org.opencontainers.image.licenses="MIT"
|
org.opencontainers.image.licenses="MIT" \
|
||||||
|
org.opencontainers.image.source="https://git.amslabs.net/Rephl3x/Magent-Public" \
|
||||||
|
org.opencontainers.image.version="${MAGENT_VERSION}" \
|
||||||
|
org.opencontainers.image.revision="${MAGENT_REVISION}"
|
||||||
|
|
||||||
USER magent:magent
|
USER magent:magent
|
||||||
|
|
||||||
|
|||||||
@@ -1,78 +1,111 @@
|
|||||||
# Magent
|
# Magent
|
||||||
|
|
||||||
Self-hosted media requests, viewing stats and issue management for Jellyfin,
|
Magent is a self-hosted home for media requests, viewing insights and issue
|
||||||
Seerr, Sonarr, Radarr and related services. Magent combines a Python/FastAPI API,
|
follow-up. It sits in front of Jellyfin, Seerr, Sonarr, Radarr and related apps,
|
||||||
a Next.js frontend and SQLite. Run the prebuilt non-root container or install
|
then turns their technical state into a clearer experience for the people using
|
||||||
the Python and Node.js services directly—Portainer is optional.
|
your server.
|
||||||
|
|
||||||
## Install
|
**Public preview:** `0.1.0-preview.1` · [Source code](https://git.amslabs.net/Rephl3x/Magent-Public) ·
|
||||||
|
[Docker Hub](https://hub.docker.com/r/rephl3xnz/magent) · [MIT license](LICENSE)
|
||||||
|
|
||||||
Start with the [installation guide](docs/INSTALLATION.md) to choose a method:
|

|
||||||
|
|
||||||
| Method | Instructions |
|
Magent does not store or stream media, replace your existing applications, or
|
||||||
| --- | --- |
|
provide content. You bring and operate those services; Magent connects to them.
|
||||||
| Docker Compose or `docker run` | [Docker installation](docs/DOCKER.md) |
|
|
||||||
| Portainer | [Single-file stack](docs/PORTAINER.md) |
|
|
||||||
| Linux without Docker | [Native install and systemd services](docs/NATIVE_INSTALL.md) |
|
|
||||||
| Windows/macOS/Linux foreground | [Source installation and development](docs/LOCAL_DEVELOPMENT.md) |
|
|
||||||
|
|
||||||
For a fresh **Docker Compose** install, download [compose.yml](compose.yml) into
|
## Why Magent?
|
||||||
its own deployment directory and run:
|
|
||||||
|
Media automation is powerful, but its status messages are written for operators.
|
||||||
|
Magent gives users one place to request something, understand what is happening,
|
||||||
|
see when it is ready, report a problem and follow the response.
|
||||||
|
|
||||||
|
- Search for and submit movie or TV requests through Seerr.
|
||||||
|
- Follow a request across approval, Arr monitoring, download and Jellyfin availability.
|
||||||
|
- Open ready titles in Jellyfin and report playback or library problems.
|
||||||
|
- View private Jellystat-powered viewing insights and monthly reports.
|
||||||
|
- Offer local or Jellyfin sign-in, invite-only registration and per-user features.
|
||||||
|
- Manage integrations, users, branding, notifications and diagnostics from the UI.
|
||||||
|
- Export an encrypted backup of configuration, SQLite data and optional artwork.
|
||||||
|
|
||||||
|
## Current scope
|
||||||
|
|
||||||
|
- The published container is validated on **Linux/amd64**.
|
||||||
|
- Magent is a single-instance application using one writable SQLite database. It
|
||||||
|
is not an HA, Kubernetes or multi-replica deployment.
|
||||||
|
- Native Windows foreground operation has been smoke-tested. Linux systemd files
|
||||||
|
are statically validated; macOS instructions are reviewed but not runtime-tested.
|
||||||
|
- This is an early public release. Pin an immutable image tag or digest, retain
|
||||||
|
backups, and test upgrades before using them on your main instance.
|
||||||
|
|
||||||
|
See [release notes](CHANGELOG.md) and [installation support boundaries](docs/INSTALLATION.md#platform-and-support-boundaries).
|
||||||
|
|
||||||
|
## Quick start with Docker Compose
|
||||||
|
|
||||||
|
Docker Compose is the recommended first installation. Create an empty directory,
|
||||||
|
download the public Compose file, and start Magent:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
curl --fail --location --output compose.yml \
|
||||||
|
https://git.amslabs.net/Rephl3x/Magent-Public/raw/branch/release/compose.yml
|
||||||
|
docker compose -f compose.yml -p magent pull
|
||||||
|
docker compose -f compose.yml -p magent up -d --wait --wait-timeout 120
|
||||||
|
docker compose -f compose.yml -p magent exec --user magent magent \
|
||||||
|
python -m app.container_bootstrap setup-token
|
||||||
|
```
|
||||||
|
|
||||||
|
PowerShell:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Invoke-WebRequest -Uri 'https://git.amslabs.net/Rephl3x/Magent-Public/raw/branch/release/compose.yml' -OutFile compose.yml
|
||||||
docker compose -f compose.yml -p magent pull
|
docker compose -f compose.yml -p magent pull
|
||||||
docker compose -f compose.yml -p magent up -d --wait --wait-timeout 120
|
docker compose -f compose.yml -p magent up -d --wait --wait-timeout 120
|
||||||
docker compose -f compose.yml -p magent ps
|
|
||||||
docker compose -f compose.yml -p magent exec --user magent magent python -m app.container_bootstrap setup-token
|
docker compose -f compose.yml -p magent exec --user magent magent python -m app.container_bootstrap setup-token
|
||||||
```
|
```
|
||||||
|
|
||||||
Keep that directory/project name and its persistent volume unchanged for updates.
|
Open `http://SERVER_IP:3000/setup`, enter the console-only token and confirm the
|
||||||
This uses `rephl3xnz/magent:latest` with no environment variables, local source
|
browser-facing URL. Then create the first administrator and connect the apps you
|
||||||
build or Dockerfile. Portainer users can paste the same file into a Docker
|
use. Optional integrations can be skipped. The managed image creates and retains
|
||||||
Standalone stack instead. Native users follow their separate guide for explicit
|
its own private keys; this path needs no `.env` or Dockerfile.
|
||||||
environment configuration and service management.
|
|
||||||
|
|
||||||
**Image availability:** the managed-install image is published on Docker Hub.
|
If you cloned the repository, the optional helper exposes the same operations:
|
||||||
Only Linux/amd64 has been validated. `latest` is mutable; record the resolved
|
`./setup.sh check`, `./setup.sh install`, and `./setup.sh token`. Read a script
|
||||||
image digest before updating, or pin an immutable release tag.
|
before running it; the documented Compose commands remain the canonical path.
|
||||||
|
|
||||||
1. Wait for the container to become healthy and retrieve the token using the
|
For public access, configure DNS and HTTPS before creating the administrator.
|
||||||
command above (or the Portainer console instructions in its guide).
|
Do not forward the plain HTTP port directly to the internet.
|
||||||
2. Open the Docker host's address on port 3000. Confirm the browser-facing URL
|
|
||||||
in setup and use the token to create the first administrator.
|
|
||||||
The **Get setup token** button shows the console instructions and lets you
|
|
||||||
copy the command; it never reveals the token to public visitors.
|
|
||||||
3. Connect your apps, choose preferences and finish setup. Optional apps can
|
|
||||||
be skipped. Save an encrypted backup afterwards.
|
|
||||||
|
|
||||||
Keep the Compose security block unchanged. Database storage is fixed at
|
## Other installation methods
|
||||||
`/app/data/magent.db` and API docs are disabled in managed installs. CORS and
|
|
||||||
cookie security follow the confirmed URL. Use HTTPS before public access.
|
|
||||||
|
|
||||||
See [all installation methods](docs/INSTALLATION.md),
|
| Method | Guide |
|
||||||
[all environment options](docs/ENVIRONMENT.md),
|
| --- | --- |
|
||||||
[backup and restore](docs/installation-and-recovery.md) and
|
| Docker Compose | [Complete Docker guide](docs/DOCKER.md#docker-compose) |
|
||||||
[advanced installation/upgrades](docs/PUBLIC_RELEASE.md).
|
| Docker CLI without Compose | [`docker run` guide](docs/DOCKER.md#docker-cli-without-compose) |
|
||||||
Existing installations must retain their original data volume and signing/
|
| Portainer | [Paste-and-deploy stack](docs/PORTAINER.md) |
|
||||||
encryption keys; this fresh-install template is not an automatic migration.
|
| Build the container from source | [Source-build override](docs/DOCKER.md#build-the-container-from-source) |
|
||||||
|
| Native Linux | [Python/Node and systemd](docs/NATIVE_INSTALL.md) |
|
||||||
|
| Windows, macOS or Linux foreground | [Local/source installation](docs/LOCAL_DEVELOPMENT.md) |
|
||||||
|
|
||||||
## Build and test
|
Start with the [installation overview](docs/INSTALLATION.md) if you are unsure.
|
||||||
|
The [environment reference](docs/ENVIRONMENT.md) documents every supported
|
||||||
|
variable, while [backup and recovery](docs/installation-and-recovery.md) covers
|
||||||
|
portable exports, offline snapshots and safe restore.
|
||||||
|
|
||||||
The source tree contains everything needed to build the application:
|
### Existing installations
|
||||||
|
|
||||||
|
Keep the same Compose project name, data mount and signing/encryption keys. The
|
||||||
|
fresh-install named volume is not an automatic migration of an existing bind
|
||||||
|
mount. Record your working image digest and make an encrypted backup before an
|
||||||
|
upgrade. Never use `docker compose down -v` on data you want to keep.
|
||||||
|
|
||||||
|
## Build and test from source
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
git clone --branch release --single-branch https://git.amslabs.net/Rephl3x/Magent-Public.git
|
||||||
|
cd Magent-Public
|
||||||
docker compose -f compose.yml -f compose.build.yml -p magent up -d --build
|
docker compose -f compose.yml -f compose.build.yml -p magent up -d --build
|
||||||
```
|
```
|
||||||
|
|
||||||
For a disposable verification run, without touching an existing installation:
|
The full quality gate uses Python 3.14 and Node.js 24:
|
||||||
|
|
||||||
```sh
|
|
||||||
docker build -t magent:review .
|
|
||||||
bash scripts/ci_container_smoke.sh magent:review
|
|
||||||
MAGENT_SMOKE_MANAGED=true bash scripts/ci_container_smoke.sh magent:review
|
|
||||||
```
|
|
||||||
|
|
||||||
Unit checks require Python 3.14 and Node 24:
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
python -m venv .venv
|
python -m venv .venv
|
||||||
@@ -86,37 +119,37 @@ npm test
|
|||||||
npm run lint
|
npm run lint
|
||||||
npm run format:check
|
npm run format:check
|
||||||
npm run typecheck
|
npm run typecheck
|
||||||
|
npm run build
|
||||||
```
|
```
|
||||||
|
|
||||||
On Windows, activate `.venv\Scripts\Activate.ps1` instead. Do not point tests
|
On Windows, use `.venv\Scripts\Activate.ps1`. Tests must use synthetic data and
|
||||||
at live services or use production credentials.
|
must never point at live media services.
|
||||||
|
|
||||||
## How it is organised
|
## Project layout
|
||||||
|
|
||||||
- `backend/app/routers/`: authenticated API endpoints and administration.
|
- `backend/app/`: FastAPI routes, service clients, request state, authentication,
|
||||||
- `backend/app/clients/`: media-service clients; `services/`: request states,
|
setup, notifications and encrypted backups.
|
||||||
synchronisation, notifications, setup and encrypted backups.
|
- `frontend/app/`: Next.js pages, shared UI, account portal and administration.
|
||||||
- `backend/app/db.py` and `schema_migrations.py`: SQLite persistence/migrations.
|
|
||||||
- `frontend/app/`: pages and shared interface components; `frontend/proxy.ts`:
|
|
||||||
browser security headers and request nonces.
|
|
||||||
- `backend/tests/` and frontend `*.test.*`: synthetic regression tests.
|
- `backend/tests/` and frontend `*.test.*`: synthetic regression tests.
|
||||||
- `Dockerfile` and `docker/`: multi-stage build and process supervision.
|
- `compose.yml`: prebuilt-image install; `compose.build.yml`: source-build override.
|
||||||
- `compose.yml`: prebuilt-image install; `compose.build.yml`: source override.
|
- `deploy/native/`: example Linux service units and private configuration templates.
|
||||||
- `deploy/native/`: example Linux service units and backend/frontend configuration.
|
- `docs/`: installation, environment, HTTPS, backup, upgrade and rollback guidance.
|
||||||
|
|
||||||
Requests are cached from Seerr, joined to collector/download/library evidence,
|
The `release` branch is a deliberately small public export. It excludes private
|
||||||
normalised into a user-facing state and displayed by the frontend. App settings
|
deployment automation, credentials, runtime data and internal Git history.
|
||||||
are stored in SQLite; sensitive settings are encrypted with installation-specific
|
|
||||||
keys. Integrations are optional and are configured through the setup wizard.
|
|
||||||
|
|
||||||
This `release` branch intentionally excludes internal deployment scripts,
|
## Help, feedback and contributions
|
||||||
environment files, runtime data, development reports and prior Git history.
|
|
||||||
It contains no workflow that automatically deploys or publishes an image.
|
|
||||||
|
|
||||||
## Contributing and security
|
- Read [SUPPORT.md](SUPPORT.md) before opening an installation or bug report.
|
||||||
|
- See [CONTRIBUTING.md](CONTRIBUTING.md) for development and pull-request checks.
|
||||||
|
- Report security concerns using [SECURITY.md](SECURITY.md); never post secrets or
|
||||||
|
exploit details in a public issue.
|
||||||
|
- Community participation follows [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md).
|
||||||
|
|
||||||
Keep changes focused, add regression tests and run the checks above. Never
|
Magent was developed through an iterative, AI-assisted workflow and then checked
|
||||||
commit tokens, database exports, backups or real user information.
|
with automated regression tests, isolated container smoke tests and a sanitized
|
||||||
See [SECURITY.md](SECURITY.md) for reporting guidance and deployment precautions.
|
public-release pass. Treat generated code like any other code: inspect it, test
|
||||||
|
it and report anything that does not make sense.
|
||||||
|
|
||||||
Licensed under [MIT](LICENSE). Third-party dependency licences remain applicable.
|
Magent is licensed under the [MIT License](LICENSE). Dependencies and base-image
|
||||||
|
components retain their own licenses; see [third-party notices](THIRD_PARTY_NOTICES.md).
|
||||||
|
|||||||
+10
-5
@@ -4,11 +4,16 @@
|
|||||||
|
|
||||||
Do not post passwords, access tokens, encryption keys, database exports, backup
|
Do not post passwords, access tokens, encryption keys, database exports, backup
|
||||||
files or live exploit details in public issues, discussions or container logs.
|
files or live exploit details in public issues, discussions or container logs.
|
||||||
Use the repository hosting platform's private vulnerability-reporting feature
|
Non-sensitive security hardening reports may be filed at
|
||||||
if the release owner has enabled it. Otherwise contact the maintainer privately
|
https://git.amslabs.net/Rephl3x/Magent-Public/issues/new after removing all
|
||||||
through the platform where you obtained this release before sending sensitive
|
deployment details and secrets. The public preview does not yet publish a
|
||||||
details. This repository does not currently advertise a dedicated reporting
|
monitored confidential-reporting channel. Do not put embargoed vulnerabilities,
|
||||||
address; the release owner must establish one before a broad public launch.
|
live exploits or sensitive evidence in a public issue. If a report cannot be
|
||||||
|
made safely in public, retain it until a private contact is listed here.
|
||||||
|
|
||||||
|
Reports are handled on a best-effort basis. The project does not promise a
|
||||||
|
specific response time or security-support window. The newest public preview is
|
||||||
|
the only version considered for security fixes unless a release note says otherwise.
|
||||||
|
|
||||||
Include the image tag/digest, affected version, a minimal reproduction using
|
Include the image tag/digest, affected version, a minimal reproduction using
|
||||||
synthetic data, and the security impact. Remove deployment credentials and
|
synthetic data, and the security impact. Remove deployment credentials and
|
||||||
|
|||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
# Support
|
||||||
|
|
||||||
|
Magent is an early public release maintained on a best-effort basis. There is no
|
||||||
|
paid support or guaranteed response time.
|
||||||
|
|
||||||
|
## Start here
|
||||||
|
|
||||||
|
- Installation choice: [docs/INSTALLATION.md](docs/INSTALLATION.md)
|
||||||
|
- Docker and Compose: [docs/DOCKER.md](docs/DOCKER.md)
|
||||||
|
- Portainer: [docs/PORTAINER.md](docs/PORTAINER.md)
|
||||||
|
- Native Linux: [docs/NATIVE_INSTALL.md](docs/NATIVE_INSTALL.md)
|
||||||
|
- Configuration: [docs/ENVIRONMENT.md](docs/ENVIRONMENT.md)
|
||||||
|
- Backup and restore: [docs/installation-and-recovery.md](docs/installation-and-recovery.md)
|
||||||
|
|
||||||
|
## Ask for help or report a problem
|
||||||
|
|
||||||
|
Use the matching issue template at
|
||||||
|
https://git.amslabs.net/Rephl3x/Magent-Public/issues/new.
|
||||||
|
|
||||||
|
Include the Magent version/tag and image digest, CPU architecture, installation
|
||||||
|
method, browser, exact reproduction steps, expected result and sanitized logs.
|
||||||
|
Say whether the problem survives a normal restart. Never attach `.env` files,
|
||||||
|
databases, backups, generated secret files, API keys, passwords, access tokens,
|
||||||
|
private URLs or personal viewing data.
|
||||||
|
|
||||||
|
Feature requests should describe the problem and intended user, not only a
|
||||||
|
proposed implementation. Integration requests should link to the upstream
|
||||||
|
application's public API documentation.
|
||||||
|
|
||||||
|
For a vulnerability, follow [SECURITY.md](SECURITY.md) instead of opening a
|
||||||
|
detailed public report.
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# Third-party notices
|
||||||
|
|
||||||
|
Magent's original source is licensed under the [MIT License](LICENSE). Third-party
|
||||||
|
software and assets retain their own copyright and license terms.
|
||||||
|
|
||||||
|
The exact JavaScript dependency graph and resolved versions are recorded in
|
||||||
|
`frontend/package-lock.json`. Production runtime packages include Next.js,
|
||||||
|
React, React DOM, Sharp and their transitive dependencies. Their license terms
|
||||||
|
come from the installed package metadata and license files, not from fields in
|
||||||
|
the lockfile. The release build collects discoverable production package
|
||||||
|
license and notice files under `/usr/share/licenses/magent/frontend`.
|
||||||
|
|
||||||
|
The exact direct Python versions are recorded in `backend/requirements.txt` and
|
||||||
|
`docker/requirements-runtime.txt`. Python package metadata and license files are
|
||||||
|
installed with those packages and remain subject to their respective terms.
|
||||||
|
|
||||||
|
The release container also contains components from its pinned Python, Node.js
|
||||||
|
and Alpine base images. Those components are not relicensed by Magent. The image
|
||||||
|
includes this notice, Magent's MIT license, Node.js's license, installed Python
|
||||||
|
package license files, discoverable production frontend license/notice files,
|
||||||
|
and any license files supplied by the Alpine packages in the runtime image under
|
||||||
|
`/usr/share/licenses`.
|
||||||
|
|
||||||
|
Before redistributing a modified image, regenerate and review its software bill
|
||||||
|
of materials and preserve every applicable license, copyright and notice file.
|
||||||
|
Lockfiles are the version inventory; this summary is not a replacement for the
|
||||||
|
complete license texts supplied by each dependency.
|
||||||
@@ -1,2 +1,5 @@
|
|||||||
BUILD_NUMBER = "0803262237"
|
BUILD_NUMBER = "0.1.0-preview.1"
|
||||||
CHANGELOG = '2026-09-19|Initial minimal release source snapshot'
|
CHANGELOG = """2026-09-22|First public preview
|
||||||
|
2026-09-22|Guided setup for Docker, Portainer and native installs
|
||||||
|
2026-09-22|Encrypted backup and staged restore
|
||||||
|
2026-09-22|Requests, viewing insights, invites and issue follow-up"""
|
||||||
|
|||||||
@@ -515,7 +515,7 @@ class SiteInfoTests(unittest.TestCase):
|
|||||||
"site_banner_tone": "warning",
|
"site_banner_tone": "warning",
|
||||||
"site_banner_background_color": "#123ABC",
|
"site_banner_background_color": "#123ABC",
|
||||||
"site_banner_border_color": "red",
|
"site_banner_border_color": "red",
|
||||||
"site_login_message": "Use your Grizzlyflix account to sign in.",
|
"site_login_message": "Use your ExampleFlix account to sign in.",
|
||||||
})
|
})
|
||||||
|
|
||||||
with patch.object(site_router, "get_runtime_settings", return_value=runtime):
|
with patch.object(site_router, "get_runtime_settings", return_value=runtime):
|
||||||
@@ -523,7 +523,7 @@ class SiteInfoTests(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertEqual(info["banner"]["backgroundColor"], "#123abc")
|
self.assertEqual(info["banner"]["backgroundColor"], "#123abc")
|
||||||
self.assertIsNone(info["banner"]["borderColor"])
|
self.assertIsNone(info["banner"]["borderColor"])
|
||||||
self.assertEqual(info["login"]["message"], "Use your Grizzlyflix account to sign in.")
|
self.assertEqual(info["login"]["message"], "Use your ExampleFlix account to sign in.")
|
||||||
|
|
||||||
|
|
||||||
class SiteSettingValidationTests(unittest.IsolatedAsyncioTestCase):
|
class SiteSettingValidationTests(unittest.IsolatedAsyncioTestCase):
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class IssueAcceptanceTests(TempDatabaseMixin, unittest.IsolatedAsyncioTestCase):
|
|||||||
content = email.await_args.kwargs
|
content = email.await_args.kwargs
|
||||||
self.assertEqual(content["subject"], f"Ready to try again? Magent issue #{item['id']}")
|
self.assertEqual(content["subject"], f"Ready to try again? Magent issue #{item['id']}")
|
||||||
self.assertIn("affected content in Jellyfin", content["body_text"])
|
self.assertIn("affected content in Jellyfin", content["body_text"])
|
||||||
self.assertNotIn("grizzlyflix", content["body_html"].lower())
|
self.assertNotIn("exampleflix", content["body_html"].lower())
|
||||||
self.assertIn("YES — it works", content["body_html"])
|
self.assertIn("YES — it works", content["body_html"])
|
||||||
self.assertIn("NO — still broken", content["body_html"])
|
self.assertIn("NO — still broken", content["body_html"])
|
||||||
self.assertIn(f"/issues/confirm/{item['id']}#yes", content["body_html"])
|
self.assertIn(f"/issues/confirm/{item['id']}#yes", content["body_html"])
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ class NewsletterConsentTests(NewsletterFixture, unittest.IsolatedAsyncioTestCase
|
|||||||
rendered = sender.call_args.args[1]
|
rendered = sender.call_args.args[1]
|
||||||
self.assertEqual(rendered['subject'], 'Confirm your Magent newsletter subscription')
|
self.assertEqual(rendered['subject'], 'Confirm your Magent newsletter subscription')
|
||||||
self.assertIn('NEW IN YOUR LIBRARY', rendered['body_html'])
|
self.assertIn('NEW IN YOUR LIBRARY', rendered['body_html'])
|
||||||
self.assertNotIn('grizzlyflix', rendered['body_html'].lower())
|
self.assertNotIn('exampleflix', rendered['body_html'].lower())
|
||||||
self.assertNotIn('Arrival', rendered['body_html'])
|
self.assertNotIn('Arrival', rendered['body_html'])
|
||||||
url = re.search(r'https://[^\s]+', rendered['body_text']).group(0)
|
url = re.search(r'https://[^\s]+', rendered['body_text']).group(0)
|
||||||
self.assertEqual(urlsplit(url).path, '/newsletter-subscription')
|
self.assertEqual(urlsplit(url).path, '/newsletter-subscription')
|
||||||
@@ -393,7 +393,7 @@ class NewsletterDeliveryTests(NewsletterFixture, unittest.IsolatedAsyncioTestCas
|
|||||||
self.assertEqual(draft['intro'], custom_intro)
|
self.assertEqual(draft['intro'], custom_intro)
|
||||||
|
|
||||||
def test_generic_email_template_preserves_custom_subject_and_intro(self):
|
def test_generic_email_template_preserves_custom_subject_and_intro(self):
|
||||||
custom_subject = 'Grizzlyflix weekend discoveries'
|
custom_subject = 'ExampleFlix weekend discoveries'
|
||||||
custom_intro = 'Welcome to our own <media> community.'
|
custom_intro = 'Welcome to our own <media> community.'
|
||||||
rendered = template.render(
|
rendered = template.render(
|
||||||
{**content(), 'subject': custom_subject, 'intro': custom_intro}, {},
|
{**content(), 'subject': custom_subject, 'intro': custom_intro}, {},
|
||||||
@@ -406,7 +406,7 @@ class NewsletterDeliveryTests(NewsletterFixture, unittest.IsolatedAsyncioTestCas
|
|||||||
self.assertIn('Welcome to our own <media> community.', rendered['body_html'])
|
self.assertIn('Welcome to our own <media> community.', rendered['body_html'])
|
||||||
self.assertIn('Watch on Jellyfin', rendered['body_html'])
|
self.assertIn('Watch on Jellyfin', rendered['body_html'])
|
||||||
self.assertIn('Explore Jellyfin', rendered['body_html'])
|
self.assertIn('Explore Jellyfin', rendered['body_html'])
|
||||||
self.assertNotIn('grizzlyflix', rendered['body_html'].lower())
|
self.assertNotIn('exampleflix', rendered['body_html'].lower())
|
||||||
|
|
||||||
async def test_weekly_worker_collects_once_and_delivers_to_confirmed_subscriber(self):
|
async def test_weekly_worker_collects_once_and_delivers_to_confirmed_subscriber(self):
|
||||||
now = datetime.now(timezone.utc)
|
now = datetime.now(timezone.utc)
|
||||||
|
|||||||
+4
-4
@@ -64,7 +64,7 @@ container in either case, not a native Windows-container or macOS application.
|
|||||||
### 1. Save the deployment file
|
### 1. Save the deployment file
|
||||||
|
|
||||||
Create a new directory for this installation and save the release branch's
|
Create a new directory for this installation and save the release branch's
|
||||||
[raw compose.yml](https://git.amslabs.net/Rephl3x/Magent/raw/branch/release/compose.yml)
|
[raw compose.yml](https://git.amslabs.net/Rephl3x/Magent-Public/raw/branch/release/compose.yml)
|
||||||
there. Keep your customized copy for future operations instead of overwriting
|
there. Keep your customized copy for future operations instead of overwriting
|
||||||
it when updating. You need only this file for the prebuilt image.
|
it when updating. You need only this file for the prebuilt image.
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@ Linux, macOS or WSL:
|
|||||||
```sh
|
```sh
|
||||||
mkdir magent-install
|
mkdir magent-install
|
||||||
cd magent-install
|
cd magent-install
|
||||||
curl --fail --location --output compose.yml https://git.amslabs.net/Rephl3x/Magent/raw/branch/release/compose.yml
|
curl --fail --location --output compose.yml https://git.amslabs.net/Rephl3x/Magent-Public/raw/branch/release/compose.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
PowerShell:
|
PowerShell:
|
||||||
@@ -81,7 +81,7 @@ PowerShell:
|
|||||||
```powershell
|
```powershell
|
||||||
New-Item -ItemType Directory -Path magent-install
|
New-Item -ItemType Directory -Path magent-install
|
||||||
Set-Location magent-install
|
Set-Location magent-install
|
||||||
Invoke-WebRequest -Uri 'https://git.amslabs.net/Rephl3x/Magent/raw/branch/release/compose.yml' -OutFile compose.yml
|
Invoke-WebRequest -Uri 'https://git.amslabs.net/Rephl3x/Magent-Public/raw/branch/release/compose.yml' -OutFile compose.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
Alternatively, open the raw link in your browser and save the plain text as
|
Alternatively, open the raw link in your browser and save the plain text as
|
||||||
@@ -236,7 +236,7 @@ It requires the full source tree and Docker build support; the prebuilt-image
|
|||||||
installation does not. Use a separate checkout directory:
|
installation does not. Use a separate checkout directory:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
git clone --branch release --single-branch https://git.amslabs.net/Rephl3x/Magent.git Magent-source
|
git clone --branch release --single-branch https://git.amslabs.net/Rephl3x/Magent-Public.git Magent-source
|
||||||
cd Magent-source
|
cd Magent-source
|
||||||
docker compose -f compose.yml -f compose.build.yml -p magent config --quiet
|
docker compose -f compose.yml -f compose.build.yml -p magent config --quiet
|
||||||
docker compose -f compose.yml -f compose.build.yml -p magent build magent
|
docker compose -f compose.yml -f compose.build.yml -p magent build magent
|
||||||
|
|||||||
@@ -238,6 +238,8 @@ consumer; builder values and supervisor values are not user-editable app setting
|
|||||||
| `PYTHONUNBUFFERED` | Image: `1` | Flush Python stdout/stderr without buffering. |
|
| `PYTHONUNBUFFERED` | Image: `1` | Flush Python stdout/stderr without buffering. |
|
||||||
| `MAGENT_UID` | Build argument: `1000` | Image runtime user's UID. Not a runtime environment switch; rebuilding with a different UID also requires matching volume/tmpfs ownership. |
|
| `MAGENT_UID` | Build argument: `1000` | Image runtime user's UID. Not a runtime environment switch; rebuilding with a different UID also requires matching volume/tmpfs ownership. |
|
||||||
| `MAGENT_GID` | Build argument: `1000` | Image runtime user's GID; same ownership caveat as UID. |
|
| `MAGENT_GID` | Build argument: `1000` | Image runtime user's GID; same ownership caveat as UID. |
|
||||||
|
| `MAGENT_VERSION` | Build argument: `0.1.0-preview.1` | OCI image version label. Release builds set this to their public version; it does not change runtime data. |
|
||||||
|
| `MAGENT_REVISION` | Build argument: `unknown` | OCI image source-revision label. Release builds set this to the full source commit. |
|
||||||
|
|
||||||
## Manual Compose and test tooling
|
## Manual Compose and test tooling
|
||||||
|
|
||||||
@@ -249,6 +251,8 @@ verification tools, not the zero-input public Compose install.
|
|||||||
| `MAGENT_IMAGE` | Required by `docker-compose.hub.yml` | Explicit published image tag/digest for manual-secret installations. |
|
| `MAGENT_IMAGE` | Required by `docker-compose.hub.yml` | Explicit published image tag/digest for manual-secret installations. |
|
||||||
| `MAGENT_BIND_ADDRESS` | `127.0.0.1` | Manual template frontend bind address. |
|
| `MAGENT_BIND_ADDRESS` | `127.0.0.1` | Manual template frontend bind address. |
|
||||||
| `MAGENT_HTTP_PORT` | `3000` | Manual template frontend host port. |
|
| `MAGENT_HTTP_PORT` | `3000` | Manual template frontend host port. |
|
||||||
|
| `MAGENT_COMPOSE_FILE` | `compose.yml` | Optional `setup.sh` Compose filename override. Use a trusted local file. |
|
||||||
|
| `MAGENT_PROJECT_NAME` | `magent` | Optional `setup.sh` Compose project name. Keep it stable to retain the same named volume. |
|
||||||
| `PYTHON_BIN` | `python3` | Interpreter used by the backend quality gate. |
|
| `PYTHON_BIN` | `python3` | Interpreter used by the backend quality gate. |
|
||||||
| `MAGENT_IMAGE_MAX_MB` | `350` | Container smoke-test unpacked image size budget in MiB. |
|
| `MAGENT_IMAGE_MAX_MB` | `350` | Container smoke-test unpacked image size budget in MiB. |
|
||||||
| `MAGENT_SMOKE_MANAGED` | `false` | Test generated managed secrets when true, or synthetic manual keys when false. |
|
| `MAGENT_SMOKE_MANAGED` | `false` | Test generated managed secrets when true, or synthetic manual keys when false. |
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ connect a development checkout to production credentials/databases.
|
|||||||
Linux/macOS (Bash/zsh):
|
Linux/macOS (Bash/zsh):
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
git clone --branch release --single-branch https://git.amslabs.net/Rephl3x/Magent.git magent
|
git clone --branch release --single-branch https://git.amslabs.net/Rephl3x/Magent-Public.git magent
|
||||||
cd magent
|
cd magent
|
||||||
python3.14 -m venv .venv
|
python3.14 -m venv .venv
|
||||||
.venv/bin/python -m pip install -r backend/requirements.txt
|
.venv/bin/python -m pip install -r backend/requirements.txt
|
||||||
@@ -24,7 +24,7 @@ python3.14 -m venv .venv
|
|||||||
Windows (PowerShell, with Python's `py` launcher installed):
|
Windows (PowerShell, with Python's `py` launcher installed):
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
git clone --branch release --single-branch https://git.amslabs.net/Rephl3x/Magent.git magent
|
git clone --branch release --single-branch https://git.amslabs.net/Rephl3x/Magent-Public.git magent
|
||||||
Set-Location magent
|
Set-Location magent
|
||||||
py -3.14 -m venv .venv
|
py -3.14 -m venv .venv
|
||||||
& .\.venv\Scripts\python.exe -m pip install -r backend\requirements.txt
|
& .\.venv\Scripts\python.exe -m pip install -r backend\requirements.txt
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ sudo useradd --system --user-group --create-home --home-dir /var/lib/magent --sh
|
|||||||
sudo install -d -o magent -g magent -m 0755 /opt/magent
|
sudo install -d -o magent -g magent -m 0755 /opt/magent
|
||||||
sudo install -d -o root -g root -m 0700 /etc/magent
|
sudo install -d -o root -g root -m 0700 /etc/magent
|
||||||
sudo install -d -o magent -g magent -m 0700 /var/lib/magent/data
|
sudo install -d -o magent -g magent -m 0700 /var/lib/magent/data
|
||||||
sudo -u magent git clone --branch release --single-branch https://git.amslabs.net/Rephl3x/Magent.git /opt/magent
|
sudo -u magent git clone --branch release --single-branch https://git.amslabs.net/Rephl3x/Magent-Public.git /opt/magent
|
||||||
sudo -u magent git -C /opt/magent rev-parse HEAD
|
sudo -u magent git -C /opt/magent rev-parse HEAD
|
||||||
sudo -u magent python3.14 -m venv /opt/magent/.venv
|
sudo -u magent python3.14 -m venv /opt/magent/.venv
|
||||||
sudo -u magent /opt/magent/.venv/bin/python -m pip install -r /opt/magent/backend/requirements.txt
|
sudo -u magent /opt/magent/.venv/bin/python -m pip install -r /opt/magent/backend/requirements.txt
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
# Reddit launch post
|
||||||
|
|
||||||
|
For `r/vibecoding`, use the **Vibe-Coded Projects** category/flair and retain the
|
||||||
|
build-process section below. The community's current self-promotion guidance says
|
||||||
|
project posts need educational detail about tools, workflow and lessons rather
|
||||||
|
than only a link. Recheck its rules immediately before posting. Add sanitized
|
||||||
|
screenshots if available; never show real users, domains, libraries, service URLs
|
||||||
|
or credentials.
|
||||||
|
|
||||||
|
## Suggested title
|
||||||
|
|
||||||
|
I vibe-coded Magent: a self-hosted request, stats and issue portal for Jellyfin stacks
|
||||||
|
|
||||||
|
## Alternative titles
|
||||||
|
|
||||||
|
- Magent is ready for testers — Docker, Portainer and native installs
|
||||||
|
- Sharing Magent: one place for media requests, viewing stats and issue follow-up
|
||||||
|
|
||||||
|
## Post
|
||||||
|
|
||||||
|
Hey everyone,
|
||||||
|
|
||||||
|
I’ve been vibe-coding a self-hosted project called **Magent**, and its first
|
||||||
|
public preview is ready for people to inspect, install and break:
|
||||||
|
|
||||||
|
https://git.amslabs.net/Rephl3x/Magent-Public
|
||||||
|
|
||||||
|
Magent is the user-facing layer I wanted around a Jellyfin media stack. It brings
|
||||||
|
requests, request progress, viewing stats and issue follow-up into one place,
|
||||||
|
while Jellyfin, Seerr, Sonarr, Radarr and the other connected apps keep doing the
|
||||||
|
jobs they already do.
|
||||||
|
|
||||||
|
What it currently includes:
|
||||||
|
|
||||||
|
- Search for and submit movie or TV requests through Seerr
|
||||||
|
- A plain-English request timeline across approval, Arr, downloads and Jellyfin
|
||||||
|
- “Watch now” links when something is available
|
||||||
|
- Issue reporting and repair follow-up
|
||||||
|
- Personal Jellystat viewing insights and monthly reports
|
||||||
|
- Local/Jellyfin sign-in, invitations and per-user feature controls
|
||||||
|
- Encrypted backup and restore for configuration and the SQLite database
|
||||||
|
|
||||||
|
It does **not** provide, store or stream media. You need to operate and connect
|
||||||
|
your own services.
|
||||||
|
|
||||||
|
Docker Compose is the recommended setup, but the repository also documents
|
||||||
|
Portainer, plain `docker run`, source-built containers, native Linux/systemd and
|
||||||
|
foreground Windows/macOS/Linux installs. A fresh managed Docker install creates
|
||||||
|
its own private keys and setup token, then walks you through the administrator
|
||||||
|
and app connections in the browser.
|
||||||
|
|
||||||
|
Docker image: https://hub.docker.com/r/rephl3xnz/magent
|
||||||
|
|
||||||
|
This is deliberately labelled a public preview. The container is currently
|
||||||
|
validated on Linux/amd64, Magent expects one writable SQLite instance, and it is
|
||||||
|
not presented as an HA/Kubernetes deployment. The repo documents HTTPS, reverse
|
||||||
|
proxies, origins/cookies, backups, upgrades and rollback rather than pretending
|
||||||
|
those details disappear.
|
||||||
|
|
||||||
|
The project grew through an iterative AI-assisted/vibe-coding workflow, followed
|
||||||
|
by regression tests, isolated container smoke tests and a separate sanitization
|
||||||
|
pass for the public repository. I’m sharing the source under MIT because I want
|
||||||
|
the implementation to be inspectable, not just the result.
|
||||||
|
|
||||||
|
### How I built it
|
||||||
|
|
||||||
|
My workflow was much closer to directing a small engineering loop than writing
|
||||||
|
one giant prompt. I described a user problem, had Codex work across the FastAPI,
|
||||||
|
Next.js and Docker layers, then reviewed the result in a running Beta instance.
|
||||||
|
Screenshots and real failure reports became the next round of requirements.
|
||||||
|
|
||||||
|
The useful discipline was making every vibe pass leave evidence behind. Backend
|
||||||
|
behavior got regression tests, interface changes got browser checks, and the
|
||||||
|
container got a disposable smoke harness covering fresh setup, login, security
|
||||||
|
headers, assets, encrypted backup/restore, restart and recreation. I also used
|
||||||
|
the ECC Codex plugin as a structured security/release review rather than treating
|
||||||
|
“it works on my stack” as a release gate.
|
||||||
|
|
||||||
|
The biggest release lesson was that a Git branch is not a privacy boundary. My
|
||||||
|
first idea was a sanitized public branch alongside private Beta/Prod branches.
|
||||||
|
Before launch I caught that every branch and old tag in a public repository is
|
||||||
|
still public, so I split the three-commit sanitized export into its own repository.
|
||||||
|
That was more valuable than another round of UI polish.
|
||||||
|
|
||||||
|
The most useful early feedback would be:
|
||||||
|
|
||||||
|
- where setup assumes too much knowledge
|
||||||
|
- installation steps that are unclear or wrong on your platform
|
||||||
|
- integrations that behave differently on another stack
|
||||||
|
- request, stats or issue flows that confuse real users
|
||||||
|
- backup or restore problems
|
||||||
|
|
||||||
|
Please use synthetic examples and sanitized logs in public reports—no tokens,
|
||||||
|
databases, backup files or private service details.
|
||||||
|
|
||||||
|
Repository: https://git.amslabs.net/Rephl3x/Magent-Public
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
@@ -16,7 +16,7 @@ describe("portable default branding", () => {
|
|||||||
expect(html).toContain("Welcome to our library");
|
expect(html).toContain("Welcome to our library");
|
||||||
expect(html).toContain("A custom message");
|
expect(html).toContain("A custom message");
|
||||||
expect(html).toContain("Local help");
|
expect(html).toContain("Local help");
|
||||||
expect(html).not.toMatch(/grizzlyflix/i);
|
expect(html).not.toMatch(/exampleflix/i);
|
||||||
expect(html).not.toContain(">Beta<");
|
expect(html).not.toContain(">Beta<");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -25,13 +25,13 @@ describe("portable default branding", () => {
|
|||||||
|
|
||||||
expect(html).toContain("MAGENT");
|
expect(html).toContain("MAGENT");
|
||||||
expect(html).toContain("Your media member portal");
|
expect(html).toContain("Your media member portal");
|
||||||
expect(html).not.toMatch(/grizzlyflix/i);
|
expect(html).not.toMatch(/exampleflix/i);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("explains the Jellyfin integration without a deployment-specific service name", () => {
|
it("explains the Jellyfin integration without a deployment-specific service name", () => {
|
||||||
const html = renderToStaticMarkup(<HowItWorksPage />);
|
const html = renderToStaticMarkup(<HowItWorksPage />);
|
||||||
|
|
||||||
expect(html).toContain("Jellyfin is where you watch them.");
|
expect(html).toContain("Jellyfin is where you watch them.");
|
||||||
expect(html).not.toMatch(/grizzlyflix/i);
|
expect(html).not.toMatch(/exampleflix/i);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "magent-frontend",
|
"name": "magent-frontend",
|
||||||
"version": "0803262237",
|
"version": "0.1.0-preview.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "magent-frontend",
|
"name": "magent-frontend",
|
||||||
"version": "0803262237",
|
"version": "0.1.0-preview.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"next": "16.3.5",
|
"next": "16.3.5",
|
||||||
"react": "19.2.4",
|
"react": "19.2.4",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "magent-frontend",
|
"name": "magent-frontend",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0803262237",
|
"version": "0.1.0-preview.1",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
compose_file="${MAGENT_COMPOSE_FILE:-compose.yml}"
|
||||||
|
project_name="${MAGENT_PROJECT_NAME:-magent}"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "Usage: ./setup.sh check|install|status|token|logs"
|
||||||
|
echo "Run this script from a directory containing the public compose.yml."
|
||||||
|
}
|
||||||
|
|
||||||
|
compose() {
|
||||||
|
docker compose -f "$compose_file" -p "$project_name" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
case "${1:-}" in
|
||||||
|
check)
|
||||||
|
docker version >/dev/null
|
||||||
|
docker compose version >/dev/null
|
||||||
|
compose config --quiet
|
||||||
|
echo "Docker and compose.yml are ready."
|
||||||
|
;;
|
||||||
|
install)
|
||||||
|
compose config --quiet
|
||||||
|
compose pull
|
||||||
|
compose up -d --wait --wait-timeout 120
|
||||||
|
compose ps
|
||||||
|
echo "Open http://SERVER_IP:3000/setup, then run: ./setup.sh token"
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
compose ps
|
||||||
|
;;
|
||||||
|
token)
|
||||||
|
compose exec --user magent magent python -m app.container_bootstrap setup-token
|
||||||
|
;;
|
||||||
|
logs)
|
||||||
|
compose logs --tail=150 magent
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
usage
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
Reference in New Issue
Block a user