import { useCallback, useEffect, useState } from 'react' import { Boxes, FileText, Plus } from 'lucide-react' import { toast } from 'sonner' import { AppShell } from '@/components/AppShell' import { MarkdownEditor } from '@/components/MarkdownEditor' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select' import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from '@/components/ui/sheet' import { api } from '@/lib/api' import { useAuth } from '@/store/auth' // A starter PRODUCT.md so an empty product gets useful structure to fill in. const IDENTITY_TEMPLATE = (name: string) => `--- product: ${name} goals: domain: conventions: glossary: --- # About ${name} Describe what this product is, who it serves, and the conventions every agent on it should follow. This identity is shared by every agent across the product's teams. ` interface Division { id: string organizationId: string name: string } interface Product { id: string organizationId: string divisionId: string | null name: string kind: string } interface Team { id: string organizationId: string name: string productId: string | null } const NONE = 'none' /** Define the org structure: divisions → products/services → teams. */ export function StructurePage() { const organizationId = useAuth((s) => s.organizationId) const [divisions, setDivisions] = useState([]) const [products, setProducts] = useState([]) const [teams, setTeams] = useState([]) const [busy, setBusy] = useState(false) const [divisionName, setDivisionName] = useState('') const [product, setProduct] = useState({ name: '', kind: 'Product', divisionId: NONE }) const [team, setTeam] = useState({ name: '', productId: NONE }) const [identity, setIdentity] = useState<{ productId: string; name: string; content: string } | null>(null) const [savingIdentity, setSavingIdentity] = useState(false) const load = useCallback(async () => { if (!organizationId) return try { const [d, p, t] = await Promise.all([ api.get(`/api/orgboard/divisions?organizationId=${organizationId}`), api.get(`/api/orgboard/products?organizationId=${organizationId}`), api.get(`/api/orgboard/teams?organizationId=${organizationId}`), ]) setDivisions(d) setProducts(p) setTeams(t) } catch (err) { toast.error((err as Error).message) } }, [organizationId]) useEffect(() => { void load() }, [load]) const run = async (action: () => Promise) => { setBusy(true) try { await action() await load() } catch (err) { toast.error((err as Error).message) } finally { setBusy(false) } } const addDivision = () => run(async () => { await api.post('/api/orgboard/divisions', { organizationId, name: divisionName }) setDivisionName('') toast.success('Division created.') }) const addProduct = () => run(async () => { await api.post('/api/orgboard/products', { organizationId, name: product.name, kind: product.kind, divisionId: product.divisionId === NONE ? null : product.divisionId, }) setProduct({ name: '', kind: 'Product', divisionId: NONE }) toast.success('Product created.') }) const addTeam = () => run(async () => { await api.post('/api/orgboard/teams', { organizationId, name: team.name, productId: team.productId === NONE ? null : team.productId, }) setTeam({ name: '', productId: NONE }) toast.success('Team created.') }) // Open the product's shared identity (PRODUCT.md) — load current text, or start from the template. const openIdentity = async (p: Product) => { try { const current = await api.get<{ identity: string | null }>(`/api/orgboard/products/${p.id}/identity`) setIdentity({ productId: p.id, name: p.name, content: current.identity ?? IDENTITY_TEMPLATE(p.name) }) } catch (err) { toast.error((err as Error).message) } } const saveIdentity = async () => { if (!identity) return setSavingIdentity(true) try { await api.put(`/api/orgboard/products/${identity.productId}/identity`, { identity: identity.content }) toast.success(`Identity saved for ${identity.name} — every agent on it now shares it.`) setIdentity(null) } catch (err) { toast.error((err as Error).message) } finally { setSavingIdentity(false) } } return (

Structure

The object spine: organization → divisions → products/services → teams.

Divisions Technical, Finance, HR, Sales — the top-level slices.
setDivisionName(e.target.value)} className="w-56" placeholder="Technical" />
{divisions.map((d) => ( {d.name} ))} {divisions.length === 0 &&

No divisions yet — optional, but they unlock the full org chart.

}
Products & services Engineering divisions ship products; other divisions run services.
setProduct({ ...product, name: e.target.value })} className="w-48" placeholder="IPNOPS" />
{products.map((p) => (
{p.name} {p.kind} {p.divisionId ? divisions.find((d) => d.id === p.divisionId)?.name ?? '' : 'no division'}
))} {products.length === 0 &&

No products yet.

}
Teams Teams run delivery. Attach them to a product to complete the spine.
setTeam({ ...team, name: e.target.value })} className="w-48" placeholder="Core team" />
{teams.map((t) => (
{t.name} {t.productId ? products.find((p) => p.id === t.productId)?.name ?? '' : 'directly under the org'}
))} {teams.length === 0 &&

No teams yet.

}
{identity && ( !o && setIdentity(null)}> Product identity — {identity.name} A shared PRODUCT.md (goals, domain, conventions) injected into every agent run on this product, across all its teams. Treated as data, never as instructions.
setIdentity({ ...identity, content })} />
)}
) } function Field({ label, children }: { label: string; children: React.ReactNode }) { return (
{children}
) }