feat: homelab deployment - NPM + IONOS DNS + monitoring + NAS backup

- Restructured docker-compose for Nginx Proxy Manager (no custom nginx)
- Added domain wordly.art configuration
- Added Prometheus + Grafana monitoring stack with pre-configured dashboards
- Added PostgreSQL backup script to NAS (daily/weekly/monthly rotation)
- Added alert rules for backend, system, and Docker metrics
- Updated deployment guide for NPM + IONOS DNS homelab setup
- Added marketing plan document
- PDF translator and watermark support
- Enhanced middleware, routes, and translator modules

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-10 11:43:28 +02:00
parent 16ac7ca2b9
commit ce8e150a61
110 changed files with 6935 additions and 4301 deletions

View File

@@ -455,7 +455,7 @@ export default function AdminSettingsPage() {
) : (
<RefreshCw className="size-3" />
)}
<span className="ml-1">Récupérer les modèles</span>
<span className="ms-1">Récupérer les modèles</span>
</Button>
</div>
{ollamaModels.length > 0 ? (
@@ -471,7 +471,7 @@ export default function AdminSettingsPage() {
<SelectItem key={model.name} value={model.name}>
{model.name}
{model.size > 0 && (
<span className="ml-2 text-xs text-muted-foreground">
<span className="ms-2 text-xs text-muted-foreground">
({(model.size / 1e9).toFixed(1)} GB)
</span>
)}
@@ -660,13 +660,13 @@ export default function AdminSettingsPage() {
className="h-8"
>
{testResults.smtp === "testing" ? (
<><Loader2 className="size-3 animate-spin mr-1" />Test...</>
<><Loader2 className="size-3 animate-spin me-1" />Test...</>
) : testResults.smtp === "ok" ? (
<><CheckCircle className="size-3 text-green-500 mr-1" />OK</>
<><CheckCircle className="size-3 text-green-500 me-1" />OK</>
) : testResults.smtp === "error" ? (
<><XCircle className="size-3 text-red-500 mr-1" />Erreur</>
<><XCircle className="size-3 text-red-500 me-1" />Erreur</>
) : (
<><FlaskConical className="size-3 mr-1" />Tester</>
<><FlaskConical className="size-3 me-1" />Tester</>
)}
</Button>
<Switch checked={config.smtp.enabled} onCheckedChange={(enabled) => updateSmtp({ enabled })} />
@@ -752,13 +752,13 @@ export default function AdminSettingsPage() {
className="h-8"
>
{isSendingTestEmail ? (
<><Loader2 className="size-3 animate-spin mr-1" />Envoi...</>
<><Loader2 className="size-3 animate-spin me-1" />Envoi...</>
) : testEmailResult === "ok" ? (
<><CheckCircle className="size-3 text-green-500 mr-1" />Envoyé</>
<><CheckCircle className="size-3 text-green-500 me-1" />Envoyé</>
) : testEmailResult === "error" ? (
<><XCircle className="size-3 text-red-500 mr-1" />Échec</>
<><XCircle className="size-3 text-red-500 me-1" />Échec</>
) : (
<><Mail className="size-3 mr-1" />Envoyer un email de test</>
<><Mail className="size-3 me-1" />Envoyer un email de test</>
)}
</Button>
{testEmailMessage && (
@@ -775,12 +775,12 @@ export default function AdminSettingsPage() {
<Button onClick={saveConfig} disabled={isSaving} size="lg">
{isSaving ? (
<>
<Loader2 className="mr-2 size-4 animate-spin" />
<Loader2 className="me-2 size-4 animate-spin" />
Sauvegarde...
</>
) : (
<>
<Save className="mr-2 size-4" />
<Save className="me-2 size-4" />
Sauvegarder la configuration
</>
)}
@@ -838,13 +838,13 @@ function ProviderCard({
className="h-8"
>
{testResult === "testing" ? (
<><Loader2 className="size-3 animate-spin mr-1" />Test...</>
<><Loader2 className="size-3 animate-spin me-1" />Test...</>
) : testResult === "ok" ? (
<><CheckCircle className="size-3 text-green-500 mr-1" />OK</>
<><CheckCircle className="size-3 text-green-500 me-1" />OK</>
) : testResult === "error" ? (
<><XCircle className="size-3 text-red-500 mr-1" />Erreur</>
<><XCircle className="size-3 text-red-500 me-1" />Erreur</>
) : (
<><FlaskConical className="size-3 mr-1" />Tester</>
<><FlaskConical className="size-3 me-1" />Tester</>
)}
</Button>
<Switch checked={enabled} onCheckedChange={onToggle} />