---
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>
