7a5f1e48dd
[migration-approved]
Templates (Migrations 123-136):
- 123 GO-GF (Geschäftsordnung Geschäftsführung)
- 124 SHA (Shareholders' Agreement, 56 Platzhalter)
- 125 Satzung (Articles of Association mit UG-Variante)
- 126 GF-Dienstvertrag (Trennungsprinzip Organ/Anstellung)
- 127 Arbeitsvertrag (AGG-neutral, NachwG, eAU)
- 128 Gesellschafterliste (§ 40 GmbHG)
- 129 GF-Bestellungsbeschluss (mit § 6 Abs. 2 Versicherung)
- 130 HRB-Anmeldung (§§ 7, 8, 39 GmbHG, § 12 HGB)
- 131 IP-Assignment Agreement (Gründer→GmbH)
- 132 Term Sheet (Pre-Seed/Seed VC-Standard)
- 133 Wandeldarlehensvertrag (Convertible Loan)
- 134 Beteiligungsvertrag (Subscription Agreement)
- 135 ESOP/VSOP-Plan (3 Varianten)
- 136 Cap Table
Kategorisierung (Migrations 137-138):
- ALTER TABLE compliance_legal_templates ADD lifecycle_stage TEXT[],
functional_category TEXT (mit CHECK Constraints + GIN-Index)
- Backfill aller 105 Templates: lifecycle_stage (pre_founding|founding|
startup|kmu|konzern) + functional_category (founding_legal|employment|
investor_funding|...)
Backend Founding-Wizard Service:
- template_renderer.py: Handlebars-light ({{VAR}}, {{#IF FLAG}}...{{/IF}})
- wizard_to_context.py: Mapping Wizard-State → SCREAMING_SNAKE_CASE Vars
- markdown_to_docx.py: Markdown → DOCX via python-docx
- founding_wizard_routes.py: POST /v1/founding-wizard/generate
→ liefert base64-DOCX-Files für ausgewählte Templates
Frontend Founding-Wizard (/sdk/founding-wizard):
- 8-Step Wizard (Basics, Gesellschafter, GF, Kapital, Notar, SHA, GF-Verträge, Generate)
- useFoundingWizardForm Hook mit localStorage-Persistenz
- TypeScript Code-Registry (template-categories.ts) als Backup zur DB
- Word-Download via data:URLs (base64)
Tests:
- 20 Unit-Tests grün (Renderer, Context-Mapping, DOCX-Conversion)
- Playwright E2E-Test mit 2-Mann GmbH (Benjamin + Sharang) Test-Daten
126 lines
4.7 KiB
TypeScript
126 lines
4.7 KiB
TypeScript
'use client'
|
|
|
|
import type { FoundingWizardState } from '@/lib/sdk/founding/types'
|
|
|
|
interface Props {
|
|
state: FoundingWizardState
|
|
update: <K extends keyof FoundingWizardState>(k: K, v: FoundingWizardState[K]) => void
|
|
}
|
|
|
|
export function StepBasics({ state, update }: Props) {
|
|
const b = state.basics
|
|
return (
|
|
<div className="space-y-4">
|
|
<div className="grid grid-cols-2 gap-4">
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">Firmenname</label>
|
|
<input
|
|
data-testid="company-name"
|
|
type="text"
|
|
value={b.company_name}
|
|
onChange={e => update('basics', { ...b, company_name: e.target.value })}
|
|
placeholder="Breakpilot GmbH"
|
|
className="w-full px-3 py-2 border rounded-lg"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">Rechtsform</label>
|
|
<select
|
|
data-testid="legal-form"
|
|
value={b.legal_form}
|
|
onChange={e => update('basics', { ...b, legal_form: e.target.value as 'GmbH' | 'UG' })}
|
|
className="w-full px-3 py-2 border rounded-lg"
|
|
>
|
|
<option value="GmbH">GmbH</option>
|
|
<option value="UG">UG (haftungsbeschränkt)</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">Sitz (Stadt)</label>
|
|
<input
|
|
data-testid="company-seat"
|
|
type="text"
|
|
value={b.company_seat}
|
|
onChange={e => update('basics', { ...b, company_seat: e.target.value })}
|
|
placeholder="z.B. Stuttgart"
|
|
className="w-full px-3 py-2 border rounded-lg"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">Adresse</label>
|
|
<input
|
|
data-testid="company-address"
|
|
type="text"
|
|
value={b.company_address}
|
|
onChange={e => update('basics', { ...b, company_address: e.target.value })}
|
|
placeholder="Straße, PLZ Ort"
|
|
className="w-full px-3 py-2 border rounded-lg"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">Branche</label>
|
|
<input
|
|
data-testid="industry"
|
|
type="text"
|
|
value={b.industry}
|
|
onChange={e => update('basics', { ...b, industry: e.target.value })}
|
|
placeholder="z.B. SaaS, Beratung, Handwerk"
|
|
className="w-full px-3 py-2 border rounded-lg"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">Geschäftsjahr</label>
|
|
<input
|
|
data-testid="business-year"
|
|
type="text"
|
|
value={b.business_year}
|
|
onChange={e => update('basics', { ...b, business_year: e.target.value })}
|
|
className="w-full px-3 py-2 border rounded-lg"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
Unternehmensgegenstand (Volltext für § 2 Satzung)
|
|
</label>
|
|
<textarea
|
|
data-testid="company-purpose"
|
|
value={b.company_purpose_description}
|
|
onChange={e => update('basics', { ...b, company_purpose_description: e.target.value })}
|
|
rows={4}
|
|
placeholder="z.B. die Entwicklung, Bereitstellung, der Betrieb und der Vertrieb von Softwarelösungen, Plattformen und IT-Dienstleistungen im Bereich der Künstlichen Intelligenz"
|
|
className="w-full px-3 py-2 border rounded-lg"
|
|
/>
|
|
</div>
|
|
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
Detaillierte Tätigkeitsbereiche (eine Zeile pro Bullet)
|
|
</label>
|
|
<textarea
|
|
data-testid="company-purpose-bullets"
|
|
value={b.company_purpose_bullets.join('\n')}
|
|
onChange={e => update('basics', { ...b, company_purpose_bullets: e.target.value.split('\n').filter(Boolean) })}
|
|
rows={5}
|
|
placeholder={'a) Entwicklung von Software\nb) Beratung im Bereich...\nc) ...'}
|
|
className="w-full px-3 py-2 border rounded-lg font-mono text-sm"
|
|
/>
|
|
</div>
|
|
|
|
<div className="flex items-center gap-2">
|
|
<input
|
|
type="checkbox"
|
|
id="research_focus"
|
|
data-testid="research-focus"
|
|
checked={b.has_research_focus}
|
|
onChange={e => update('basics', { ...b, has_research_focus: e.target.checked })}
|
|
/>
|
|
<label htmlFor="research_focus" className="text-sm text-gray-700">
|
|
Forschungsfokus (aktiviert F&E-Klauseln in SHA und GO-GF)
|
|
</label>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|