291 lines
13 KiB
Markdown
291 lines
13 KiB
Markdown
---
|
|
phase: 43-documents-branding
|
|
plan: 03
|
|
type: execute
|
|
wave: 3
|
|
depends_on: ["43-01", "43-02"]
|
|
files_modified:
|
|
- ui/src/components/DocumentGeneratePanel.tsx
|
|
- ui/src/components/BrandKitPanel.tsx
|
|
- ui/src/components/BrandKitResult.tsx
|
|
- ui/src/pages/ContentStudio.tsx
|
|
autonomous: false
|
|
requirements: [DOC-01, DOC-02, DOC-03, BRAND-01, BRAND-02, BRAND-03, BRAND-04, BRAND-05, BRAND-06]
|
|
|
|
must_haves:
|
|
truths:
|
|
- "User can select document type (report, invoice, one-pager, api-docs) and generate a PDF"
|
|
- "Generated PDF can be downloaded from the UI"
|
|
- "User can describe a brand and generate a full brand kit"
|
|
- "Brand kit result shows logo, avatars, social images, signature, letterhead previews"
|
|
- "User can download the entire brand kit as a ZIP file"
|
|
- "ContentStudio has Documents and Brand tabs alongside existing tabs"
|
|
artifacts:
|
|
- path: "ui/src/components/DocumentGeneratePanel.tsx"
|
|
provides: "Document type selection, prompt input, PDF generation trigger, download"
|
|
min_lines: 60
|
|
- path: "ui/src/components/BrandKitPanel.tsx"
|
|
provides: "Brand prompt input, generation trigger, result display"
|
|
min_lines: 50
|
|
- path: "ui/src/components/BrandKitResult.tsx"
|
|
provides: "Brand kit display: logo, avatars, social images, templates, guidelines, ZIP download"
|
|
min_lines: 80
|
|
- path: "ui/src/pages/ContentStudio.tsx"
|
|
provides: "Documents and Brand tabs added"
|
|
contains: "documents"
|
|
key_links:
|
|
- from: "ui/src/components/DocumentGeneratePanel.tsx"
|
|
to: "useContentJob"
|
|
via: "submit('pdf-document', { docType, prompt, title })"
|
|
pattern: "pdf-document"
|
|
- from: "ui/src/components/BrandKitPanel.tsx"
|
|
to: "useContentJob"
|
|
via: "submit('brand-kit', { prompt })"
|
|
pattern: "brand-kit"
|
|
- from: "ui/src/pages/ContentStudio.tsx"
|
|
to: "ui/src/components/DocumentGeneratePanel.tsx"
|
|
via: "import + TabsContent"
|
|
pattern: "DocumentGeneratePanel"
|
|
---
|
|
|
|
<objective>
|
|
UI panels for document generation and brand kit, wired into ContentStudio tabs.
|
|
|
|
Purpose: Give users a UI to generate PDFs (reports, invoices, one-pagers, API docs) and complete brand identity kits from a prompt. Adds "Documents" and "Brand" tabs to ContentStudio.
|
|
Output: DocumentGeneratePanel, BrandKitPanel, BrandKitResult components, updated ContentStudio.
|
|
</objective>
|
|
|
|
<execution_context>
|
|
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
|
|
@$HOME/.claude/get-shit-done/templates/summary.md
|
|
</execution_context>
|
|
|
|
<context>
|
|
@.planning/PROJECT.md
|
|
@.planning/ROADMAP.md
|
|
@.planning/STATE.md
|
|
@.planning/phases/43-documents-branding/43-RESEARCH.md
|
|
@.planning/phases/43-documents-branding/43-01-SUMMARY.md
|
|
@.planning/phases/43-documents-branding/43-02-SUMMARY.md
|
|
|
|
@ui/src/pages/ContentStudio.tsx
|
|
@ui/src/components/SocialPostPanel.tsx
|
|
@ui/src/hooks/useContentJob.ts
|
|
@ui/src/api/contentJobs.ts
|
|
|
|
<interfaces>
|
|
<!-- Key types and patterns the executor needs -->
|
|
|
|
From server/src/services/renderers/types.ts (Plan 01):
|
|
```typescript
|
|
export interface PdfDocumentBundle {
|
|
type: "pdf-document-bundle";
|
|
docType: string;
|
|
title: string;
|
|
pdfBase64: string;
|
|
}
|
|
|
|
export interface BrandKitBundle {
|
|
type: "brand-kit-bundle";
|
|
spec: { name: string; tagline: string; primaryColor: string; secondaryColor: string; fontStyle: string; industry: string; };
|
|
logoSvgBase64: string;
|
|
avatarPngs: Record<string, string>; // "512"|"256"|"128"|"64"|"32" -> base64
|
|
socialImages: Record<string, string>; // "twitter-profile" etc -> base64
|
|
signatureHtml: string;
|
|
letterheadHtml: string;
|
|
guidelinesPdfBase64: string;
|
|
zipBase64: string;
|
|
}
|
|
```
|
|
|
|
From ui/src/hooks/useContentJob.ts:
|
|
```typescript
|
|
export function useContentJob(companyId: string): {
|
|
submit: (jobType: string, input: Record<string, unknown>) => void;
|
|
status: string | null;
|
|
bundle: unknown;
|
|
resultAssetId: string | null;
|
|
error: string | null;
|
|
};
|
|
```
|
|
|
|
From ui/src/api/contentJobs.ts:
|
|
```typescript
|
|
export function getContentJobAsset(companyId: string, assetId: string): Promise<{ url: string }>;
|
|
```
|
|
|
|
UI pattern from SocialPostPanel.tsx:
|
|
- useContentJob for submit + SSE progress
|
|
- When status="done" && resultAssetId && !bundle -> fetch asset -> JSON.parse -> setBundle
|
|
- Display result component
|
|
- Download via URL.createObjectURL + <a>.click()
|
|
</interfaces>
|
|
</context>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto">
|
|
<name>Task 1: Create DocumentGeneratePanel and BrandKitPanel + BrandKitResult components</name>
|
|
<files>ui/src/components/DocumentGeneratePanel.tsx, ui/src/components/BrandKitPanel.tsx, ui/src/components/BrandKitResult.tsx</files>
|
|
<read_first>
|
|
- ui/src/components/SocialPostPanel.tsx (full file — reference pattern for useContentJob, asset fetch, bundle state, download trigger)
|
|
- ui/src/components/SocialPostResult.tsx (result display pattern)
|
|
- ui/src/hooks/useContentJob.ts (hook API)
|
|
- ui/src/api/contentJobs.ts (getContentJobAsset)
|
|
- ui/src/components/WallpaperGeneratePanel.tsx (another panel example for download pattern)
|
|
</read_first>
|
|
<action>
|
|
**DocumentGeneratePanel.tsx:**
|
|
- Props: `{ companyId: string }`
|
|
- State: prompt (string), title (string), docType ("report" | "invoice" | "one-pager" | "api-docs"), bundle (PdfDocumentBundle | null)
|
|
- Define PdfDocumentBundle type locally (same pattern as SocialPostBundle in SocialPostPanel — bundle types are defined locally in panel files per project convention for wallpaper/social, BUT research says to use types.ts for these. Follow research: import is server-side only. Define locally in UI file matching the server shape.)
|
|
- useContentJob(companyId) for submit + status tracking
|
|
- UI layout using shadcn Card, CardHeader, CardContent:
|
|
- Select dropdown for docType with 4 options: Report, Invoice, One-Pager, API Documentation
|
|
- Input for title
|
|
- Textarea for prompt/content description
|
|
- Generate button (disabled when loading, shows Loader2 spinner)
|
|
- Progress bar when status is "running" or "queued"
|
|
- When status="done" && resultAssetId && !bundle: fetch asset via getContentJobAsset, parse JSON, setBundle
|
|
- When bundle exists: show title, docType badge, and a "Download PDF" button
|
|
- Download PDF: decode pdfBase64 -> Uint8Array -> Blob("application/pdf") -> URL.createObjectURL -> <a download="{title}.pdf">.click() -> revokeObjectURL
|
|
|
|
**BrandKitPanel.tsx:**
|
|
- Props: `{ companyId: string }`
|
|
- State: prompt (string), bundle (BrandKitBundle | null)
|
|
- Define BrandKitBundle type locally (matching server shape)
|
|
- useContentJob(companyId) for submit + status
|
|
- UI layout:
|
|
- Textarea for brand description prompt (placeholder: "Describe the brand you want to create -- name, industry, style preferences, colors...")
|
|
- Generate button with loading state
|
|
- Progress bar during generation
|
|
- When done: fetch asset, parse JSON, setBundle, render BrandKitResult
|
|
|
|
**BrandKitResult.tsx:**
|
|
- Props: `{ bundle: BrandKitBundle }`
|
|
- Display in a grid layout:
|
|
- **Logo section**: SVG preview via `<img src="data:image/svg+xml;base64,{logoSvgBase64}" />`
|
|
- **Avatars section**: Grid of 5 avatar sizes as `<img src="data:image/png;base64,{avatarPngs[size]}" />` with size labels
|
|
- **Social images section**: Grid of social platform images with platform name labels
|
|
- **Templates section**: "Email Signature" and "Letterhead" cards with HTML preview in sandboxed iframes (`srcdoc={signatureHtml}`)
|
|
- **Guidelines**: "Brand Guidelines" card with a "Download PDF" button (decode guidelinesPdfBase64 -> blob download)
|
|
- **Full Kit Download**: Prominent "Download Brand Kit (ZIP)" button at the bottom
|
|
- ZIP download function: same base64-to-blob pattern but with type "application/zip" and `.zip` extension (use the downloadZip pattern from RESEARCH.md)
|
|
- PDF download for guidelines: same base64-to-blob pattern with type "application/pdf"
|
|
|
|
Use shadcn components: Card, CardHeader, CardTitle, CardContent, Button, Textarea, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Progress. Import Loader2 from lucide-react.
|
|
</action>
|
|
<acceptance_criteria>
|
|
- grep -q "DocumentGeneratePanel" ui/src/components/DocumentGeneratePanel.tsx
|
|
- grep -q "pdf-document" ui/src/components/DocumentGeneratePanel.tsx
|
|
- grep -q "BrandKitPanel" ui/src/components/BrandKitPanel.tsx
|
|
- grep -q "brand-kit" ui/src/components/BrandKitPanel.tsx
|
|
- grep -q "BrandKitResult" ui/src/components/BrandKitResult.tsx
|
|
- grep -q "zipBase64" ui/src/components/BrandKitResult.tsx
|
|
- grep -q "Download Brand Kit" ui/src/components/BrandKitResult.tsx
|
|
</acceptance_criteria>
|
|
<verify>
|
|
<automated>pnpm --filter @paperclipai/ui exec tsc --noEmit</automated>
|
|
</verify>
|
|
<done>Document and brand kit panels render with correct form inputs, submit correct job types, display results, and provide download functionality for PDF and ZIP.</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 2: Add Documents and Brand tabs to ContentStudio</name>
|
|
<files>ui/src/pages/ContentStudio.tsx</files>
|
|
<read_first>
|
|
- ui/src/pages/ContentStudio.tsx (current tab structure — 5 tabs: diagrams, icons, themes, wallpapers, social)
|
|
</read_first>
|
|
<action>
|
|
1. Add imports at the top of ContentStudio.tsx:
|
|
```typescript
|
|
import { DocumentGeneratePanel } from "../components/DocumentGeneratePanel";
|
|
import { BrandKitPanel } from "../components/BrandKitPanel";
|
|
```
|
|
|
|
2. Add two new TabsTrigger entries in the TabsList, AFTER the "Social" trigger:
|
|
```tsx
|
|
<TabsTrigger value="documents">Documents</TabsTrigger>
|
|
<TabsTrigger value="brand">Brand</TabsTrigger>
|
|
```
|
|
|
|
3. Add two new TabsContent blocks after the social TabsContent:
|
|
```tsx
|
|
<TabsContent value="documents" className="mt-4">
|
|
{companyId ? (
|
|
<DocumentGeneratePanel companyId={companyId} />
|
|
) : (
|
|
<p className="text-sm text-muted-foreground">Select a company to get started.</p>
|
|
)}
|
|
</TabsContent>
|
|
|
|
<TabsContent value="brand" className="mt-4">
|
|
{companyId ? (
|
|
<BrandKitPanel companyId={companyId} />
|
|
) : (
|
|
<p className="text-sm text-muted-foreground">Select a company to get started.</p>
|
|
)}
|
|
</TabsContent>
|
|
```
|
|
|
|
Keep `defaultValue="diagrams"` unchanged. Use stable string values "documents" and "brand" for tab IDs.
|
|
</action>
|
|
<acceptance_criteria>
|
|
- grep -q "DocumentGeneratePanel" ui/src/pages/ContentStudio.tsx
|
|
- grep -q "BrandKitPanel" ui/src/pages/ContentStudio.tsx
|
|
- grep -q '"documents"' ui/src/pages/ContentStudio.tsx
|
|
- grep -q '"brand"' ui/src/pages/ContentStudio.tsx
|
|
</acceptance_criteria>
|
|
<verify>
|
|
<automated>pnpm --filter @paperclipai/ui exec tsc --noEmit</automated>
|
|
</verify>
|
|
<done>ContentStudio has 7 tabs: Diagrams, Icons, Themes, Wallpapers, Social, Documents, Brand. TypeScript compiles cleanly.</done>
|
|
</task>
|
|
|
|
<task type="checkpoint:human-verify" gate="blocking">
|
|
<name>Task 3: Visual verification of Documents and Brand tabs</name>
|
|
<files>ui/src/pages/ContentStudio.tsx</files>
|
|
<action>
|
|
Human verifies the complete document generation and brand kit UI end-to-end.
|
|
|
|
How to verify:
|
|
1. Navigate to Content Studio in the Nexus UI
|
|
2. Verify 7 tabs visible: Diagrams, Icons, Themes, Wallpapers, Social, Documents, Brand
|
|
3. Click "Documents" tab:
|
|
- Select "Report" from dropdown
|
|
- Enter a title and prompt
|
|
- Click Generate — verify spinner/progress appears
|
|
- When done, verify "Download PDF" button appears
|
|
4. Click "Brand" tab:
|
|
- Enter a brand description
|
|
- Click Generate — verify progress appears
|
|
- When done, verify logo SVG preview, avatar grid, social images, template previews, and "Download Brand Kit (ZIP)" button
|
|
5. Download the ZIP — verify it contains logo/, social/, templates/, guidelines.pdf
|
|
|
|
Resume signal: Type "approved" or describe issues.
|
|
</action>
|
|
<verify>
|
|
<automated>pnpm --filter @paperclipai/ui exec tsc --noEmit</automated>
|
|
</verify>
|
|
<done>User confirms Documents and Brand tabs work end-to-end: PDF generation + download, brand kit generation + preview + ZIP download.</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<verification>
|
|
- `pnpm --filter @paperclipai/ui exec tsc --noEmit` compiles without errors
|
|
- ContentStudio renders 7 tabs
|
|
- Document generation flow works end-to-end
|
|
- Brand kit generation shows all asset previews and ZIP download
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
- Documents tab: user can select type, enter prompt, generate PDF, download it
|
|
- Brand tab: user can enter description, generate full brand kit, see all previews, download ZIP
|
|
- All 7 ContentStudio tabs render correctly
|
|
- TypeScript clean
|
|
</success_criteria>
|
|
|
|
<output>
|
|
After completion, create `.planning/phases/43-documents-branding/43-03-SUMMARY.md`
|
|
</output>
|