325 lines
16 KiB
Python
325 lines
16 KiB
Python
"""Tool catalogue — the Family Home Lab "home dash".
|
|
|
|
Each tool maps to a category (colour sticker), a friendly name/description and a
|
|
launch mode: "embed" (inline iframe) or "window" (new tab / external link).
|
|
|
|
This is a curated home-dash across .13 and .35 plus Proxmox / Home Assistant.
|
|
Most of these are external apps that keep their OWN secondary login — we link
|
|
out to them and never try to pass credentials (no SSO passthrough).
|
|
Flags:
|
|
external : link out in a new tab (opens URL directly, no /tool/ wrapper)
|
|
login : the target has its own login the user must sign into
|
|
lan : only resolves on the LAN (*.home.lab), not from the internet
|
|
admin : admin-only (infra / backups / monitoring)
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
|
|
from .config import settings
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class Tool:
|
|
id: str
|
|
name: str
|
|
category: str
|
|
description: str
|
|
url: str
|
|
mode: str = "window" # "embed" | "window"
|
|
status: str = "online"
|
|
external: bool = True
|
|
login: bool = False
|
|
lan: bool = False
|
|
admin: bool = False
|
|
private: bool = False # per-user private app (e.g. dsh instance)
|
|
|
|
|
|
def section_label(category: str) -> str:
|
|
return {
|
|
"chat": "Chat & AI",
|
|
"image": "Image Lab",
|
|
"video": "Video Lab",
|
|
"audio": "Audio Lab",
|
|
"docs": "Notes & Docs",
|
|
"ai": "AI Tools",
|
|
"media": "Media & Fun",
|
|
"data": "Data & Links",
|
|
"storage": "Storage & Backups",
|
|
"home": "Home & Lab",
|
|
"infra": "Infrastructure",
|
|
"network": "Home Network",
|
|
"home-mgmt": "Home Management",
|
|
"dev": "Development",
|
|
"portfolio": "Portfolio",
|
|
}.get(category, category.title())
|
|
|
|
|
|
def section_color(category: str) -> str:
|
|
return settings.SECTION_COLORS.get(category, "#a39e98")
|
|
|
|
|
|
# Every category a user may have tools in; simple tooling produces all of these.
|
|
ALL_CATEGORIES = [
|
|
"chat", "ai", "image", "video", "audio", "media", "docs", "data",
|
|
"home-mgmt", "storage", "dev", "portfolio", "home", "infra", "network",
|
|
]
|
|
|
|
|
|
def _cat() -> list[Tool]:
|
|
"""Curated home-dash catalogue across .13 / .35 / Proxmox / Home Assistant."""
|
|
return [
|
|
# ---- Chat & AI -----------------------------------------------------
|
|
Tool("dsh", "DeepSeek Harness", "chat",
|
|
"Your personal assistant instance", "https://dsh-sam.lab.audasmedia.com.au",
|
|
private=True, login=True),
|
|
Tool("chat-lab", "Family Chat", "chat",
|
|
"Group chat — available to everyone", "https://chat.lab.audasmedia.com.au", login=True),
|
|
Tool("pb-chat", "PB Chat (Admin)", "chat",
|
|
"Chat admin console (admins only)", "https://pb.chat.lab.audasmedia.com.au", login=True, admin=True),
|
|
Tool("ai-router", "AI Router", "ai",
|
|
"OmniRoute LLM gateway dashboard", "https://omniroute.lab.audasmedia.com.au", login=True),
|
|
Tool("n8n", "n8n", "ai",
|
|
"Workflow automation", "https://n8n.lab.audasmedia.com.au", login=True),
|
|
Tool("langfuse", "Langfuse", "ai",
|
|
"LLM tracing & observability", "https://langfuse.home.lab", login=True, lan=True, admin=True),
|
|
Tool("prefect", "Prefect", "ai",
|
|
"Workflow orchestration", "https://prefect.lab.audasmedia.com.au", login=True),
|
|
Tool("archon", "Archon", "ai",
|
|
"Autonomous coding agent", "https://archon.home.lab", login=True, lan=True),
|
|
Tool("supabase", "LangChain (Supabase)", "ai",
|
|
"LangChain dev service", "https://supabase.home.lab", login=True, lan=True, admin=True),
|
|
|
|
# ---- Image ---------------------------------------------------------
|
|
Tool("photopea", "Photopea", "image",
|
|
"Browser photo & PSD editor", "https://photo.lab.audasmedia.com.au", login=True),
|
|
Tool("penpot", "Penpot", "image",
|
|
"Open-source design & prototyping", "https://penpot.lab.audasmedia.com.au", login=True),
|
|
Tool("photo-filter", "Photo Filter", "image",
|
|
"Photo utility / filtering", "https://photo-filter.lab.audasmedia.com.au", login=True),
|
|
|
|
# ---- Video ---------------------------------------------------------
|
|
Tool("video-editor", "Video Editor", "video",
|
|
"Desktop video editing in your browser", "https://video.lab.audasmedia.com.au", login=True),
|
|
Tool("jellyfin", "Jellyfin", "media",
|
|
"Movies, TV & music server", "https://jellyfin.lab.audasmedia.com.au", login=True),
|
|
Tool("jellyseerr", "Jellyseerr", "media",
|
|
"Request movies & shows", "https://jellyseerr.lab.audasmedia.com.au", login=True),
|
|
Tool("games", "Games", "media",
|
|
"Retro games (emulatorjs, LAN)", "https://games.home.lab", lan=True),
|
|
Tool("sonarr", "Sonarr", "media",
|
|
"TV series manager", "https://sonarr.lab.audasmedia.com.au", login=True, admin=True),
|
|
Tool("radarr", "Radarr", "media",
|
|
"Movie manager", "https://radarr.lab.audasmedia.com.au", login=True, admin=True),
|
|
Tool("readarr", "Readarr", "media",
|
|
"Ebook manager", "https://readarr.lab.audasmedia.com.au", login=True, admin=True),
|
|
Tool("lidarr", "Lidarr", "media",
|
|
"Music manager", "https://lidarr.lab.audasmedia.com.au", login=True, admin=True),
|
|
Tool("sabnzbd", "SABnzbd", "media",
|
|
"Usenet downloader", "https://sabnzbd.lab.audasmedia.com.au", login=True, admin=True),
|
|
Tool("qbittorrent", "qBittorrent", "media",
|
|
"Torrent client", "https://qbittorrent.lab.audasmedia.com.au", login=True, admin=True),
|
|
Tool("spotweb", "Spotweb", "media",
|
|
"Spotnet indexer", "https://spotweb.lab.audasmedia.com.au", login=True, admin=True),
|
|
Tool("headphones", "Headphones", "media",
|
|
"Music manager", "https://headphones.lab.audasmedia.com.au", login=True, admin=True),
|
|
|
|
# ---- Audio ---------------------------------------------------------
|
|
Tool("audio-editor", "Audio Editor", "audio",
|
|
"Multi-track audio editing", "https://audio.lab.audasmedia.com.au", login=True),
|
|
Tool("lmms", "LMMS Music Studio", "audio",
|
|
"Beats, melodies & full arrangements", "https://lmms.lab.audasmedia.com.au", login=True),
|
|
Tool("snapcast", "Snapcast", "audio",
|
|
"Sync audio to speakers around the house", "https://snapcast.home.lab", lan=True),
|
|
Tool("mopidy", "Mopidy", "audio",
|
|
"Music player (LAN only)", "http://mopidy.home.lab", lan=True),
|
|
|
|
# ---- Notes & Docs --------------------------------------------------
|
|
Tool("silverbullet", "SilverBullet", "docs",
|
|
"Markdown notes & knowledge", "https://silverbullet.lab.audasmedia.com.au", login=True),
|
|
Tool("affine", "AFFiNE", "docs",
|
|
"Docs + whiteboard + database", "https://affine.lab.audasmedia.com.au", login=True),
|
|
Tool("hedgedoc", "HedgeDoc", "docs",
|
|
"Real-time collaborative markdown", "https://hedgedoc.lab.audasmedia.com.au", login=True),
|
|
Tool("trilium", "Trilium", "docs",
|
|
"Privacy-focused notes", "https://trillium.lab.audasmedia.com.au", login=True),
|
|
Tool("flatnotes", "Flatnotes", "docs",
|
|
"Minimal markdown notes", "https://flatnotes.lab.audasmedia.com.au", login=True),
|
|
Tool("vikunja", "Vikunja", "docs",
|
|
"Tasks & to-dos", "https://vikunja.lab.audasmedia.com.au", login=True),
|
|
Tool("bookstack", "BookStack", "docs",
|
|
"Documentation chains", "https://bookstack.home.lab", login=True, lan=True),
|
|
Tool("dokuwiki", "DokuWiki", "docs",
|
|
"Lightweight wiki", "https://dokuwiki.lab.audasmedia.com.au", login=True),
|
|
Tool("kanboard", "Kanboard", "docs",
|
|
"Kanban boards", "https://kanboard.lab.audasmedia.com.au", login=True),
|
|
|
|
# ---- Data & Links --------------------------------------------------
|
|
Tool("nocodb", "NocoDB", "data",
|
|
"Turn spreadsheets into apps", "https://nocodb.lab.audasmedia.com.au", login=True),
|
|
Tool("linkace", "LinkAce", "data",
|
|
"Bookmark manager", "https://linkace.lab.audasmedia.com.au", login=True),
|
|
Tool("wherewoof", "Where-Woof", "data",
|
|
"Family location tracking", "https://where-woof.com", login=True),
|
|
Tool("wherewoof-admin", "Where-Woof Admin", "data",
|
|
"Manage family location tracking", "https://admin.where-woof.com", login=True),
|
|
Tool("freshrss", "FreshRSS", "data",
|
|
"RSS reader", "https://freshrss.lab.audasmedia.com.au", login=True),
|
|
Tool("firefly", "Firefly III", "data",
|
|
"Personal finance", "https://firefly.lab.audasmedia.com.au", login=True, admin=True),
|
|
Tool("vaultwarden", "Vaultwarden", "data",
|
|
"Password manager", "https://vaultwarden.lab.audasmedia.com.au", login=True, admin=True),
|
|
|
|
# ---- Home Management ----------------------------------------------
|
|
Tool("homebox", "Homebox", "home-mgmt",
|
|
"Home inventory & items", "https://homebox.lab.audasmedia.com.au", login=True),
|
|
Tool("toora", "Toora Wiki", "home-mgmt",
|
|
"Home wiki", "https://toora.lab.audasmedia.com.au", login=True),
|
|
Tool("sams", "Sams Files", "home-mgmt",
|
|
"Home file server (LAN)", "http://sams.home.lab", lan=True),
|
|
Tool("owl", "Owl Recipes", "home-mgmt",
|
|
"Kitchen recipes & household", "https://owl.lab.audasmedia.com.au", login=True),
|
|
|
|
# ---- Storage & Files ----------------------------------------------
|
|
Tool("nextcloud", "Nextcloud", "storage",
|
|
"Files, calendar, contacts", "https://nextcloud.home.lab", login=True, lan=True),
|
|
Tool("immich", "Immich", "storage",
|
|
"Self-hosted photo gallery", "https://immich.lab.audasmedia.com.au", login=True),
|
|
Tool("paperless", "Paperless-ngx", "storage",
|
|
"Scan, OCR & archive documents", "https://paperless.lab.audasmedia.com.au", login=True),
|
|
Tool("filebrowser", "File Browser", "storage",
|
|
"File management web UI", "https://filebrowser.lab.audasmedia.com.au", login=True),
|
|
Tool("garage", "Garage S3", "storage",
|
|
"Object storage (buckets)", "http://192.168.20.13:3902",
|
|
login=True, lan=True, admin=True),
|
|
Tool("pingvin", "Pingvin Share", "storage",
|
|
"Share files & notes", "https://pingvin.lab.audasmedia.com.au", login=True),
|
|
Tool("kopia", "Kopia", "storage",
|
|
"Backups & restore", "https://kopia.home.lab", login=True, lan=True, admin=True),
|
|
Tool("backrest", "Backrest", "storage",
|
|
"Restic backup UI", "https://restic.home.lab", login=True, lan=True, admin=True),
|
|
|
|
# ---- Development ---------------------------------------------------
|
|
Tool("gitea", "Gitea", "dev",
|
|
"Git repositories", "https://gitea.lab.audasmedia.com.au", login=True),
|
|
|
|
# ---- Portfolio (Sam's resume sites) --------------------------------
|
|
Tool("sam-developer", "Developer", "portfolio",
|
|
"Resume — software development", "https://sam-developer.lab.audasmedia.com.au"),
|
|
Tool("sam-devops", "DevOps", "portfolio",
|
|
"Resume — DevOps & infrastructure", "https://sam-devops.lab.audasmedia.com.au"),
|
|
Tool("sam-iot-electronics", "IoT & Electronics", "portfolio",
|
|
"Resume — IoT & electronics", "https://sam-iot-electronics.lab.audasmedia.com.au"),
|
|
Tool("sam-pursuits", "Pursuits", "portfolio",
|
|
"Resume — projects & pursuits", "https://sam-pursuits.lab.audasmedia.com.au"),
|
|
Tool("wikijs", "Wiki.js", "portfolio",
|
|
"Resume wiki — machines & projects", "https://wikijs.lab.audasmedia.com.au", login=True),
|
|
Tool("lynx", "Lynx", "portfolio",
|
|
"Resume — projects gallery", "https://lynx.lab.audasmedia.com.au", login=True),
|
|
Tool("sequence", "Sequence", "portfolio",
|
|
"Resume — sequence", "https://sequence.lab.audasmedia.com.au"),
|
|
|
|
# ---- Home & Lab ----------------------------------------------------
|
|
Tool("home-assistant", "Home Assistant", "home",
|
|
"Home automation", "https://homeassistant.home.lab", login=True, lan=True),
|
|
Tool("proxmox", "Proxmox VE", "home",
|
|
"Virtualisation & containers", "https://proxmox.home.lab", login=True, lan=True, admin=True),
|
|
Tool("proxmox-backup", "Proxmox Backup", "home",
|
|
"VM/CT backup server", "https://proxmox_backup.home.lab", login=True, lan=True, admin=True),
|
|
|
|
# ---- Infrastructure & Network -------------------------------------
|
|
Tool("grafana", "Grafana", "infra",
|
|
"Metrics dashboards", "https://grafana.home.lab", login=True, lan=True, admin=True),
|
|
Tool("uptimekuma", "Uptime Kuma", "infra",
|
|
"Uptime monitoring & alerts", "https://uptimekuma.lab.audasmedia.com.au", login=True),
|
|
Tool("apprise", "Apprise", "infra",
|
|
"Notification & messaging API", "https://apprise.lab.audasmedia.com.au"),
|
|
Tool("portainer", "Portainer", "infra",
|
|
"Docker management", "https://portainer.home.lab", login=True, lan=True, admin=True),
|
|
Tool("dozzle", "Dozzle", "infra",
|
|
"Container logs (LAN)", "https://dozzle.home.lab", login=True, lan=True, admin=True),
|
|
Tool("watchyourlan", "WatchYourLAN", "infra",
|
|
"LAN device scanning (LAN)", "https://watchyourlan.home.lab", login=True, lan=True, admin=True),
|
|
Tool("phpipam", "phpIPAM", "infra",
|
|
"IP address manager (LAN)", "https://phpipam.home.lab", login=True, lan=True, admin=True),
|
|
Tool("flare", "Flare", "infra",
|
|
"Start page (LAN)", "https://flare.home.lab", login=True, lan=True),
|
|
Tool("ntfy", "Ntfy", "infra",
|
|
"Push notifications (LAN)", "https://ntfy.home.lab", login=True, lan=True),
|
|
Tool("worldmonitor", "World Monitor", "infra",
|
|
"Global monitoring", "https://worldmonitor.lab.audasmedia.com.au", login=True, admin=True),
|
|
Tool("homepage", "Homepage", "infra",
|
|
"Start page", "https://homepage.lab.audasmedia.com.au", login=True),
|
|
Tool("librenms", "LibreNMS", "network",
|
|
"Network monitoring", "https://librenms.home.lab", login=True, lan=True, admin=True),
|
|
Tool("pihole", "Pi-hole", "network",
|
|
"Network-wide ad blocking", "https://pihole.home.lab", login=True, lan=True),
|
|
]
|
|
|
|
|
|
TOOLS = _cat()
|
|
|
|
|
|
def tools_for_user(user) -> list[tuple[str, list[Tool]]]:
|
|
"""Return tools the user is permitted to see, grouped into category sections.
|
|
|
|
Family categories (media/fun, data, storage, home) are open to everyone.
|
|
Infra/network are gated by the admin flag on each tool. Existing per-user
|
|
capabilities (chat/image/video/audio/docs) still apply to those categories.
|
|
"""
|
|
# Admins see every category regardless of per-user capability flags.
|
|
if user.is_admin:
|
|
allowed = {cat: True for cat in ALL_CATEGORIES}
|
|
else:
|
|
allowed = {
|
|
"chat": user.can_chat,
|
|
"ai": user.can_chat, # ai stack broadly tied to chat entitlement
|
|
"image": user.can_image,
|
|
"video": user.can_video,
|
|
"audio": user.can_audio,
|
|
"docs": user.can_docs,
|
|
# open family-facing categories
|
|
"media": True,
|
|
"data": True,
|
|
"storage": True,
|
|
"home": True,
|
|
"home-mgmt": True,
|
|
"dev": True,
|
|
"portfolio": True,
|
|
"infra": True, # filtered by per-tool admin flag below
|
|
"network": True,
|
|
}
|
|
|
|
sections: dict[str, list[Tool]] = {}
|
|
for tool in TOOLS:
|
|
if tool.admin and not user.is_admin:
|
|
continue
|
|
if not allowed.get(tool.category, True):
|
|
continue
|
|
# Specialise the dsh chat link to the logged-in user's own instance.
|
|
if tool.id == "dsh":
|
|
tool = _dsh_for_user(user)
|
|
sections.setdefault(tool.category, []).append(tool)
|
|
|
|
ordered = []
|
|
for cat in ALL_CATEGORIES:
|
|
if cat in sections:
|
|
ordered.append((cat, sections[cat]))
|
|
return ordered
|
|
|
|
|
|
def _dsh_for_user(user) -> Tool:
|
|
base = next(t for t in TOOLS if t.id == "dsh")
|
|
host = user.username.strip().lower()
|
|
return Tool(
|
|
id=base.id,
|
|
name=base.name,
|
|
category=base.category,
|
|
description=base.description,
|
|
url=f"https://dsh-{host}.lab.audasmedia.com.au",
|
|
mode=base.mode,
|
|
status=base.status,
|
|
external=True,
|
|
login=True,
|
|
private=True,
|
|
) |