Convert wiki-link titles to lowercase slugs

- Convert all frontmatter titles to lowercase-hyphenated format
- Update all wiki-links to use the new slug format
- Update doc-titles task to validate slug format (lowercase, hyphens only)

Quartz appears to require titles without spaces for wiki-link resolution.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Erich Blume 2026-02-03 16:02:03 -08:00
commit fb5684929b
36 changed files with 288 additions and 248 deletions

View file

@ -1,6 +1,5 @@
---
title: README
---
title: readme---
# BlumeOps Documentation

View file

@ -0,0 +1 @@
Convert wiki-link titles to lowercase slugs for reliable Quartz resolution

View file

@ -1,11 +1,10 @@
---
title: BlumeOps Documentation
---
title: blumeops-documentation---
Welcome to the BlumeOps documentation.
[[README|Documentation Home]] - Temporary home while docs are being restructured (see [Diataxis](https://diataxis.fr/) restructuring plan)
[[readme|Documentation Home]] - Temporary home while docs are being restructured (see [Diataxis](https://diataxis.fr/) restructuring plan)
## Sections
- [[Reference]] - Technical reference cards for services, infrastructure, and operations
- [[reference]] - Technical reference cards for services, infrastructure, and operations

View file

@ -1,5 +1,5 @@
---
title: Reference
title: reference
tags:
- reference
---
@ -14,54 +14,54 @@ Individual service reference cards with URLs and configuration details.
| Service | Description | Location |
|---------|-------------|----------|
| [[Grafana Alloy|Alloy]] | Observability collector (metrics & logs) | indri + k8s |
| [[ArgoCD]] | GitOps continuous delivery | k8s |
| [[Borgmatic]] | Backup system | indri |
| [[1Password]] | Secrets management | cloud + k8s |
| [[Forgejo]] | Git forge & CI/CD | indri |
| [[Grafana]] | Dashboards & visualization | k8s |
| [[Immich]] | Photo management | k8s |
| [[Jellyfin]] | Media server | indri |
| [[Kiwix]] | Offline Wikipedia & ZIM archives | k8s |
| [[Loki]] | Log aggregation | k8s |
| [[Miniflux]] | RSS feed reader | k8s |
| [[Navidrome]] | Music streaming | k8s |
| [[PostgreSQL]] | Database cluster | k8s |
| [[Prometheus]] | Metrics collection | k8s |
| [[TeslaMate]] | Tesla data logger | k8s |
| [[Transmission]] | BitTorrent daemon | k8s |
| [[Zot]] | Container registry | indri |
| [[grafana-alloy|Alloy]] | Observability collector (metrics & logs) | indri + k8s |
| [[argocd]] | GitOps continuous delivery | k8s |
| [[borgmatic]] | Backup system | indri |
| [[1password]] | Secrets management | cloud + k8s |
| [[forgejo]] | Git forge & CI/CD | indri |
| [[grafana]] | Dashboards & visualization | k8s |
| [[immich]] | Photo management | k8s |
| [[jellyfin]] | Media server | indri |
| [[kiwix]] | Offline Wikipedia & ZIM archives | k8s |
| [[loki]] | Log aggregation | k8s |
| [[miniflux]] | RSS feed reader | k8s |
| [[navidrome]] | Music streaming | k8s |
| [[postgresql]] | Database cluster | k8s |
| [[prometheus]] | Metrics collection | k8s |
| [[teslamate]] | Tesla data logger | k8s |
| [[transmission]] | BitTorrent daemon | k8s |
| [[zot]] | Container registry | indri |
## Infrastructure
Host inventory and network configuration.
- [[Host Inventory|Hosts]] - Device inventory
- [[Indri]] - Primary server
- [[Gilbert]] - Development workstation
- [[Tailscale]] - ACLs, groups, tags
- [[Service Routing|Routing]] - DNS domains, port mappings
- [[host-inventory|Hosts]] - Device inventory
- [[indri]] - Primary server
- [[gilbert]] - Development workstation
- [[tailscale]] - ACLs, groups, tags
- [[service-routing|Routing]] - DNS domains, port mappings
## Kubernetes
Cluster configuration and application registry.
- [[Kubernetes Cluster|Cluster]] - Minikube specs, storage, networking
- [[ArgoCD Applications|Apps]] - ArgoCD application registry
- [[External Secrets]] - Secrets management
- [[kubernetes-cluster|Cluster]] - Minikube specs, storage, networking
- [[argocd-applications|Apps]] - ArgoCD application registry
- [[external-secrets]] - Secrets management
## Storage
Network storage and backup configuration.
- [[Sifaka NAS|Sifaka]] - Synology NAS configuration
- [[PostgreSQL Storage]] - Database cluster
- [[Backup Policy|Backups]] - Backup policy and schedule
- [[sifaka-nas|Sifaka]] - Synology NAS configuration
- [[postgresql-storage]] - Database cluster
- [[backup-policy|Backups]] - Backup policy and schedule
## Operations
Operational concerns and their components.
- [[Observability]] - Metrics, logs, dashboards
- [[Backup]] - Data protection
- [[Disaster Recovery]] - Recovery procedures (TBD)
- [[observability]] - Metrics, logs, dashboards
- [[backup]] - Data protection
- [[disaster-recovery]] - Recovery procedures (TBD)

View file

@ -1,5 +1,5 @@
---
title: Gilbert
title: gilbert
tags:
- infrastructure
- host
@ -23,5 +23,5 @@ Managed via `Brewfile` and `mise.toml` in the blumeops repo.
## Related
- [[Indri]] - Server accessed from gilbert
- [[Kubernetes Cluster|Cluster]] - Remote k8s access
- [[indri]] - Server accessed from gilbert
- [[kubernetes-cluster|Cluster]] - Remote k8s access

View file

@ -1,5 +1,5 @@
---
title: Host Inventory
title: host-inventory
tags:
- infrastructure
---
@ -12,14 +12,14 @@ All devices connected via [Tailscale](https://login.tailscale.com/) tailnet `tai
| Host | Description | Card |
|------|-------------|------|
| **Indri** | Mac Mini M1, 2020 - Primary server | [[Indri|Details]] |
| **Gilbert** | MacBook Air M4, 2025 - Workstation | [[Gilbert|Details]] |
| **[[Sifaka NAS|Sifaka]]** | Synology NAS - Storage & backups | [[Sifaka NAS|Details]] |
| **Indri** | Mac Mini M1, 2020 - Primary server | [[indri|Details]] |
| **Gilbert** | MacBook Air M4, 2025 - Workstation | [[gilbert|Details]] |
| **[[sifaka-nas|Sifaka]]** | Synology NAS - Storage & backups | [[sifaka-nas|Details]] |
| **Mouse** | MacBook Air M2 - Allison's laptop | - |
| **UniFi** | UniFi Express 7 - Home WiFi | - |
| **Dwarf** | iPad Air - Employer-provided, off tailnet | - |
## Related
- [[Tailscale]] - Network configuration
- [[Service Routing|Routing]] - Service URLs
- [[tailscale]] - Network configuration
- [[service-routing|Routing]] - Service URLs

View file

@ -1,5 +1,5 @@
---
title: Indri
title: indri
tags:
- infrastructure
- host
@ -22,17 +22,17 @@ Primary BlumeOps server. Mac Mini M1 (2020).
## Services Hosted
**Native (via Ansible):**
- [[Forgejo]] - Git forge
- [[Zot]] - Container registry
- [[Jellyfin]] - Media server
- [[Borgmatic]] - Backup system
- [[Grafana Alloy|Alloy]] - Metrics/logs collector
- [[forgejo]] - Git forge
- [[zot]] - Container registry
- [[jellyfin]] - Media server
- [[borgmatic]] - Backup system
- [[grafana-alloy|Alloy]] - Metrics/logs collector
- Caddy - Reverse proxy for `*.ops.eblu.me`
**Kubernetes (via minikube):**
- [[ArgoCD Applications|All k8s applications]]
- [[argocd-applications|All k8s applications]]
## Related
- [[Service Routing|Routing]] - Port mappings
- [[Kubernetes Cluster|Cluster]] - Minikube details
- [[service-routing|Routing]] - Port mappings
- [[kubernetes-cluster|Cluster]] - Minikube details

View file

@ -1,5 +1,5 @@
---
title: Service Routing
title: service-routing
tags:
- infrastructure
- network
@ -25,20 +25,20 @@ DNS points to indri's Tailscale IP (100.98.163.89). TLS via Let's Encrypt (ACME
| Service | URL | Description |
|---------|-----|-------------|
| Homepage | https://go.ops.eblu.me | Service dashboard |
| [[Forgejo]] | https://forge.ops.eblu.me | Git hosting (SSH: 2222) |
| [[Zot]] | https://registry.ops.eblu.me | Container registry |
| [[Grafana]] | https://grafana.ops.eblu.me | Dashboards |
| [[ArgoCD]] | https://argocd.ops.eblu.me | GitOps CD |
| [[Prometheus]] | https://prometheus.ops.eblu.me | Metrics |
| [[Loki]] | https://loki.ops.eblu.me | Logs |
| [[Miniflux]] | https://feed.ops.eblu.me | RSS reader |
| [[Kiwix]] | https://kiwix.ops.eblu.me | Offline Wikipedia |
| [[Transmission]] | https://torrent.ops.eblu.me | BitTorrent |
| [[TeslaMate]] | https://tesla.ops.eblu.me | Tesla logger |
| [[Navidrome]] | https://dj.ops.eblu.me | Music streaming |
| [[Jellyfin]] | https://jellyfin.ops.eblu.me | Media server |
| [[PostgreSQL]] | pg.ops.eblu.me:5432 | Database |
| [[Sifaka NAS|Sifaka]] | https://nas.ops.eblu.me | NAS dashboard |
| [[forgejo]] | https://forge.ops.eblu.me | Git hosting (SSH: 2222) |
| [[zot]] | https://registry.ops.eblu.me | Container registry |
| [[grafana]] | https://grafana.ops.eblu.me | Dashboards |
| [[argocd]] | https://argocd.ops.eblu.me | GitOps CD |
| [[prometheus]] | https://prometheus.ops.eblu.me | Metrics |
| [[loki]] | https://loki.ops.eblu.me | Logs |
| [[miniflux]] | https://feed.ops.eblu.me | RSS reader |
| [[kiwix]] | https://kiwix.ops.eblu.me | Offline Wikipedia |
| [[transmission]] | https://torrent.ops.eblu.me | BitTorrent |
| [[teslamate]] | https://tesla.ops.eblu.me | Tesla logger |
| [[navidrome]] | https://dj.ops.eblu.me | Music streaming |
| [[jellyfin]] | https://jellyfin.ops.eblu.me | Media server |
| [[postgresql]] | pg.ops.eblu.me:5432 | Database |
| [[sifaka-nas|Sifaka]] | https://nas.ops.eblu.me | NAS dashboard |
## Tailscale-Only Services
@ -61,5 +61,5 @@ DNS points to indri's Tailscale IP (100.98.163.89). TLS via Let's Encrypt (ACME
## Related
- [[Tailscale]] - ACL configuration
- [[Indri]] - Where services run
- [[tailscale]] - ACL configuration
- [[indri]] - Where services run

View file

@ -1,5 +1,5 @@
---
title: Tailscale
title: tailscale
tags:
- infrastructure
- network
@ -17,7 +17,7 @@ ACLs managed via Pulumi in `pulumi/policy.hujson`.
| Group | Members | Purpose |
|-------|---------|---------|
| `group:allisonflix` | admin, member | [[Jellyfin]] media access |
| `group:allisonflix` | admin, member | [[jellyfin]] media access |
## Device Tags
@ -58,5 +58,5 @@ Pulumi uses OAuth client from 1Password (blumeops vault):
## Related
- [[Service Routing|Routing]] - Service URLs
- [[Host Inventory|Hosts]] - Device inventory
- [[service-routing|Routing]] - Service URLs
- [[host-inventory|Hosts]] - Device inventory

View file

@ -1,5 +1,5 @@
---
title: ArgoCD Applications
title: argocd-applications
tags:
- kubernetes
- argocd
@ -7,33 +7,33 @@ tags:
# ArgoCD Applications
Registry of all applications deployed via [[ArgoCD]].
Registry of all applications deployed via [[argocd]].
## Application Registry
| App | Namespace | Path/Source | Service |
|-----|-----------|-------------|---------|
| `apps` | argocd | `argocd/apps/` | App-of-apps root |
| `argocd` | argocd | `argocd/manifests/argocd/` | [[ArgoCD]] |
| `argocd` | argocd | `argocd/manifests/argocd/` | [[argocd]] |
| `tailscale-operator` | tailscale | `argocd/manifests/tailscale-operator/` | Tailscale k8s operator |
| `1password-connect` | 1password | `argocd/manifests/1password-connect/` | [[1Password]] |
| `external-secrets` | external-secrets | Helm chart | [[1Password]] |
| `external-secrets-config` | external-secrets | `argocd/manifests/external-secrets-config/` | [[1Password]] |
| `1password-connect` | 1password | `argocd/manifests/1password-connect/` | [[1password]] |
| `external-secrets` | external-secrets | Helm chart | [[1password]] |
| `external-secrets-config` | external-secrets | `argocd/manifests/external-secrets-config/` | [[1password]] |
| `cloudnative-pg` | cnpg-system | Helm chart (forge mirror) | PostgreSQL operator |
| `blumeops-pg` | databases | `argocd/manifests/databases/` | [[PostgreSQL]] |
| `prometheus` | monitoring | `argocd/manifests/prometheus/` | [[Prometheus]] |
| `loki` | monitoring | `argocd/manifests/loki/` | [[Loki]] |
| `grafana` | monitoring | Helm chart (forge mirror) | [[Grafana]] |
| `grafana-config` | monitoring | `argocd/manifests/grafana-config/` | [[Grafana]] |
| `immich` | immich | Helm chart | [[Immich]] |
| `alloy-k8s` | alloy | `argocd/manifests/alloy-k8s/` | [[Grafana Alloy|Alloy]] |
| `blumeops-pg` | databases | `argocd/manifests/databases/` | [[postgresql]] |
| `prometheus` | monitoring | `argocd/manifests/prometheus/` | [[prometheus]] |
| `loki` | monitoring | `argocd/manifests/loki/` | [[loki]] |
| `grafana` | monitoring | Helm chart (forge mirror) | [[grafana]] |
| `grafana-config` | monitoring | `argocd/manifests/grafana-config/` | [[grafana]] |
| `immich` | immich | Helm chart | [[immich]] |
| `alloy-k8s` | alloy | `argocd/manifests/alloy-k8s/` | [[grafana-alloy|Alloy]] |
| `kube-state-metrics` | monitoring | `argocd/manifests/kube-state-metrics/` | K8s metrics |
| `miniflux` | miniflux | `argocd/manifests/miniflux/` | [[Miniflux]] |
| `kiwix` | kiwix | `argocd/manifests/kiwix/` | [[Kiwix]] |
| `torrent` | torrent | `argocd/manifests/torrent/` | [[Transmission]] |
| `navidrome` | navidrome | `argocd/manifests/navidrome/` | [[Navidrome]] |
| `teslamate` | teslamate | `argocd/manifests/teslamate/` | [[TeslaMate]] |
| `forgejo-runner` | forgejo-runner | `argocd/manifests/forgejo-runner/` | [[Forgejo]] CI |
| `miniflux` | miniflux | `argocd/manifests/miniflux/` | [[miniflux]] |
| `kiwix` | kiwix | `argocd/manifests/kiwix/` | [[kiwix]] |
| `torrent` | torrent | `argocd/manifests/torrent/` | [[transmission]] |
| `navidrome` | navidrome | `argocd/manifests/navidrome/` | [[navidrome]] |
| `teslamate` | teslamate | `argocd/manifests/teslamate/` | [[teslamate]] |
| `forgejo-runner` | forgejo-runner | `argocd/manifests/forgejo-runner/` | [[forgejo]] CI |
## Sync Policies
@ -44,5 +44,5 @@ Registry of all applications deployed via [[ArgoCD]].
## Related
- [[ArgoCD]] - GitOps platform details
- [[Kubernetes Cluster|Cluster]] - Kubernetes infrastructure
- [[argocd]] - GitOps platform details
- [[kubernetes-cluster|Cluster]] - Kubernetes infrastructure

View file

@ -1,12 +1,12 @@
---
title: Kubernetes Cluster
title: kubernetes-cluster
tags:
- kubernetes
---
# Kubernetes Cluster
Single-node Minikube cluster running on [[Indri]].
Single-node Minikube cluster running on [[indri]].
## Cluster Specifications
@ -24,16 +24,16 @@ Single-node Minikube cluster running on [[Indri]].
## Volume Mounting
Pods mount NFS directly from [[Sifaka NAS|Sifaka]]. Docker NATs outbound traffic through indri's LAN IP (192.168.1.50), allowing access to Sifaka's NFS exports.
Pods mount NFS directly from [[sifaka-nas|Sifaka]]. Docker NATs outbound traffic through indri's LAN IP (192.168.1.50), allowing access to Sifaka's NFS exports.
## Registry Mirror
Containerd uses [[Zot]] as a pull-through cache at `host.minikube.internal:5050`.
Containerd uses [[zot]] as a pull-through cache at `host.minikube.internal:5050`.
Mirrors configured: `registry.ops.eblu.me`, `docker.io`, `ghcr.io`, `quay.io`
## Related
- [[ArgoCD Applications|Apps]] - ArgoCD applications
- [[ArgoCD]] - GitOps deployment
- [[Zot]] - Registry mirror
- [[argocd-applications|Apps]] - ArgoCD applications
- [[argocd]] - GitOps deployment
- [[zot]] - Registry mirror

View file

@ -1,5 +1,5 @@
---
title: External Secrets
title: external-secrets
tags:
- kubernetes
- secrets
@ -7,4 +7,4 @@ tags:
# External Secrets
See [[1Password]] in Services.
See [[1password]] in Services.

View file

@ -1,5 +1,5 @@
---
title: Backup
title: backup
tags:
- operations
---
@ -10,6 +10,6 @@ Daily automated backups of BlumeOps data.
## Components
- [[Borgmatic]] - Backup orchestration
- [[Sifaka NAS|Sifaka]] - Backup target (NAS)
- [[Backup Policy]] - What gets backed up and retention
- [[borgmatic]] - Backup orchestration
- [[sifaka-nas|Sifaka]] - Backup target (NAS)
- [[backup-policy]] - What gets backed up and retention

View file

@ -1,5 +1,5 @@
---
title: Disaster Recovery
title: disaster-recovery
tags:
- operations
---
@ -8,12 +8,12 @@ tags:
TBD. Current state:
- [[Borgmatic]] provides daily backups to [[Sifaka NAS|Sifaka]]
- [[borgmatic]] provides daily backups to [[sifaka-nas|Sifaka]]
- Infrastructure can be rebootstrapped using the blumeops repo
- Detailed DR procedures not yet documented
## Components
- [[Borgmatic]] - Backup restoration
- [[1Password]] - Credential recovery
- [[Forgejo]] - Source of truth for infrastructure code
- [[borgmatic]] - Backup restoration
- [[1password]] - Credential recovery
- [[forgejo]] - Source of truth for infrastructure code

View file

@ -1,5 +1,5 @@
---
title: Observability
title: observability
tags:
- operations
---
@ -10,7 +10,7 @@ Metrics, logs, and dashboards for BlumeOps infrastructure.
## Components
- [[Prometheus]] - Metrics storage and querying
- [[Loki]] - Log aggregation
- [[Grafana Alloy|Alloy]] - Metrics and log collection
- [[Grafana]] - Dashboards and visualization
- [[prometheus]] - Metrics storage and querying
- [[loki]] - Log aggregation
- [[grafana-alloy|Alloy]] - Metrics and log collection
- [[grafana]] - Dashboards and visualization

View file

@ -1,5 +1,5 @@
---
title: 1Password
title: 1password
tags:
- service
- secrets
@ -36,5 +36,5 @@ Services reference 1Password items via `ExternalSecret` manifests.
## Related
- [[ArgoCD]] - Uses secrets for git access
- [[PostgreSQL]] - Database credentials
- [[argocd]] - Uses secrets for git access
- [[postgresql]] - Database credentials

View file

@ -1,5 +1,5 @@
---
title: Grafana Alloy
title: grafana-alloy
tags:
- service
- observability
@ -27,7 +27,7 @@ Unified observability collector for metrics and logs with two deployments:
- System metrics via `prometheus.exporter.unix`
- Textfile collector: `minikube.prom`, `borgmatic.prom`, `zot.prom`, `jellyfin.prom`
- Zot registry metrics from `http://localhost:5050/metrics`
- Pushed to [[Prometheus]] via remote_write
- Pushed to [[prometheus]] via remote_write
### From Kubernetes
- All pod logs via `loki.source.kubernetes`
@ -39,7 +39,7 @@ Unified observability collector for metrics and logs with two deployments:
**mcquack LaunchAgents:** alloy, borgmatic, zot, jellyfin
Logs pushed to [[Loki]] at `https://loki.tail8d86e.ts.net/loki/api/v1/push`.
Logs pushed to [[loki]] at `https://loki.tail8d86e.ts.net/loki/api/v1/push`.
## Why Built from Source
@ -49,6 +49,6 @@ The Homebrew bottle uses `CGO_ENABLED=0`, which breaks Tailscale MagicDNS. Build
## Related
- [[Prometheus]] - Metrics storage
- [[Loki]] - Log storage
- [[Grafana]] - Visualization
- [[prometheus]] - Metrics storage
- [[loki]] - Log storage
- [[grafana]] - Visualization

View file

@ -1,5 +1,5 @@
---
title: ArgoCD
title: argocd
tags:
- service
- gitops
@ -7,7 +7,7 @@ tags:
# ArgoCD
GitOps continuous delivery platform for the [[Kubernetes Cluster|Kubernetes cluster]].
GitOps continuous delivery platform for the [[kubernetes-cluster|Kubernetes cluster]].
## Quick Reference
@ -33,5 +33,5 @@ GitOps continuous delivery platform for the [[Kubernetes Cluster|Kubernetes clus
## Related
- [[ArgoCD Applications|Apps]] - Full application registry
- [[Forgejo]] - Git source
- [[argocd-applications|Apps]] - Full application registry
- [[forgejo]] - Git source

View file

@ -1,5 +1,5 @@
---
title: Borgmatic
title: borgmatic
tags:
- service
- backup
@ -16,7 +16,7 @@ Daily backup system using Borg backup, running on indri.
| **Install** | mise (pipx) |
| **Config** | `~/.config/borgmatic/config.yaml` |
| **Schedule** | Daily at 2:00 AM |
| **Repository** | `/Volumes/backups/borg/` on [[Sifaka NAS|Sifaka]] |
| **Repository** | `/Volumes/backups/borg/` on [[sifaka-nas|Sifaka]] |
## What Gets Backed Up
@ -28,8 +28,8 @@ Daily backup system using Borg backup, running on indri.
- `~/Pictures` - Photos
**Databases:**
- `miniflux` on [[PostgreSQL]]
- `teslamate` on [[PostgreSQL]]
- `miniflux` on [[postgresql]]
- `teslamate` on [[postgresql]]
**Not backed up (by design):**
- ZIM archives (re-downloadable)
@ -46,15 +46,15 @@ Daily backup system using Borg backup, running on indri.
## Monitoring
Metrics exposed via textfile collector to [[Prometheus]]:
Metrics exposed via textfile collector to [[prometheus]]:
- `borgmatic_up` - Repository accessibility
- `borgmatic_last_archive_timestamp` - Last backup time
- `borgmatic_repo_deduplicated_size_bytes` - Disk usage
Dashboard: "Borgmatic Backups" in [[Grafana]]
Dashboard: "Borgmatic Backups" in [[grafana]]
## Related
- [[Backup Policy|Backups]] - Full backup policy
- [[Sifaka NAS|Sifaka]] - Backup target
- [[PostgreSQL]] - Database backups
- [[backup-policy|Backups]] - Full backup policy
- [[sifaka-nas|Sifaka]] - Backup target
- [[postgresql]] - Database backups

View file

@ -1,5 +1,5 @@
---
title: Forgejo
title: forgejo
tags:
- service
- git
@ -44,5 +44,5 @@ Managed via 1Password: `lfs-jwt-secret`, `internal-token`, `oauth2-jwt-secret`,
## Related
- [[ArgoCD]] - Uses Forgejo as git source
- [[Zot]] - Container registry for built images
- [[argocd]] - Uses Forgejo as git source
- [[zot]] - Container registry for built images

View file

@ -1,5 +1,5 @@
---
title: Grafana
title: grafana
tags:
- service
- observability
@ -45,6 +45,6 @@ Optional annotation: `grafana_folder: "FolderName"`
## Related
- [[Prometheus]] - Metrics datasource
- [[Loki]] - Logs datasource
- [[Grafana Alloy|Alloy]] - Data collector
- [[prometheus]] - Metrics datasource
- [[loki]] - Logs datasource
- [[grafana-alloy|Alloy]] - Data collector

View file

@ -1,5 +1,5 @@
---
title: Immich
title: immich
tags:
- service
- media
@ -16,11 +16,11 @@ Self-hosted photo and video management.
| **URL** | https://photos.ops.eblu.me |
| **Namespace** | `immich` |
| **Deployment** | Helm chart (k8s) |
| **Database** | [[PostgreSQL]] (CNPG) |
| **Storage** | [[Sifaka NAS|Sifaka]] photos volume |
| **Database** | [[postgresql]] (CNPG) |
| **Storage** | [[sifaka-nas|Sifaka]] photos volume |
## Related
- [[PostgreSQL]] - Database backend
- [[Sifaka NAS|Sifaka]] - Photo storage
- [[Jellyfin]] - Video streaming (separate service)
- [[postgresql]] - Database backend
- [[sifaka-nas|Sifaka]] - Photo storage
- [[jellyfin]] - Video streaming (separate service)

View file

@ -1,5 +1,5 @@
---
title: Jellyfin
title: jellyfin
tags:
- service
- media
@ -42,10 +42,10 @@ Dashboard > Playback:
## Observability
- Metrics: `jellyfin_metrics` ansible role
- Logs: Forwarded via [[Grafana Alloy|Alloy]]
- Dashboard: "Jellyfin Media Server" in [[Grafana]]
- Logs: Forwarded via [[grafana-alloy|Alloy]]
- Dashboard: "Jellyfin Media Server" in [[grafana]]
## Related
- [[Navidrome]] - Music streaming
- [[Sifaka NAS|Sifaka]] - Media storage
- [[navidrome]] - Music streaming
- [[sifaka-nas|Sifaka]] - Media storage

View file

@ -1,5 +1,5 @@
---
title: Kiwix
title: kiwix
tags:
- service
- knowledge
@ -17,14 +17,14 @@ Offline Wikipedia and ZIM archive server.
| **Tailscale URL** | https://kiwix.tail8d86e.ts.net |
| **Namespace** | `kiwix` |
| **Image** | `ghcr.io/kiwix/kiwix-serve:3.8.1` |
| **Storage** | NFS from [[Sifaka NAS|Sifaka]] (`/volume1/torrents`) |
| **Storage** | NFS from [[sifaka-nas|Sifaka]] (`/volume1/torrents`) |
## Architecture
| Component | Purpose |
|-----------|---------|
| kiwix-serve | Serves ZIM files on port 80 |
| torrent-sync | Sidecar syncing ZIM torrents to [[Transmission]] |
| torrent-sync | Sidecar syncing ZIM torrents to [[transmission]] |
| zim-watcher | CronJob (hourly) to restart on new ZIMs |
## Configured Archives
@ -43,10 +43,10 @@ Full list: `argocd/manifests/kiwix/configmap-zim-torrents.yaml`
1. Edit `configmap-zim-torrents.yaml`
2. Add torrent URL from https://download.kiwix.org/zim/
3. Sync: `argocd app sync kiwix`
4. Torrent-sync adds to [[Transmission]]
4. Torrent-sync adds to [[transmission]]
5. zim-watcher restarts kiwix when download completes
## Related
- [[Transmission]] - Downloads ZIM files
- [[Sifaka NAS|Sifaka]] - ZIM storage
- [[transmission]] - Downloads ZIM files
- [[sifaka-nas|Sifaka]] - ZIM storage

View file

@ -1,5 +1,5 @@
---
title: Loki
title: loki
tags:
- service
- observability
@ -24,8 +24,8 @@ Log aggregation system for BlumeOps infrastructure.
- Single-node deployment with filesystem storage
- TSDB index with 24h period
- Logs collected by [[Grafana Alloy|Alloy]] and pushed via Loki API
- Queried via [[Grafana]]
- Logs collected by [[grafana-alloy|Alloy]] and pushed via Loki API
- Queried via [[grafana]]
## Log Sources
@ -46,6 +46,6 @@ Log aggregation system for BlumeOps infrastructure.
## Related
- [[Grafana Alloy|Alloy]] - Log collector
- [[Grafana]] - Log visualization
- [[Prometheus]] - Metrics counterpart
- [[grafana-alloy|Alloy]] - Log collector
- [[grafana]] - Log visualization
- [[prometheus]] - Metrics counterpart

View file

@ -1,5 +1,5 @@
---
title: Miniflux
title: miniflux
tags:
- service
- rss
@ -17,7 +17,7 @@ Minimalist RSS/Atom feed reader.
| **Tailscale URL** | https://feed.tail8d86e.ts.net |
| **Namespace** | `miniflux` |
| **Image** | `ghcr.io/miniflux/miniflux:latest` |
| **Database** | [[PostgreSQL]] |
| **Database** | [[postgresql]] |
## Features
@ -33,9 +33,9 @@ Uses CloudNativePG cluster at `pg.ops.eblu.me`. Database user password stored in
## Backup
Feed subscriptions and read state backed up via [[Borgmatic]] PostgreSQL hook.
Feed subscriptions and read state backed up via [[borgmatic]] PostgreSQL hook.
## Related
- [[PostgreSQL]] - Database backend
- [[Borgmatic]] - Data backup
- [[postgresql]] - Database backend
- [[borgmatic]] - Data backup

View file

@ -1,5 +1,5 @@
---
title: Navidrome
title: navidrome
tags:
- service
- media
@ -38,5 +38,5 @@ The `/data` directory contains SQLite database, configuration, and cache.
## Related
- [[Jellyfin]] - Video streaming
- [[Sifaka NAS|Sifaka]] - Music storage
- [[jellyfin]] - Video streaming
- [[sifaka-nas|Sifaka]] - Music storage

View file

@ -1,5 +1,5 @@
---
title: PostgreSQL
title: postgresql
tags:
- service
- database
@ -23,8 +23,8 @@ Database cluster via CloudNativePG operator.
| Database | Owner | Purpose |
|----------|-------|---------|
| miniflux | miniflux | [[Miniflux]] feed data |
| teslamate | teslamate | [[TeslaMate]] vehicle data |
| miniflux | miniflux | [[miniflux]] feed data |
| teslamate | teslamate | [[teslamate]] vehicle data |
## Users
@ -34,11 +34,11 @@ Database cluster via CloudNativePG operator.
| miniflux | app owner | Owns miniflux database |
| teslamate | superuser | TeslaMate (needs extensions) |
| eblume | superuser | Admin access |
| borgmatic | pg_read_all_data | [[Borgmatic|Backup]] access |
| borgmatic | pg_read_all_data | [[borgmatic|Backup]] access |
## Backup
Backed up via [[Borgmatic]] `postgresql_databases` hook. Streams `pg_dump` directly to Borg (no intermediate files, no downtime). See [[Backup]] for overall backup policy.
Backed up via [[borgmatic]] `postgresql_databases` hook. Streams `pg_dump` directly to Borg (no intermediate files, no downtime). See [[backup]] for overall backup policy.
## Credentials
@ -54,6 +54,6 @@ Backed up via [[Borgmatic]] `postgresql_databases` hook. Streams `pg_dump` direc
## Related
- [[Miniflux]] - Feed reader database
- [[TeslaMate]] - Vehicle data database
- [[Borgmatic]] - Database backup
- [[miniflux]] - Feed reader database
- [[teslamate]] - Vehicle data database
- [[borgmatic]] - Database backup

View file

@ -1,5 +1,5 @@
---
title: Prometheus
title: prometheus
tags:
- service
- observability
@ -23,19 +23,19 @@ Metrics storage and querying for BlumeOps infrastructure.
## Data Sources
### Remote Write (from Alloy)
- Indri system metrics via [[Grafana Alloy|Alloy]] remote_write
- Indri system metrics via [[grafana-alloy|Alloy]] remote_write
- Textfile metrics: minikube, borgmatic, zot, jellyfin
### Scrape Targets
| Target | Metrics |
|--------|---------|
| `sifaka:9100` | [[Sifaka NAS|Sifaka]] NAS (node_exporter) |
| `cnpg-metrics.tail8d86e.ts.net:9187` | [[PostgreSQL|CloudNativePG]] metrics |
| `sifaka:9100` | [[sifaka-nas|Sifaka]] NAS (node_exporter) |
| `cnpg-metrics.tail8d86e.ts.net:9187` | [[postgresql|CloudNativePG]] metrics |
| `kube-state-metrics.monitoring.svc:8080` | Kubernetes resource metrics |
## Related
- [[Grafana Alloy|Alloy]] - Metrics collector
- [[Grafana]] - Visualization
- [[Loki]] - Logs counterpart
- [[grafana-alloy|Alloy]] - Metrics collector
- [[grafana]] - Visualization
- [[loki]] - Logs counterpart

View file

@ -1,5 +1,5 @@
---
title: TeslaMate
title: teslamate
tags:
- service
- vehicle
@ -17,7 +17,7 @@ Self-hosted Tesla data logger collecting vehicle telemetry from the Tesla Owner
| **Tailscale URL** | https://tesla.tail8d86e.ts.net |
| **Namespace** | `teslamate` |
| **Image** | `teslamate/teslamate:2.2.0` |
| **Database** | [[PostgreSQL]] |
| **Database** | [[postgresql]] |
## Data Collected
@ -53,6 +53,6 @@ Uses Tesla Owner API via OAuth:
## Related
- [[PostgreSQL]] - Data storage
- [[Grafana]] - Dashboards
- [[Borgmatic]] - Database backup
- [[postgresql]] - Data storage
- [[grafana]] - Dashboards
- [[borgmatic]] - Database backup

View file

@ -1,5 +1,5 @@
---
title: Transmission
title: transmission
tags:
- service
- torrent
@ -7,7 +7,7 @@ tags:
# Transmission
BitTorrent daemon, primarily for downloading ZIM archives for [[Kiwix]].
BitTorrent daemon, primarily for downloading ZIM archives for [[kiwix]].
## Quick Reference
@ -17,7 +17,7 @@ BitTorrent daemon, primarily for downloading ZIM archives for [[Kiwix]].
| **Tailscale URL** | https://torrent.tail8d86e.ts.net |
| **Namespace** | `torrent` |
| **Image** | `lscr.io/linuxserver/transmission:latest` |
| **Storage** | NFS PVC from [[Sifaka NAS|Sifaka]] |
| **Storage** | NFS PVC from [[sifaka-nas|Sifaka]] |
## Storage Layout
@ -30,7 +30,7 @@ NFS share on sifaka (`/volume1/torrents`):
| `/config/` | Transmission configuration |
| `/watch/` | Watch directory for .torrent files |
[[Kiwix]] reads from `/downloads/complete/` to serve ZIM archives.
[[kiwix]] reads from `/downloads/complete/` to serve ZIM archives.
## Integration with Kiwix
@ -43,11 +43,11 @@ When downloads complete, the zim-watcher CronJob detects new ZIMs and restarts K
## Monitoring
Basic uptime via blackbox probe in [[Grafana Alloy|Alloy]] k8s (Services Health dashboard).
Basic uptime via blackbox probe in [[grafana-alloy|Alloy]] k8s (Services Health dashboard).
Web UI shows: active/seeding/paused counts, speeds, disk usage.
## Related
- [[Kiwix]] - ZIM archive consumer
- [[Sifaka NAS|Sifaka]] - Download storage
- [[kiwix]] - ZIM archive consumer
- [[sifaka-nas|Sifaka]] - Download storage

View file

@ -1,5 +1,5 @@
---
title: Zot
title: zot
tags:
- service
- registry
@ -30,7 +30,7 @@ OCI-native container registry providing pull-through cache and private image sto
## Pull-Through Cache
When [[Kubernetes Cluster|minikube]] pulls an image, containerd checks zot first. If cached, returns immediately. If not, zot fetches from upstream, caches it, then returns.
When [[kubernetes-cluster|minikube]] pulls an image, containerd checks zot first. If cached, returns immediately. If not, zot fetches from upstream, caches it, then returns.
## Security Model
@ -38,5 +38,5 @@ Network access only (no authentication). Defense is the Tailscale ACL boundary.
## Related
- [[Forgejo]] - Container build CI
- [[Kubernetes Cluster|Cluster]] - Registry consumer
- [[forgejo]] - Container build CI
- [[kubernetes-cluster|Cluster]] - Registry consumer

View file

@ -1,5 +1,5 @@
---
title: Backup Policy
title: backup-policy
tags:
- storage
- backup
@ -7,13 +7,13 @@ tags:
# Backup Policy
Daily automated backups from [[Indri]] to [[Sifaka NAS|Sifaka]] NAS.
Daily automated backups from [[indri]] to [[sifaka-nas|Sifaka]] NAS.
## Schedule
| Time | Frequency | System |
|------|-----------|--------|
| 2:00 AM | Daily | [[Borgmatic]] |
| 2:00 AM | Daily | [[borgmatic]] |
## What Gets Backed Up
@ -31,8 +31,8 @@ Daily automated backups from [[Indri]] to [[Sifaka NAS|Sifaka]] NAS.
| Database | Host | Method |
|----------|------|--------|
| miniflux | [[PostgreSQL|pg.ops.eblu.me]] | pg_dump stream |
| teslamate | [[PostgreSQL|pg.ops.eblu.me]] | pg_dump stream |
| miniflux | [[postgresql|pg.ops.eblu.me]] | pg_dump stream |
| teslamate | [[postgresql|pg.ops.eblu.me]] | pg_dump stream |
## What Is NOT Backed Up
@ -53,19 +53,19 @@ Daily automated backups from [[Indri]] to [[Sifaka NAS|Sifaka]] NAS.
## Backup Target
Repository: `/Volumes/backups/borg/` on [[Sifaka NAS|Sifaka]]
Repository: `/Volumes/backups/borg/` on [[sifaka-nas|Sifaka]]
## Monitoring
Metrics exposed to [[Prometheus]]:
Metrics exposed to [[prometheus]]:
- `borgmatic_up` - Repository accessible
- `borgmatic_last_archive_timestamp` - Last backup time
- `borgmatic_repo_deduplicated_size_bytes` - Disk usage
Dashboard: "Borgmatic Backups" in [[Grafana]]
Dashboard: "Borgmatic Backups" in [[grafana]]
## Related
- [[Borgmatic]] - Backup system details
- [[Sifaka NAS|Sifaka]] - Backup storage
- [[PostgreSQL]] - Database backups
- [[borgmatic]] - Backup system details
- [[sifaka-nas|Sifaka]] - Backup storage
- [[postgresql]] - Database backups

View file

@ -1,5 +1,5 @@
---
title: PostgreSQL Storage
title: postgresql-storage
tags:
- storage
- database
@ -7,4 +7,4 @@ tags:
# PostgreSQL Storage
See [[PostgreSQL]] in Services.
See [[postgresql]] in Services.

View file

@ -1,5 +1,5 @@
---
title: Sifaka NAS
title: sifaka-nas
tags:
- storage
---
@ -21,11 +21,11 @@ Synology NAS providing network storage and backup target.
| Share | Path | Purpose | Consumers |
|-------|------|---------|-----------|
| backups | `/volume1/backups` | Borg backup repository | [[Borgmatic]] |
| torrents | `/volume1/torrents` | ZIM downloads | [[Kiwix]], [[Transmission]] |
| music | `/volume1/music` | Music library | [[Navidrome]] |
| allisonflix | `/volume1/allisonflix` | Video library | [[Jellyfin]] |
| photos | `/volume1/photos` | Photo library | [[Immich]] |
| backups | `/volume1/backups` | Borg backup repository | [[borgmatic]] |
| torrents | `/volume1/torrents` | ZIM downloads | [[kiwix]], [[transmission]] |
| music | `/volume1/music` | Music library | [[navidrome]] |
| allisonflix | `/volume1/allisonflix` | Video library | [[jellyfin]] |
| photos | `/volume1/photos` | Photo library | [[immich]] |
## NFS Exports
@ -37,7 +37,7 @@ Synology NAS providing network storage and backup target.
## Monitoring
Node exporter running in Docker container, scraped by [[Prometheus]] at `sifaka:9100`.
Node exporter running in Docker container, scraped by [[prometheus]] at `sifaka:9100`.
## Tailscale
@ -46,14 +46,14 @@ Node exporter running in Docker container, scraped by [[Prometheus]] at `sifaka:
## Backup
Sifaka is the **target** for [[Backup|backups]], not a backup source. [[Borgmatic]] sends backups TO sifaka, not OF sifaka.
Sifaka is the **target** for [[backup|backups]], not a backup source. [[borgmatic]] sends backups TO sifaka, not OF sifaka.
Data protection for sifaka itself currently relies on the Synology RAID 5 configuration, which provides single-disk fault tolerance. Future plans include offsite duplication for additional resiliency.
## Related
- [[Backup Policy|Backups]] - Backup policy
- [[Borgmatic]] - Backup system
- [[Immich]] - Photo consumer
- [[Jellyfin]] - Media consumer
- [[Navidrome]] - Music consumer
- [[backup-policy|Backups]] - Backup policy
- [[borgmatic]] - Backup system
- [[immich]] - Photo consumer
- [[jellyfin]] - Media consumer
- [[navidrome]] - Music consumer

View file

@ -3,19 +3,22 @@
# requires-python = ">=3.12"
# dependencies = ["pyyaml>=6.0", "rich>=13.0.0"]
# ///
#MISE description="List all doc card titles and detect duplicates"
"""List all documentation card titles and detect duplicates.
#MISE description="List all doc card titles and detect duplicates or invalid formats"
"""List all documentation card titles and detect duplicates or invalid formats.
This script scans all markdown files in the docs/ directory (excluding
changelog.d/ and zk/), extracts frontmatter titles, and reports any
duplicates that could cause wiki-link resolution issues.
duplicates or invalid formats that could cause wiki-link resolution issues.
With Quartz, wiki-links like [[Title]] resolve by frontmatter title,
so titles must be unique across the documentation.
With Quartz, wiki-links like [[title]] resolve by frontmatter title,
so titles must be:
- Unique across the documentation
- Lowercase with hyphens (no spaces or uppercase)
Usage: mise run doc-titles
"""
import re
import sys
from collections import defaultdict
from pathlib import Path
@ -26,6 +29,9 @@ from rich.table import Table
DOCS_DIR = Path(__file__).parent.parent / "docs"
# Valid title pattern: lowercase letters, numbers, hyphens only
VALID_TITLE_PATTERN = re.compile(r"^[a-z0-9]+(-[a-z0-9]+)*$")
def extract_frontmatter(file_path: Path) -> dict | None:
"""Extract YAML frontmatter from a markdown file."""
@ -44,12 +50,18 @@ def extract_frontmatter(file_path: Path) -> dict | None:
return None
def is_valid_slug(title: str) -> bool:
"""Check if title is a valid slug (lowercase, hyphens, no spaces)."""
return bool(VALID_TITLE_PATTERN.match(title))
def main() -> int:
console = Console()
# Collect all titles and their source files
# Key: title, Value: list of file paths
titles: dict[str, list[str]] = defaultdict(list)
invalid_titles: list[tuple[str, str]] = [] # (title, file_path)
# Scan all markdown files (excluding zk/ and changelog.d/)
for md_file in sorted(DOCS_DIR.rglob("*.md")):
@ -66,6 +78,8 @@ def main() -> int:
title = frontmatter.get("title")
if title:
titles[title].append(rel_path)
if not is_valid_slug(title):
invalid_titles.append((title, rel_path))
# Find duplicates
duplicates = {title: paths for title, paths in titles.items() if len(paths) > 1}
@ -73,12 +87,30 @@ def main() -> int:
# Print results
console.print("[bold]Doc Card Title Inventory[/bold]")
console.print()
console.print("With Quartz, wiki-links like [[Title]] resolve by frontmatter title,")
console.print("so titles must be unique across the documentation.")
console.print("Titles must be lowercase slugs (e.g., 'grafana-alloy', not 'Grafana Alloy')")
console.print("and unique across the documentation for wiki-link resolution.")
console.print()
has_errors = False
# Invalid format table (if any)
if invalid_titles:
has_errors = True
console.print("[bold red]Invalid Title Format[/bold red]")
console.print("Titles must be lowercase with hyphens only (no spaces or uppercase).")
inv_table = Table(show_header=True, header_style="bold")
inv_table.add_column("Title")
inv_table.add_column("File")
for title, file_path in invalid_titles:
inv_table.add_row(title, file_path)
console.print(inv_table)
console.print()
# Duplicates table (if any)
if duplicates:
has_errors = True
console.print("[bold red]Duplicate Titles Found[/bold red]")
dup_table = Table(show_header=True, header_style="bold")
dup_table.add_column("Title")
@ -101,7 +133,15 @@ def main() -> int:
for title in sorted(titles.keys()):
paths = titles[title]
is_dup = title in duplicates
status = "[red]DUPLICATE[/red]" if is_dup else "[green]OK[/green]"
is_invalid = not is_valid_slug(title)
if is_dup:
status = "[red]DUPLICATE[/red]"
elif is_invalid:
status = "[red]INVALID[/red]"
else:
status = "[green]OK[/green]"
all_table.add_row(title, paths[0], status)
for extra_path in paths[1:]:
all_table.add_row("", extra_path, "")
@ -113,10 +153,11 @@ def main() -> int:
console.print(f"Total files: {sum(len(p) for p in titles.values())}")
console.print(f"Unique titles: {len(titles)}")
console.print(f"Duplicate titles: {len(duplicates)}")
console.print(f"Invalid format: {len(invalid_titles)}")
if duplicates:
if has_errors:
console.print()
console.print("[bold red]Action required:[/bold red] Rename titles to ensure unique wiki-link resolution.")
console.print("[bold red]Action required:[/bold red] Fix title issues above.")
return 1
return 0