Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 82 additions & 8 deletions app/docs/admin-guide/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export default function AdminGuideDocsPage() {
return (
<DocPage
title="Admin Guide"
subtitle="Managing submissions, the application registry, notes, and the review workflow."
subtitle="Managing submissions, the application registry, notes, and the review workflow during the ClickUp transition."
breadcrumbs={[
{ label: "Docs", href: "/docs" },
{ label: "Admin Guide" },
Expand Down Expand Up @@ -95,16 +95,59 @@ export default function AdminGuideDocsPage() {
</ul>

<h3>Application Lifecycle</h3>
<p>Applications progress through these states:</p>
<p>
The canonical lifecycle is the two-layer taxonomy in{" "}
<a href="https://github.com/ui-insight/AISPEG/blob/main/docs/adr/0001-product-lifecycle-taxonomy.md">
ADR 0001
</a>
: an operational ladder of eleven states plus the <code>tracked</code>{" "}
meta-state, rolling up into six public stages. Each state has a
measurable verification rule enforced by{" "}
<code>npm run verify:portfolio</code> in CI.
</p>
<ul>
<li><strong>idea</strong> — Concept stage, not yet approved</li>
<li><strong>approved</strong> — Approved to proceed (auto-set when promoted)</li>
<li><strong>in-development</strong> — Actively being built</li>
<li><strong>staging</strong> — Deployed to a test environment</li>
<li><strong>production</strong> — Live and serving users</li>
<li><strong>retired</strong> — Decommissioned (excluded from similarity checks)</li>
<li><strong>idea</strong> — named, no owner or sponsor engaged yet</li>
<li><strong>scoping</strong> — named humans engaged, feasibility underway, no formal go decision</li>
<li><strong>approved</strong> — committed to build with named owner and sponsor</li>
<li><strong>building</strong> — under active development</li>
<li><strong>prototype</strong> — demo-able but quiet; feature-complete or dormant</li>
<li><strong>piloting</strong> — in use by a bounded, named cohort</li>
<li><strong>production</strong> — in real institutional use beyond the pilot</li>
<li><strong>maintained</strong> — production, maintenance-only mode</li>
<li><strong>paused</strong> — deliberately on hold; not abandoned</li>
<li><strong>sunsetting</strong> — winding down with a planned successor</li>
<li><strong>archived</strong> — stopped; record kept for institutional memory</li>
<li><strong>tracked</strong> — externally owned; IIDS observes but did not build</li>
</ul>

<InfoBox type="warning" title="The registry form's status list is stale">
<p>
<code>STATUS_OPTIONS</code> in{" "}
<code>app/admin/registry/[id]/page.tsx</code> still offers the legacy
submission states (<code>in-development</code>, <code>staging</code>,{" "}
<code>retired</code>) and the pre-ADR-0001 capitalised union
(<code>Planned</code>, <code>Prototype</code>, <code>Piloting</code>,{" "}
<code>Production</code>, <code>Tracked</code>, <code>Archived</code>).
None of those are members of the current taxonomy.
</p>
<p className="mt-2">
<code>applications.status</code> is plain <code>TEXT</code> with no
CHECK constraint, so such a value writes successfully, and{" "}
<code>publicStageFromStatus()</code> buckets anything unrecognised as{" "}
<em>Exploring</em> so the UI never crashes. The practical effect:
setting a status here can silently misfile a project on{" "}
<code>/portfolio</code>.{" "}
<code>npm run verify:portfolio</code> will not catch it — the verifier
reads <code>lib/portfolio.ts</code>, not the database.
</p>
<p className="mt-2">
<strong>Until that list is fixed, prefer editing{" "}
<code>lib/portfolio.ts</code> and re-seeding</strong> over changing a
status here. Tracked as a follow-up to the July 2026 documentation
audit.
</p>
</InfoBox>

<h3>Registry Detail Page</h3>
<p>
Each registry entry (<code>/admin/registry/[id]</code>) has an editable form for:
Expand All @@ -128,6 +171,37 @@ export default function AdminGuideDocsPage() {
This is useful for existing applications that predate the platform.
</p>

<h2>Where the admin surfaces sit now</h2>
<p>
<code>/admin/*</code> is <strong>transitional</strong>. The source-of-truth
boundary has moved since these pages were built:
</p>
<ul>
<li>
<strong>Project identity and lifecycle</strong> — authored in{" "}
<code>lib/portfolio.ts</code> and seeded into <code>applications</code>{" "}
by <code>npm run seed:portfolio</code>. The seed{" "}
<code>TRUNCATE</code>s, so registry edits made here are{" "}
<strong>overwritten by the next re-seed</strong>.
</li>
<li>
<strong>Project status narrative and ROI</strong> — ClickUp, pulled
read-only into <code>clickup_*</code> tables (ADR 0004). Trigger a
pull with the &ldquo;Sync now&rdquo; button on <code>/internal</code>.
</li>
<li>
<strong>Requests</strong> — the <code>tech_requests</code> registry
(ADR 0005), surfaced publicly at <code>/portfolio/pipeline</code>.
That is the one all-origin queue; there is no internal copy.
</li>
</ul>
<p>
Submissions review — the dashboard, notes, similarity, and promote —
remains the live workflow here, and is what this page is for. ClickUp
write-side (new submissions creating ClickUp tasks) is still future
work; when it lands, <code>/admin/submissions</code> retires.
</p>

<h2>Notes System</h2>
<p>
Notes are simple text entries attached to submissions. Each note has an author name and
Expand Down
75 changes: 73 additions & 2 deletions app/docs/api-reference/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export default function ApiReferenceDocsPage() {
return (
<DocPage
title="API Reference"
subtitle="REST API endpoints for submissions, the application registry, notes, similarity detection, and AI features."
subtitle="REST API endpoints for submissions, the application registry, notes, similarity detection, AI features, the site assistant, and the ClickUp sync trigger."
breadcrumbs={[
{ label: "Docs", href: "/docs" },
{ label: "API Reference" },
Expand Down Expand Up @@ -151,7 +151,7 @@ export default function ApiReferenceDocsPage() {
<Endpoint method="PATCH" path="/api/registry/[id]" description="Update any application fields. Only provided fields are modified.">
<ParamTable params={[
{ name: "name", type: "string?", desc: "Application name" },
{ name: "status", type: "string?", desc: "idea | approved | in-development | staging | production | retired" },
{ name: "status", type: "string?", desc: "An ADR 0001 operational status — idea | scoping | approved | building | prototype | piloting | production | maintained | paused | sunsetting | archived | tracked. The column is plain TEXT with no CHECK, so anything else writes successfully and renders as Exploring. Send one of these." },
{ name: "github_repo", type: "string?", desc: "GitHub repository" },
{ name: "url", type: "string?", desc: "Production URL" },
{ name: "...", type: "...", desc: "Any other application field" },
Expand All @@ -176,7 +176,78 @@ export default function ApiReferenceDocsPage() {
]} />
<p className="text-xs text-gray-500 mt-2">Returns 503 if MINDROUTER_API_KEY is not configured.</p>
</Endpoint>

<Endpoint method="POST" path="/api/ask" description="The site assistant. Runs the tool-using agent loop over read-only site data and returns a cited answer. Backs the floating chat widget on every page. See ADR 0007.">
<ParamTable params={[
{ name: "message", type: "string", desc: "User question. Required; 2000 chars max." },
{ name: "history", type: "array", desc: "Optional prior turns as {role: 'user'|'assistant', content}. Last 20 kept; other roles are dropped." },
]} />
<p className="text-xs text-gray-500 mt-2">
Returns <code>{`{ response, citations[], toolCalls[], iterations, truncated, salvagedToolCalls }`}</code>.
Citations are assembled from the tools&apos; own canonical URLs, never authored by the model.
</p>
<p className="text-xs text-gray-500 mt-1">
Rate limited per IP hash: 60/hour public, 600/hour internal. Over the
limit returns <strong>429</strong> with <code>Retry-After</code>,
<code>X-RateLimit-Limit</code>, and <code>X-RateLimit-Remaining</code>.
Returns 503 with <code>unconfigured: true</code> when
MINDROUTER_API_KEY is unset.
</p>
<p className="text-xs text-gray-500 mt-1">
A MindRouter outage returns <strong>200</strong>, not 500 — the body
carries a friendly fallback message and <code>fallback: true</code> so
the chat widget degrades instead of erroring. Every call is logged to{" "}
<code>agent_queries</code>.
</p>
</Endpoint>
</div>

<h2>Similarity</h2>
<div className="not-prose space-y-4">
<Endpoint method="POST" path="/api/similarity/preview" description="Stateless similarity check against the registry. Takes a partial assessment profile and returns matches without persisting anything — used mid-assessment so a submitter can coordinate before duplicating effort.">
<ParamTable params={[
{ name: "sensitivity", type: "string[]", desc: "Partial wizard answers — all fields optional" },
{ name: "complexity", type: "string", desc: "Static | CRUD | Multi-source | Real-time" },
{ name: "userbase", type: "string", desc: "Team | Department | College | University | External" },
{ name: "auth", type: "string", desc: "None | Password | SSO | RBAC | Multi-tenant" },
{ name: "integrations", type: "string[]", desc: "" },
{ name: "dataSources", type: "string[]", desc: "" },
{ name: "universitySystems", type: "string[]", desc: "" },
{ name: "outputTypes", type: "string[]", desc: "" },
]} />
<p className="text-xs text-gray-500 mt-2">
Distinct from <code>/api/submissions/[id]/similarity</code>, which
persists matches after a real submission. This runs at threshold
<strong> 0.2</strong> rather than 0.3 — deliberately over-notifying and
letting the submitter judge.
</p>
</Endpoint>
</div>

<h2>Operations</h2>
<div className="not-prose space-y-4">
<Endpoint method="POST" path="/internal/sync" description="Trigger a ClickUp ingestion run (ADR 0004). Pulls project status updates, ROI fields, and the scored request backlog into the clickup_* tables.">
<p className="text-xs text-gray-500 mt-2">
Lives under <code>/internal</code> so the Basic-auth proxy covers it.
Used by the &ldquo;Sync now&rdquo; button and by the host cron:
</p>
<pre className="mt-2 rounded-lg bg-gray-900 p-3 text-xs text-green-400 overflow-x-auto">{`curl -s -u "$BASIC_AUTH_USER:$BASIC_AUTH_PASS" -X POST \\
https://aispeg.insight.uidaho.edu/internal/sync`}</pre>
<p className="text-xs text-gray-500 mt-2">
Returns the run summary on success. <strong>503</strong> if
CLICKUP_API_TOKEN is unset; <strong>409</strong> if a sync is already
in flight — a run takes 30–60s of sequential ClickUp calls and
overlapping runs would double-write.
</p>
</Endpoint>
</div>

<InfoBox type="tip" title="Keeping this page honest">
This page drifted badly once already (issue #94): it documented the
registry and submissions endpoints while missing the site assistant, the
similarity preview, and the sync trigger entirely. If you add a route
under <code>app/api/</code>, add it here in the same PR.
</InfoBox>
</DocPage>
);
}
Loading
Loading