Add architecture docs and humanize use case copy
This commit is contained in:
parent
ad974239fd
commit
c5a17a0a69
24 changed files with 1969 additions and 1468 deletions
115
apps/web/src/components/NodeDetailDrawer.tsx
Normal file
115
apps/web/src/components/NodeDetailDrawer.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue