chore: standardize security and quality foundations
Magent CI/CD / verify (push) Failing after 9m34s
Magent CI/CD / deploy-beta (push) Skipped

This commit is contained in:
2026-09-17 20:03:47 +12:00
parent 5639dbcb83
commit f852e7c941
127 changed files with 17928 additions and 10741 deletions
+92 -115
View File
@@ -1,106 +1,106 @@
'use client'
"use client";
import { useEffect, useState } from 'react'
import { useRouter } from 'next/navigation'
import AdminShell from '../../ui/AdminShell'
import { authFetch, clearToken, getApiBase, getToken } from '../../lib/auth'
import { useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import AdminShell from "../../ui/AdminShell";
import { authFetch, clearToken, getApiBase, getToken } from "../../lib/auth";
type FlowStage = {
title: string
input: string
action: string
output: string
}
title: string;
input: string;
action: string;
output: string;
};
const REQUEST_FLOW: FlowStage[] = [
{
title: 'Identity + access',
input: 'Jellyfin/local login',
action: 'Magent validates credentials and role',
output: 'JWT token + user scope',
title: "Identity + access",
input: "Jellyfin/local login",
action: "Magent validates credentials and role",
output: "JWT token + user scope",
},
{
title: 'Request intake',
input: 'Seerr request ID',
action: 'Magent snapshots request + media metadata',
output: 'Unified request state',
title: "Request intake",
input: "Seerr request ID",
action: "Magent snapshots request + media metadata",
output: "Unified request state",
},
{
title: 'Queue orchestration',
input: 'Approved request',
action: 'Sonarr/Radarr add/search operations',
output: 'Grab decision',
title: "Queue orchestration",
input: "Approved request",
action: "Sonarr/Radarr add/search operations",
output: "Grab decision",
},
{
title: 'Download execution',
input: 'Selected release',
action: 'qBittorrent downloads + reports progress',
output: 'Import-ready payload',
title: "Download execution",
input: "Selected release",
action: "qBittorrent downloads + reports progress",
output: "Import-ready payload",
},
{
title: 'Library import',
input: 'Completed download',
action: 'Sonarr/Radarr import and finalize',
output: 'Available media object',
title: "Library import",
input: "Completed download",
action: "Sonarr/Radarr import and finalize",
output: "Available media object",
},
{
title: 'Playback availability',
input: 'Imported media',
action: 'Jellyfin refresh + link resolution',
output: 'Ready-to-watch state',
title: "Playback availability",
input: "Imported media",
action: "Jellyfin refresh + link resolution",
output: "Ready-to-watch state",
},
]
];
export default function AdminSystemGuidePage() {
const router = useRouter()
const [loading, setLoading] = useState(true)
const [authorized, setAuthorized] = useState(false)
const router = useRouter();
const [loading, setLoading] = useState(true);
const [authorized, setAuthorized] = useState(false);
useEffect(() => {
let active = true
let active = true;
const load = async () => {
if (!getToken()) {
router.push('/login')
return
router.push("/login");
return;
}
try {
const baseUrl = getApiBase()
const response = await authFetch(`${baseUrl}/auth/me`)
const baseUrl = getApiBase();
const response = await authFetch(`${baseUrl}/auth/me`);
if (!response.ok) {
if (response.status === 401) {
clearToken()
router.push('/login')
return
clearToken();
router.push("/login");
return;
}
router.push('/')
return
router.push("/");
return;
}
const me = await response.json()
if (!active) return
if (me?.role !== 'admin') {
router.push('/')
return
const me = await response.json();
if (!active) return;
if (me?.role !== "admin") {
router.push("/");
return;
}
setAuthorized(true)
setAuthorized(true);
} catch (error) {
console.error(error)
router.push('/')
console.error(error);
router.push("/");
} finally {
if (active) setLoading(false)
if (active) setLoading(false);
}
}
void load()
};
void load();
return () => {
active = false
}
}, [router])
active = false;
};
}, [router]);
if (loading) {
return <main className="card">Loading system guide...</main>
return <main className="card">Loading system guide...</main>;
}
if (!authorized) {
return null
return null;
}
const rail = (
@@ -112,26 +112,23 @@ export default function AdminSystemGuidePage() {
<span className="small-pill">Admin only</span>
</div>
</div>
)
);
return (
<AdminShell
title="System guide"
subtitle="Service connections, controls, and recovery paths."
rail={rail}
>
<AdminShell title="System guide" subtitle="Service connections, controls, and recovery paths." rail={rail}>
<section className="admin-section system-guide">
<div className="admin-panel">
<h2>End-to-end system flow</h2>
<p className="lede">
This is the runtime path the platform follows from authentication through to playback
availability.
This is the runtime path the platform follows from authentication through to playback availability.
</p>
<div className="system-flow-track">
{REQUEST_FLOW.map((stage, index) => (
<div key={stage.title} className="system-flow-segment">
<article className="system-flow-card">
<div className="system-flow-card-title">{index + 1}. {stage.title}</div>
<div className="system-flow-card-title">
{index + 1}. {stage.title}
</div>
<div className="system-flow-card-row">
<span>Input</span>
<strong>{stage.input}</strong>
@@ -145,7 +142,11 @@ export default function AdminSystemGuidePage() {
<strong>{stage.output}</strong>
</div>
</article>
{index < REQUEST_FLOW.length - 1 && <div className="system-flow-arrow" aria-hidden="true"></div>}
{index < REQUEST_FLOW.length - 1 && (
<div className="system-flow-arrow" aria-hidden="true">
</div>
)}
</div>
))}
</div>
@@ -157,30 +158,23 @@ export default function AdminSystemGuidePage() {
<article className="system-guide-card">
<h3>Magent</h3>
<p>
Handles authentication, request pages, live event updates, invite workflows,
diagnostics, notifications, and admin operations.
Handles authentication, request pages, live event updates, invite workflows, diagnostics, notifications,
and admin operations.
</p>
</article>
<article className="system-guide-card">
<h3>Seerr</h3>
<p>
Stores the request itself and remains the request-state source for approval and
media request metadata.
Stores the request itself and remains the request-state source for approval and media request metadata.
</p>
</article>
<article className="system-guide-card">
<h3>Jellyfin</h3>
<p>
Provides user sign-in identity and the final playback destination once content is
available.
</p>
<p>Provides user sign-in identity and the final playback destination once content is available.</p>
</article>
<article className="system-guide-card">
<h3>Sonarr / Radarr</h3>
<p>
Control queue placement, quality-profile decisions, import handling, and release
monitoring.
</p>
<p>Control queue placement, quality-profile decisions, import handling, and release monitoring.</p>
</article>
<article className="system-guide-card">
<h3>Prowlarr</h3>
@@ -188,10 +182,7 @@ export default function AdminSystemGuidePage() {
</article>
<article className="system-guide-card">
<h3>qBittorrent</h3>
<p>
Executes the download and exposes live progress, paused states, and queue
visibility.
</p>
<p>Executes the download and exposes live progress, paused states, and queue visibility.</p>
</article>
</div>
</div>
@@ -213,10 +204,7 @@ export default function AdminSystemGuidePage() {
</article>
<article className="system-guide-card">
<h3>Invite management</h3>
<p>
Master template, profile assignment, invite access policy, invite emails, and trace
map lineage.
</p>
<p>Master template, profile assignment, invite access policy, invite emails, and trace map lineage.</p>
</article>
<article className="system-guide-card">
<h3>Requests + cache</h3>
@@ -225,8 +213,8 @@ export default function AdminSystemGuidePage() {
<article className="system-guide-card">
<h3>Maintenance + diagnostics</h3>
<p>
Connectivity checks, live diagnostics, database repair, cleanup, log review, and
nuclear flush/resync operations.
Connectivity checks, live diagnostics, database repair, cleanup, log review, and nuclear flush/resync
operations.
</p>
</article>
</div>
@@ -235,23 +223,11 @@ export default function AdminSystemGuidePage() {
<div className="admin-panel">
<h2>User and invite model</h2>
<ol className="system-decision-list">
<li>
Jellyfin is used for sign-in identity and user presence across the platform.
</li>
<li>
Seerr provides request ownership and request-state data for Magent request pages.
</li>
<li>
Invite links, invite profiles, blanket rules, and invite-access controls are managed
inside Magent.
</li>
<li>
If invite tracing is enabled, the lineage view shows who invited whom and how the
chain branches.
</li>
<li>
Cross-system removal and ban flows are initiated from Magent admin controls.
</li>
<li>Jellyfin is used for sign-in identity and user presence across the platform.</li>
<li>Seerr provides request ownership and request-state data for Magent request pages.</li>
<li>Invite links, invite profiles, blanket rules, and invite-access controls are managed inside Magent.</li>
<li>If invite tracing is enabled, the lineage view shows who invited whom and how the chain branches.</li>
<li>Cross-system removal and ban flows are initiated from Magent admin controls.</li>
</ol>
</div>
@@ -265,7 +241,8 @@ export default function AdminSystemGuidePage() {
In queue but no release found <span></span> run <strong>Search releases</strong> and inspect options.
</li>
<li>
Release exists and user should not pick manually <span></span> run <strong>Search + auto-download</strong>.
Release exists and user should not pick manually <span></span> run{" "}
<strong>Search + auto-download</strong>.
</li>
<li>
Download paused/stalled in qBittorrent <span></span> run <strong>Resume download</strong>.
@@ -295,5 +272,5 @@ export default function AdminSystemGuidePage() {
</div>
</section>
</AdminShell>
)
);
}