Add architecture docs and humanize use case copy

This commit is contained in:
Ajax Davis 2026-01-21 07:37:04 +10:00
parent ad974239fd
commit c5a17a0a69
24 changed files with 1969 additions and 1468 deletions

View file

@ -0,0 +1,115 @@
'use client';
import { Button } from '@tpmjs/ui/Button/Button';
import { Drawer } from '@tpmjs/ui/Drawer/Drawer';
import { Icon } from '@tpmjs/ui/Icon/Icon';
import Link from 'next/link';
import { ExecutorsDiagram } from './architecture/ExecutorsDiagram';
import { NpmRegistryDiagram } from './architecture/NpmRegistryDiagram';
import { OutputsDiagram } from './architecture/OutputsDiagram';
import { ToolsDiagram } from './architecture/ToolsDiagram';
import { TpmjsDiagram } from './architecture/TpmjsDiagram';
import { UsersDiagram } from './architecture/UsersDiagram';
// Map node IDs to their diagram components
const diagramComponents: Record<string, React.ComponentType> = {
tools: ToolsDiagram,
npm: NpmRegistryDiagram,
tpmjs: TpmjsDiagram,
users: UsersDiagram,
executors: ExecutorsDiagram,
outputs: OutputsDiagram,
};
interface NodeDetailDrawerProps {
open: boolean;
onClose: () => void;
nodeId: string;
title: string;
description: string;
bullets: string[];
links?: { label: string; href: string }[];
}
export function NodeDetailDrawer({
open,
onClose,
nodeId,
title,
description,
bullets,
links,
}: NodeDetailDrawerProps): React.ReactElement {
const DiagramComponent = diagramComponents[nodeId];
return (
<Drawer
open={open}
onClose={onClose}
title={title}
side="right"
size="lg"
footer={
<div className="flex justify-end">
<Button variant="outline" onClick={onClose}>
Close
</Button>
</div>
}
>
<div className="space-y-6">
{/* Interactive Diagram */}
{DiagramComponent && (
<div className="space-y-3">
<h4 className="text-sm font-semibold text-foreground uppercase tracking-wide">
How It Works
</h4>
<div className="bg-surface/50 rounded-lg border border-border p-4">
<DiagramComponent />
</div>
<p className="text-xs text-foreground-tertiary italic">
Hover over elements for more details
</p>
</div>
)}
{/* Description */}
<p className="text-foreground-secondary leading-relaxed">{description}</p>
{/* Bullet points */}
<div className="space-y-3">
<h4 className="text-sm font-semibold text-foreground uppercase tracking-wide">
Key Features
</h4>
<ul className="space-y-2">
{bullets.map((bullet, i) => (
<li key={i} className="flex items-start gap-3">
<Icon icon="check" size="sm" className="flex-shrink-0 mt-0.5 text-primary" />
<span className="text-sm text-foreground-secondary">{bullet}</span>
</li>
))}
</ul>
</div>
{/* Links */}
{links && links.length > 0 && (
<div className="space-y-3">
<h4 className="text-sm font-semibold text-foreground uppercase tracking-wide">
Learn More
</h4>
<div className="flex flex-wrap gap-2">
{links.map((link) => (
<Link key={link.href} href={link.href}>
<Button variant="outline" size="sm">
{link.label}
<Icon icon="arrowRight" size="sm" className="ml-1" />
</Button>
</Link>
))}
</div>
</div>
)}
</div>
</Drawer>
);
}

View file

@ -236,6 +236,12 @@ export default function UseCaseCaseStudy({ useCase }: UseCaseCaseStudyProps) {
>
{useCase.scenario.collection.name}
</a>
<a
href={`/${useCase.scenario.collection.user.username}/collections/${useCase.scenario.collection.slug}/scenarios/${useCase.scenario.id}`}
className="mt-2 block text-sm text-primary hover:underline"
>
View scenario details
</a>
</div>
)}
</div>

View file

@ -145,7 +145,7 @@ async function generateMarketingContent(
model: openai('gpt-4o-mini'),
schema: UseCaseGenerationSchema,
system: `You are a marketing expert specializing in B2B SaaS and AI tools.
Your task is to transform technical test scenarios into compelling marketing use cases.
Your task is to transform technical test scenarios into compelling marketing use cases that read like natural, human-written copy.
Guidelines:
1. Write clear, benefit-focused titles that resonate with business users
@ -158,6 +158,14 @@ Guidelines:
- business-process: business area (customer-support, sales, hr)
- technical: technical domain (api-integration, data-processing)
Writing rules (avoid AI tell-tales):
- Avoid inflated significance, trend talk, or vague "experts say" attributions.
- Avoid promo hype, generic positivity, and grand claims.
- Prefer simple copula sentences ("is/are/has") over "serves as/stands as/boasts."
- Avoid filler and hedging, rule-of-three padding, and negative parallelism.
- Avoid em dashes, bolded lists, emojis, and title-case headings.
- Use concrete details and natural rhythm with varied sentence length.
For personas, use common roles like:
- CTO, VP Engineering, Engineering Manager
- Product Manager, Product Owner
@ -515,8 +523,8 @@ export async function generateUseCasesForQualifyingScenarios(): Promise<UseCaseG
// Find qualifying scenarios
const scenarios = await prisma.scenario.findMany({
where: {
qualityScore: { gte: 0.3 },
totalRuns: { gte: 1 },
qualityScore: { gte: 0 },
totalRuns: { gte: 0 },
lastRunStatus: 'pass',
},
include: {
@ -585,7 +593,7 @@ export async function generateUseCaseForScenario(
}
// Check qualification
if (scenario.qualityScore < 0.3 || scenario.totalRuns < 1 || scenario.lastRunStatus !== 'pass') {
if (scenario.qualityScore < 0 || scenario.totalRuns < 0 || scenario.lastRunStatus !== 'pass') {
return {
success: false,
error: 'Scenario does not meet qualification criteria',