Dashboard Organization

Dashboard Organization

The dashboard/ directory contains a single Next.js 16 application that hosts multiple skill dashboards. Each skill’s UI is isolated using route groups and component subfolders.

Directory Structure

dashboard/src/
├── app/
│   ├── layout.tsx                    ← minimal root (fonts, dark mode)
│   ├── globals.css
│   │
│   ├── (jobhunt)/                    ← route group (not in URL)
│   │   ├── layout.tsx                ← jobhunt metadata
│   │   ├── page.tsx                  ← URL: /
│   │   ├── position/[id]/page.tsx    ← URL: /position/:id
│   │   └── collection/[id]/page.tsx  ← URL: /collection/:id
│   │
│   └── api/
│       ├── jobhunt/                  ← jobhunt API routes
│           ├── pipeline/route.ts
│           ├── position/[id]/route.ts
│           └── ...
│
├── components/
│   ├── ui/                           ← shared shadcn/ui primitives
│   ├── jobhunt/                      ← jobhunt-specific components
│       ├── pipeline-board.tsx
│       ├── skills-matrix.tsx
│       ├── stats-overview.tsx
│       ├── learning-plan.tsx
│       └── candidates-table.tsx
│
└── lib/
    ├── jobhunt.ts                    ← jobhunt CLI wrapper
    └── utils.ts                      ← shared utilities

Key Concepts

Route Groups

Folders wrapped in parentheses like (jobhunt) are Next.js route groups. They organize files without affecting the URL. This lets each skill dashboard have its own layout.tsx with separate metadata (browser tab title, description) while sharing the same root layout for fonts and global styles.

Route Group Layout Metadata URL Prefix
(jobhunt) “Job Hunt Dashboard | Skillful-Alhazen” / (root)

Three-Layer Pattern

Each dashboard follows the same three-layer pattern:

Browser (React pages)
  → API routes (thin try/catch wrappers)
    → lib/<skill>.ts (calls Python CLI via uv run)
      → TypeDB
  1. lib/<skill>.ts — CLI wrapper that calls uv run python .claude/skills/<skill>/<skill>.py via execFile, parses JSON output
  2. api/<skill>/ — One route per CLI command, thin try/catch returning NextResponse.json()
  3. Pages — React client components using useState/useEffect to fetch from API routes

Component Organization

Components are namespaced by skill under components/:

  • components/ui/ — Shared shadcn/ui primitives (Button, Card, Badge, Table, etc.)
  • components/jobhunt/ — Jobhunt-specific components

If a component is reusable across skills, it belongs in a shared location. Currently all domain components are skill-specific.

Adding a Dashboard for a New Skill

  1. Create the CLI wrappersrc/lib/<skill>.ts
    import { execFile } from 'child_process';
    import { promisify } from 'util';
    import path from 'path';
    
    const execFileAsync = promisify(execFile);
    const PROJECT_ROOT = process.env.PROJECT_ROOT || path.resolve(__dirname, '../../..');
    const SCRIPT = path.join(PROJECT_ROOT, '.claude/skills/<skill>/<skill>.py');
    
    async function runSkill(args: string[]): Promise<unknown> {
      const { stdout } = await execFileAsync(
        'uv', ['run', 'python', SCRIPT, ...args],
        {
          cwd: PROJECT_ROOT,
          maxBuffer: 10 * 1024 * 1024,
          env: { ...process.env, TYPEDB_DATABASE: 'alhazen_notebook' },
        }
      );
      return JSON.parse(stdout);
    }
    
    export async function listItems() {
      return runSkill(['list-items']);
    }
    
  2. Create API routessrc/app/api/<skill>/
    import { NextResponse } from 'next/server';
    import { listItems } from '@/lib/<skill>';
    
    export async function GET() {
      try {
        const data = await listItems();
        return NextResponse.json(data);
      } catch (error) {
        console.error('Error:', error);
        return NextResponse.json({ error: 'Failed' }, { status: 500 });
      }
    }
    
  3. Create route group and pagessrc/app/(<skill>)/
    • layout.tsx — Metadata for the skill dashboard
    • <skill>/page.tsx — Home page at URL /<skill>
    • <skill>/<entity>/[id]/page.tsx — Detail pages
  4. Create componentssrc/components/<skill>/

  5. Verify./node_modules/.bin/next build

Environment Notes

  • Always pass TYPEDB_DATABASE: 'alhazen_notebook' in execFile env (the default in some scripts differs)
  • Build with ./node_modules/.bin/next build (not npm run build which may miss PATH)
  • Tech stack: Next.js 16, shadcn/ui, Tailwind CSS 4, React 19
  • All pages use 'use client' directive (client-side rendering with useState/useEffect)