app:
name: dashboard
description: >
Personal hub — forge project state, LifeOS, misc tasks, and
app integrations. Runs as a protected /dashboard route on
astro-blog-site, fed by forge-denv HTTP API via Cloudflare tunnel.
stack: astro
version: 0.1.0
status: planned
cross_project:
- forge # denv HTTP API server (ANNOT-357)
- forge-denv # local runtime server + tunnel
- astro-blog-site # host (this file lives here)
- lifeos # Supabase connection for /dashboard/lifeos
# ─── Domains ─────────────────────────────────────────────────────────────────
domains:
- FORGE # forge project state, graph, packets, annotations
- TASKS # misc tasks, inbox, iOS shortcut integration
- LIFEOS # LifeOS habits, goals, check-ins (pre-mobile web UI)
- AUTH # owner-only gate, session management
- SHELL # shared layout, nav, sidebar, design tokens
# ─── Screens ─────────────────────────────────────────────────────────────────
screens:
- name: DashboardShell
domain: SHELL
path: src/pages/dashboard.astro
notes: >
Owner-only SSR gate. Checks session → redirects if not owner.
Renders sidebar nav + slot for section pages.
- name: ForgeStatusScreen
domain: FORGE
path: src/pages/dashboard/forge.astro
- name: ForgeProjectScreen
domain: FORGE
path: src/pages/dashboard/forge/[project].astro
notes: Per-project deep view — graph, diff, packet queue, annotations.
- name: TasksScreen
domain: TASKS
path: src/pages/dashboard/tasks.astro
- name: InboxScreen
domain: TASKS
path: src/pages/dashboard/inbox.astro
notes: Unprocessed items from iOS Shortcuts POST.
- name: LifeOSScreen
domain: LIFEOS
path: src/pages/dashboard/lifeos.astro
# ─── Features ────────────────────────────────────────────────────────────────
features:
- name: forge_live_status
kill_switch: false
notes: forge-denv must be running locally + tunnel active.
- name: forge_diff_view
kill_switch: false
notes: Shows forge verify --diff plan per domain.
- name: forge_packet_queue
kill_switch: false
- name: forge_annotation_feed
kill_switch: false
- name: tasks_inbox
kill_switch: false
notes: iOS Shortcut integration via POST /api/tasks.
- name: lifeos_integration
kill_switch: true
notes: Deferred — requires LifeOS Supabase connection.
- name: cloudflare_tunnel
kill_switch: false
notes: forge-denv exposed via Cloudflare Tunnel. Graceful offline state when Mac not running.
# ─── Nodes Planned ───────────────────────────────────────────────────────────
nodes_planned:
# SHELL
- name: DashboardLayout
type: layout
domain: SHELL
notes: Wraps all dashboard pages. Owner gate logic lives here.
- name: DashboardNav
type: component
domain: SHELL
notes: Sidebar nav with section links and active state.
- name: OfflineState
type: component
domain: SHELL
notes: >
Shown when forge-denv is unreachable. Graceful degradation —
does not break the dashboard for the owner.
# AUTH
- name: AuthGuard
type: component
domain: AUTH
notes: >
SSR auth check — reads session cookie, redirects non-owners.
Reuses existing astro-blog-site auth primitives.
# FORGE
- name: ForgeStatusPanel
type: component
domain: FORGE
notes: >
React island. Fetches GET /api/status from forge-denv.
Shows: project, phase, blocker, next_action, packet queue.
- name: ForgeDiffPanel
type: component
domain: FORGE
notes: >
React island. Fetches GET /api/diff/:domain.
Shows: planned vs present nodes per domain, ✓/✗ per node.
First ✗ per domain labelled "← next".
- name: ForgePacketPanel
type: component
domain: FORGE
notes: >
React island. Fetches GET /api/packets.
Shows: pending/expired/failed counts, packet list with age + review status.
- name: ForgeAnnotationFeed
type: component
domain: FORGE
notes: >
React island. Fetches GET /api/annotations.
Shows: annotation list filtered by horizon, kind, severity.
- name: ForgeGraphView
type: component
domain: FORGE
notes: >
React island. Fetches GET /api/graph.
Renders manifest graph visually (D3 or similar).
Deferred — lower priority than status/diff/packets.
- name: ForgeAPIClient
type: component
domain: FORGE
notes: >
Shared fetch utility for all forge panels.
Reads PUBLIC_FORGE_API_URL env var.
Handles offline state — returns null on fetch failure,
panels render OfflineState component.
# TASKS
- name: TaskList
type: component
domain: TASKS
notes: >
React island. Fetches GET /api/tasks.
Shows: task list grouped by tag (misc, content, dev, etc.).
Add task inline via POST /api/tasks.
- name: InboxList
type: component
domain: TASKS
notes: >
React island. Fetches GET /api/inbox.
Shows: unprocessed items from iOS Shortcuts.
Triage actions: tag + move to tasks, or dismiss.
# LIFEOS
- name: LifeOSPanel
type: component
domain: LIFEOS
notes: >
React island. Connects to LifeOS Supabase project.
Shows: habits, goals, check-ins, streaks.
Kill-switched until LifeOS Supabase connection is live.
Acts as primary LifeOS interface before mobile app ships.
# ─── Connections Planned ─────────────────────────────────────────────────────
connections_planned:
# Auth gate
- from: DashboardLayout
to: AuthGuard
type: depends_on
# Forge panels → API client
- from: ForgeStatusPanel
to: ForgeAPIClient
type: depends_on
- from: ForgeDiffPanel
to: ForgeAPIClient
type: depends_on
- from: ForgePacketPanel
to: ForgeAPIClient
type: depends_on
- from: ForgeAnnotationFeed
to: ForgeAPIClient
type: depends_on
- from: ForgeGraphView
to: ForgeAPIClient
type: depends_on
# API client → forge-denv (external, via tunnel)
- from: ForgeAPIClient
to: forge-denv-http-api
type: depends_on
notes: External service. Offline-tolerant.
# Screens → components
- from: ForgeStatusScreen
to: ForgeStatusPanel
type: routes_to
- from: ForgeStatusScreen
to: ForgeDiffPanel
type: routes_to
- from: ForgeStatusScreen
to: ForgePacketPanel
type: routes_to
- from: ForgeProjectScreen
to: ForgeAnnotationFeed
type: routes_to
- from: ForgeProjectScreen
to: ForgeGraphView
type: routes_to
- from: TasksScreen
to: TaskList
type: routes_to
- from: InboxScreen
to: InboxList
type: routes_to
- from: LifeOSScreen
to: LifeOSPanel
type: routes_to
# Offline degradation
- from: ForgeAPIClient
to: OfflineState
type: emits
notes: emits when forge-denv unreachable
# ─── External Services ────────────────────────────────────────────────────────
external_services:
- name: forge-denv-http-api
url_env: PUBLIC_FORGE_API_URL
notes: >
forge-denv local server exposed via Cloudflare Tunnel.
Set in Vercel env vars. Not always-on — requires Mac + tunnel running.
auth:
outer: Cloudflare Zero Trust Access (owner email only)
inner: X-Forge-Token header from .secrets/forge-denv/.env
- name: lifeos-supabase
notes: >
LifeOS Supabase project. Connected only when lifeos_integration
kill-switch is enabled.
status: planned
# ─── Infrastructure ──────────────────────────────────────────────────────────
infrastructure:
tunnel:
tool: cloudflare-tunnel
tunnel_name: forge-local
local_port: 7890
subdomain: forge.yourdomain.com # replace with actual domain
always_on: launchd # plist starts cloudflared on Mac login
setup_steps:
- brew install cloudflare/cloudflare/cloudflared
- cloudflared tunnel login
- cloudflared tunnel create forge-local
- cloudflared tunnel route dns forge-local forge.yourdomain.com
- create ~/.cloudflared/config.yaml (ingress → localhost:7890)
- Cloudflare Zero Trust → Access → add application on subdomain
- cloudflared service install (launchd, starts on login)
ios_shortcuts:
- name: Add Task
action: POST forge-denv /api/tasks
payload: "{title, tags}"
notes: Replaces Obsidian for capturing misc tasks from phone.
- name: Start Forge
action: open https://forge.yourdomain.com/dashboard
notes: Tunnel already running via launchd — just opens the URL.
# ─── Slot Order (generation sequence) ────────────────────────────────────────
slot_order:
# Foundation first
- AuthGuard # auth primitives must exist before any page
- DashboardLayout # shell wraps everything
- DashboardNav # nav inside shell
- OfflineState # needed by all API-dependent components
- ForgeAPIClient # shared fetch — all panels depend on it
# Forge panels (highest priority — core use case)
- ForgeStatusPanel
- ForgeDiffPanel
- ForgePacketPanel
- ForgeAnnotationFeed
# Screens (after their components exist)
- ForgeStatusScreen
- ForgeProjectScreen
# Tasks
- TaskList
- InboxList
- TasksScreen
- InboxScreen
# LifeOS (kill-switched, do last)
- LifeOSPanel
- LifeOSScreen
# Deferred
- ForgeGraphView # lower priority, do after core panels work
# ─── Config Keys ─────────────────────────────────────────────────────────────
config_keys:
# Vercel env vars (PUBLIC_ prefix = client-accessible in Astro)
- key: PUBLIC_FORGE_API_URL
example: https://forge.yourdomain.com/api
notes: Set in Vercel project settings. Never hardcoded.
# forge-denv secrets (local only)
- key: FORGE_TOKEN
path: ~/Projects/.secrets/forge-denv/.env
notes: Inner auth token. Sent as X-Forge-Token header from Astro.
# ─── Annotations Cross-Ref ───────────────────────────────────────────────────
annotations:
- ANNOT-354: forge-denv HTTP API surface (forge project)
- ANNOT-355: CLAUDE.md + forge_orient routing enforcement (forge)
- ANNOT-356: Execution graph feedback loop gap (forge)
- ANNOT-357: forge-denv Cloudflare tunnel + Astro integration (forge)
- ANNOT-358: LifeOS web interface + misc tasks hub (forge)
← All notes