feat: Template-Spec v1 Phase C — IF-Renderer + HOSTING/FEATURES + 4 neue DE-Templates
All checks were successful
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-ai-compliance (push) Successful in 36s
CI / test-python-backend-compliance (push) Successful in 32s
CI / test-python-document-crawler (push) Successful in 22s
CI / test-python-dsms-gateway (push) Successful in 18s

- contextBridge.ts: HostingCtx + FeaturesCtx (35 Felder), ~50 neue Platzhalter-Aliases
- ruleEngine.ts: buildBoolContext() + applyConditionalBlocks() (IF/IF_NOT/IF_ANY)
- ruleEngine.test.ts: 67 Tests (+18 für Phase C), alle grün
- page.tsx: IF-Renderer in Pipeline, HOSTING+FEATURES Formular-Sections, erweiterter SDK-Prefill
- scripts/apply_templates_023.py: 4 neue DE-Templates (Cookie v2, DSE, AGB, Impressum)
- migrations/023_new_templates_de.sql: Dokumentation + Verifikations-Query

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-03-04 14:35:56 +01:00
parent 7f3bf93cd6
commit e0f7f2134e
6 changed files with 1208 additions and 10 deletions

View File

@@ -112,6 +112,61 @@ export interface ConsentCtx {
MARKETING_PARTNERS: string | null
}
export interface HostingCtx {
PROVIDER_NAME: string
COUNTRY: string
CONTRACT_TYPE: string // e.g. "AVV nach Art. 28 DSGVO"
}
export interface FeaturesCtx {
// ── Impressum ──────────────────────────────────────────────────────────────
HAS_REGULATED_PROFESSION: boolean
REGULATED_PROFESSION_TEXT: string
HAS_EDITORIAL_RESPONSIBLE: boolean
EDITORIAL_RESPONSIBLE_NAME: string
EDITORIAL_RESPONSIBLE_ADDRESS: string
HAS_DISPUTE_RESOLUTION: boolean
DISPUTE_RESOLUTION_TEXT: string
// ── DSI / Datenschutzerklärung ─────────────────────────────────────────────
HAS_THIRD_COUNTRY: boolean
TRANSFER_GUARDS: string // e.g. "EU-Standardvertragsklauseln (SCC)"
SECURITY_MEASURES_SUMMARY: string // e.g. "TLS, RBAC, Backups, Logging"
DATA_SUBJECT_REQUEST_CHANNEL: string // e.g. "per E-Mail an {{CONTACT_EMAIL}}"
CONSENT_WITHDRAWAL_PATH: string // e.g. "Footer-Link Cookie-Einstellungen"
// ── Service-Features (DSI/AGB) ─────────────────────────────────────────────
HAS_NEWSLETTER: boolean
NEWSLETTER_PROVIDER_DETAIL: string
HAS_ACCOUNT: boolean
HAS_PAYMENTS: boolean
PAYMENT_PROVIDER_DETAIL: string
HAS_SUPPORT: boolean
HAS_SOCIAL_MEDIA: boolean
SOCIAL_MEDIA_DETAIL: string
// ── Tool-Details (DSI + Cookie Banner) ────────────────────────────────────
ANALYTICS_TOOLS_DETAIL: string
MARKETING_TOOLS_DETAIL: string
CMP_NAME: string
CMP_LOGS_CONSENTS: boolean
HAS_FUNCTIONAL_COOKIES: boolean
// ── AGB (SaaS) ────────────────────────────────────────────────────────────
HAS_PAID_PLANS: boolean
PRICES_TEXT: string
PAYMENT_TERMS_TEXT: string
CONTRACT_TERM_TEXT: string
HAS_SLA: boolean
SLA_URL: string
HAS_EXPORT_POLICY: boolean
EXPORT_POLICY_TEXT: string
LIMITATION_CAP_TEXT: string
HAS_WITHDRAWAL: boolean
CONSUMER_WITHDRAWAL_TEXT: string
SUPPORT_CHANNELS_TEXT: string
}
export interface TemplateContext {
PROVIDER: ProviderCtx
CUSTOMER: CustomerCtx
@@ -123,6 +178,8 @@ export interface TemplateContext {
SECURITY: SecurityCtx
NDA: NDACtx
CONSENT: ConsentCtx
HOSTING: HostingCtx
FEATURES: FeaturesCtx
}
export interface ComputedFlags {
@@ -180,6 +237,32 @@ export const EMPTY_CONTEXT: TemplateContext = {
},
NDA: { PURPOSE: '', DURATION_YEARS: 5, PENALTY_AMOUNT_EUR: null },
CONSENT: { WEBSITE_NAME: '', ANALYTICS_TOOLS: null, MARKETING_PARTNERS: null },
HOSTING: {
PROVIDER_NAME: '', COUNTRY: 'Deutschland', CONTRACT_TYPE: 'AVV nach Art. 28 DSGVO',
},
FEATURES: {
// Impressum
HAS_REGULATED_PROFESSION: false, REGULATED_PROFESSION_TEXT: '',
HAS_EDITORIAL_RESPONSIBLE: false, EDITORIAL_RESPONSIBLE_NAME: '', EDITORIAL_RESPONSIBLE_ADDRESS: '',
HAS_DISPUTE_RESOLUTION: false, DISPUTE_RESOLUTION_TEXT: '',
// DSI
HAS_THIRD_COUNTRY: false, TRANSFER_GUARDS: 'EU-Standardvertragsklauseln (SCC)',
SECURITY_MEASURES_SUMMARY: 'TLS 1.3, RBAC, Verschlüsselung at rest, regelmäßige Backups, Logging',
DATA_SUBJECT_REQUEST_CHANNEL: 'per E-Mail', CONSENT_WITHDRAWAL_PATH: 'Footer-Link „Cookie-Einstellungen"',
// Service features
HAS_NEWSLETTER: false, NEWSLETTER_PROVIDER_DETAIL: '',
HAS_ACCOUNT: false, HAS_PAYMENTS: false, PAYMENT_PROVIDER_DETAIL: '',
HAS_SUPPORT: false, HAS_SOCIAL_MEDIA: false, SOCIAL_MEDIA_DETAIL: '',
// Tools
ANALYTICS_TOOLS_DETAIL: '', MARKETING_TOOLS_DETAIL: '',
CMP_NAME: '', CMP_LOGS_CONSENTS: false, HAS_FUNCTIONAL_COOKIES: false,
// AGB
HAS_PAID_PLANS: false, PRICES_TEXT: '', PAYMENT_TERMS_TEXT: '',
CONTRACT_TERM_TEXT: '', HAS_SLA: false, SLA_URL: '',
HAS_EXPORT_POLICY: false, EXPORT_POLICY_TEXT: '',
LIMITATION_CAP_TEXT: '', HAS_WITHDRAWAL: false, CONSUMER_WITHDRAWAL_TEXT: '',
SUPPORT_CHANNELS_TEXT: '',
},
}
// =============================================================================
@@ -213,6 +296,8 @@ export function contextToPlaceholders(ctx: TemplateContext): Record<string, stri
const sec = ctx.SECURITY
const nda = ctx.NDA
const con = ctx.CONSENT
const h = ctx.HOSTING
const f = ctx.FEATURES
const address = providerAddress(p)
@@ -298,6 +383,57 @@ export function contextToPlaceholders(ctx: TemplateContext): Record<string, stri
'{{WEBSITE_NAME}}': con.WEBSITE_NAME || str(p.WEBSITE_URL),
'{{ANALYTICS_TOOLS}}': str(con.ANALYTICS_TOOLS),
'{{MARKETING_PARTNERS}}': str(con.MARKETING_PARTNERS),
// --- ALIASES (canonical names from new templates) ---
'{{COMPANY_LEGAL_NAME}}': str(p.LEGAL_NAME),
'{{COMPANY_LEGAL_FORM}}': str(p.LEGAL_FORM),
'{{COMPANY_ADDRESS_LINE}}': str(p.ADDRESS_LINE),
'{{COMPANY_POSTAL_CODE}}': str(p.POSTAL_CODE),
'{{COMPANY_CITY}}': str(p.CITY),
'{{COMPANY_COUNTRY}}': str(p.COUNTRY),
'{{COMPANY_ADDRESS_FULL}}': [p.ADDRESS_LINE, [p.POSTAL_CODE, p.CITY].filter(Boolean).join(' '), p.COUNTRY].filter(Boolean).join(', '),
'{{WEBSITE_URL}}': str(p.WEBSITE_URL),
'{{CONTACT_PHONE}}': str(p.PHONE),
'{{REPRESENTED_BY_NAME}}': str(p.CEO_NAME),
'{{REGISTER_COURT}}': str(p.REGISTER_COURT),
'{{REGISTER_NUMBER}}': str(p.REGISTER_NUMBER),
'{{VAT_ID}}': str(p.VAT_ID),
'{{SERVICE_DESCRIPTION_SHORT}}': str(s.DESCRIPTION),
'{{NOTICE_PERIOD_DAYS}}': str(s.TERMINATION_NOTICE_DAYS),
'{{ANALYTICS_TOOLS_LIST}}': str(con.ANALYTICS_TOOLS),
'{{MARKETING_PARTNERS_LIST}}': str(con.MARKETING_PARTNERS),
'{{DATA_PROCESSING_LOCATIONS}}': str(s.DATA_LOCATION),
'{{SUPERVISORY_AUTHORITY_NAME}}': str(prv.SUPERVISORY_AUTHORITY_NAME),
'{{SUPERVISORY_AUTHORITY_ADDRESS}}': str(prv.SUPERVISORY_AUTHORITY_ADDRESS),
// --- HOSTING ---
'{{HOSTING_PROVIDER_NAME}}': str(h.PROVIDER_NAME),
'{{HOSTING_PROVIDER_COUNTRY}}': str(h.COUNTRY),
'{{HOSTING_PROVIDER_CONTRACT_TYPE}}': str(h.CONTRACT_TYPE),
// --- FEATURES (text fields) ---
'{{CONSENT_WITHDRAWAL_PATH}}': str(f.CONSENT_WITHDRAWAL_PATH),
'{{SECURITY_MEASURES_SUMMARY}}': str(f.SECURITY_MEASURES_SUMMARY),
'{{DATA_SUBJECT_REQUEST_CHANNEL}}': str(f.DATA_SUBJECT_REQUEST_CHANNEL),
'{{TRANSFER_GUARDS}}': str(f.TRANSFER_GUARDS),
'{{REGULATED_PROFESSION_TEXT}}': str(f.REGULATED_PROFESSION_TEXT),
'{{EDITORIAL_RESPONSIBLE_NAME}}': str(f.EDITORIAL_RESPONSIBLE_NAME),
'{{EDITORIAL_RESPONSIBLE_ADDRESS}}': str(f.EDITORIAL_RESPONSIBLE_ADDRESS),
'{{DISPUTE_RESOLUTION_TEXT}}': str(f.DISPUTE_RESOLUTION_TEXT),
'{{NEWSLETTER_PROVIDER_DETAIL}}': str(f.NEWSLETTER_PROVIDER_DETAIL),
'{{PAYMENT_PROVIDER_DETAIL}}': str(f.PAYMENT_PROVIDER_DETAIL),
'{{SOCIAL_MEDIA_DETAIL}}': str(f.SOCIAL_MEDIA_DETAIL),
'{{ANALYTICS_TOOLS_DETAIL}}': str(f.ANALYTICS_TOOLS_DETAIL),
'{{MARKETING_TOOLS_DETAIL}}': str(f.MARKETING_TOOLS_DETAIL),
'{{CMP_NAME}}': str(f.CMP_NAME),
'{{PRICES_TEXT}}': str(f.PRICES_TEXT),
'{{PAYMENT_TERMS_TEXT}}': str(f.PAYMENT_TERMS_TEXT),
'{{CONTRACT_TERM_TEXT}}': str(f.CONTRACT_TERM_TEXT),
'{{SLA_URL}}': str(f.SLA_URL),
'{{EXPORT_POLICY_TEXT}}': str(f.EXPORT_POLICY_TEXT),
'{{LIMITATION_CAP_TEXT}}': str(f.LIMITATION_CAP_TEXT),
'{{CONSUMER_WITHDRAWAL_TEXT}}': str(f.CONSUMER_WITHDRAWAL_TEXT),
'{{SUPPORT_CHANNELS_TEXT}}': str(f.SUPPORT_CHANNELS_TEXT),
}
}
@@ -323,16 +459,18 @@ export function computeFlags(ctx: TemplateContext): ComputedFlags {
/** All placeholder patterns covered by each context section */
const SECTION_COVERS: Record<keyof TemplateContext, string[]> = {
PROVIDER: ['{{COMPANY_NAME}}', '{{PROVIDER_NAME}}', '{{DISCLOSING_PARTY}}', '{{SERVICE_PROVIDER}}', '{{COMPANY_ADDRESS}}', '{{PROVIDER_ADDRESS}}', '{{CONTACT_EMAIL}}', '{{PROVIDER_EMAIL}}', '{{ABUSE_EMAIL}}', '{{REPORT_EMAIL}}'],
PROVIDER: ['{{COMPANY_NAME}}', '{{PROVIDER_NAME}}', '{{DISCLOSING_PARTY}}', '{{SERVICE_PROVIDER}}', '{{COMPANY_ADDRESS}}', '{{PROVIDER_ADDRESS}}', '{{CONTACT_EMAIL}}', '{{PROVIDER_EMAIL}}', '{{ABUSE_EMAIL}}', '{{REPORT_EMAIL}}', '{{COMPANY_LEGAL_NAME}}', '{{COMPANY_LEGAL_FORM}}', '{{COMPANY_ADDRESS_LINE}}', '{{COMPANY_POSTAL_CODE}}', '{{COMPANY_CITY}}', '{{COMPANY_COUNTRY}}', '{{COMPANY_ADDRESS_FULL}}', '{{WEBSITE_URL}}', '{{CONTACT_PHONE}}', '{{REPRESENTED_BY_NAME}}', '{{REGISTER_COURT}}', '{{REGISTER_NUMBER}}', '{{VAT_ID}}'],
CUSTOMER: ['{{CUSTOMER_NAME}}', '{{RECEIVING_PARTY}}', '{{CUSTOMER}}'],
SERVICE: ['{{SERVICE_NAME}}', '{{PLATFORM_NAME}}', '{{SERVICE_DESCRIPTION}}', '{{SERVICE_MODEL}}', '{{SERVICE_TIER}}', '{{DATA_LOCATION}}', '{{EXPORT_FORMATS}}', '{{EXPORT_WINDOW_DAYS}}', '{{MIN_TERM_MONTHS}}', '{{TERMINATION_NOTICE_DAYS}}'],
SERVICE: ['{{SERVICE_NAME}}', '{{PLATFORM_NAME}}', '{{SERVICE_DESCRIPTION}}', '{{SERVICE_MODEL}}', '{{SERVICE_TIER}}', '{{DATA_LOCATION}}', '{{EXPORT_FORMATS}}', '{{EXPORT_WINDOW_DAYS}}', '{{MIN_TERM_MONTHS}}', '{{TERMINATION_NOTICE_DAYS}}', '{{SERVICE_DESCRIPTION_SHORT}}', '{{NOTICE_PERIOD_DAYS}}', '{{DATA_PROCESSING_LOCATIONS}}'],
LEGAL: ['{{GOVERNING_LAW}}', '{{JURISDICTION_CITY}}', '{{VERSION_DATE}}', '{{EFFECTIVE_DATE}}', '{{START_DATE}}'],
PRIVACY: ['{{PRIVACY_CONTACT_EMAIL}}', '{{DPO_NAME}}', '{{DPO_EMAIL}}', '{{COPYRIGHT_CONTACT_NAME}}', '{{COPYRIGHT_EMAIL}}', '{{PRIVACY_POLICY_URL}}', '{{COOKIE_POLICY_URL}}', '{{ANALYTICS_RETENTION_MONTHS}}', '{{DATA_TRANSFER_THIRD_COUNTRIES}}'],
PRIVACY: ['{{PRIVACY_CONTACT_EMAIL}}', '{{DPO_NAME}}', '{{DPO_EMAIL}}', '{{COPYRIGHT_CONTACT_NAME}}', '{{COPYRIGHT_EMAIL}}', '{{PRIVACY_POLICY_URL}}', '{{COOKIE_POLICY_URL}}', '{{ANALYTICS_RETENTION_MONTHS}}', '{{DATA_TRANSFER_THIRD_COUNTRIES}}', '{{SUPERVISORY_AUTHORITY_NAME}}', '{{SUPERVISORY_AUTHORITY_ADDRESS}}'],
SLA: ['{{AVAILABILITY_PERCENT}}', '{{MAINTENANCE_NOTICE_HOURS}}', '{{SUPPORT_EMAIL}}', '{{SUPPORT_PHONE}}', '{{SUPPORT_HOURS}}', '{{RESPONSE_CRITICAL_H}}', '{{RESOLUTION_CRITICAL_H}}', '{{RESPONSE_HIGH_H}}', '{{RESOLUTION_HIGH_H}}', '{{RESPONSE_MEDIUM_H}}', '{{RESOLUTION_MEDIUM_H}}', '{{RESPONSE_LOW_H}}'],
PAYMENTS: ['{{MONTHLY_FEE}}', '{{PAYMENT_DUE_DAY}}', '{{PAYMENT_METHOD}}', '{{PAYMENT_DAYS}}'],
SECURITY: ['{{INCIDENT_NOTICE_HOURS}}', '{{LOG_RETENTION_DAYS}}', '{{SECURITY_LOG_RETENTION_DAYS}}'],
NDA: ['{{PURPOSE}}', '{{DURATION_YEARS}}', '{{PENALTY_AMOUNT}}'],
CONSENT: ['{{WEBSITE_NAME}}', '{{ANALYTICS_TOOLS}}', '{{MARKETING_PARTNERS}}'],
CONSENT: ['{{WEBSITE_NAME}}', '{{ANALYTICS_TOOLS}}', '{{MARKETING_PARTNERS}}', '{{ANALYTICS_TOOLS_LIST}}', '{{MARKETING_PARTNERS_LIST}}'],
HOSTING: ['{{HOSTING_PROVIDER_NAME}}', '{{HOSTING_PROVIDER_COUNTRY}}', '{{HOSTING_PROVIDER_CONTRACT_TYPE}}'],
FEATURES: ['{{CONSENT_WITHDRAWAL_PATH}}', '{{SECURITY_MEASURES_SUMMARY}}', '{{DATA_SUBJECT_REQUEST_CHANNEL}}', '{{TRANSFER_GUARDS}}', '{{REGULATED_PROFESSION_TEXT}}', '{{EDITORIAL_RESPONSIBLE_NAME}}', '{{EDITORIAL_RESPONSIBLE_ADDRESS}}', '{{DISPUTE_RESOLUTION_TEXT}}', '{{NEWSLETTER_PROVIDER_DETAIL}}', '{{PAYMENT_PROVIDER_DETAIL}}', '{{SOCIAL_MEDIA_DETAIL}}', '{{ANALYTICS_TOOLS_DETAIL}}', '{{MARKETING_TOOLS_DETAIL}}', '{{CMP_NAME}}', '{{PRICES_TEXT}}', '{{PAYMENT_TERMS_TEXT}}', '{{CONTRACT_TERM_TEXT}}', '{{SLA_URL}}', '{{EXPORT_POLICY_TEXT}}', '{{LIMITATION_CAP_TEXT}}', '{{CONSUMER_WITHDRAWAL_TEXT}}', '{{SUPPORT_CHANNELS_TEXT}}'],
}
/**