feat(pitch-admin): structured form editors, bilingual fields, version preview
Some checks failed
CI / nodejs-lint (push) Has been skipped
CI / test-go-consent (push) Successful in 32s
CI / test-python-voice (push) Successful in 32s
CI / test-bqas (push) Successful in 32s
CI / Deploy (push) Failing after 4s
Build pitch-deck / build-and-push (push) Failing after 59s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped

Replaces raw JSON textarea in version editor with proper form UIs:

- Company: single-record form with side-by-side DE/EN tagline + mission
- Team: expandable card list with bilingual role/bio, expertise tags
- Financials: year-by-year table with numeric inputs
- Market: TAM/SAM/SOM row table
- Competitors: card list with strengths/weaknesses tag arrays
- Features: card list with DE/EN names + checkbox matrix
- Milestones: card list with DE/EN title/description + status dropdown
- Metrics: card list with DE/EN labels
- Funding: form + nested use_of_funds table
- Products: card list with DE/EN capabilities + feature tag arrays
- FM Scenarios: card list with color picker
- FM Assumptions: row table

Shared editor primitives (components/pitch-admin/editors/):
  BilingualField, FormField, ArrayField, RowTable, CardList

"Edit as JSON" toggle preserved as escape hatch on every tab.

Preview: admin clicks "Preview" on version editor → opens
/pitch-preview/[versionId] in new tab showing the full pitch deck
with that version's data. Admin-cookie gated (no investor auth).
Yellow "PREVIEW MODE" banner at top.

Also fixes the [object Object] inline table type cast in FM editor.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sharang Parnerkar
2026-04-10 10:34:42 +02:00
parent edadf39445
commit ea752088f6
11 changed files with 915 additions and 92 deletions

View File

@@ -0,0 +1,44 @@
import { NextRequest, NextResponse } from 'next/server'
import pool from '@/lib/db'
import { getAdminFromCookie } from '@/lib/admin-auth'
interface Ctx { params: Promise<{ versionId: string }> }
export async function GET(request: NextRequest, ctx: Ctx) {
// Admin-only: verify admin session
const admin = await getAdminFromCookie()
if (!admin) {
return NextResponse.json({ error: 'Admin access required for preview' }, { status: 401 })
}
const { versionId } = await ctx.params
// Load version data
const { rows } = await pool.query(
`SELECT table_name, data FROM pitch_version_data WHERE version_id = $1`,
[versionId],
)
if (rows.length === 0) {
return NextResponse.json({ error: 'Version not found or has no data' }, { status: 404 })
}
const map: Record<string, unknown[]> = {}
for (const row of rows) {
map[row.table_name] = typeof row.data === 'string' ? JSON.parse(row.data) : row.data
}
// Return PitchData format
return NextResponse.json({
company: (map.company || [])[0] || null,
team: map.team || [],
financials: map.financials || [],
market: map.market || [],
competitors: map.competitors || [],
features: map.features || [],
milestones: map.milestones || [],
metrics: map.metrics || [],
funding: (map.funding || [])[0] || null,
products: map.products || [],
})
}