KOP Integration

Renewa One handles three different deal types based on who is the customer’s primary contractor: Renewa itself, a Renewa-partnered Handwerker, or a customer-chosen external Handwerker. The two non-EB types are collectively referred to as KOP in conversation and in UI labels — in code, the vocabulary was renamed to contractor in May 2026 (PR#1690, the P2 contractor-engagement rebuild).

This page is the canonical reference for what those terms mean, why we use them, and how the rename actually landed.

The three engagement types

engagement_typeCustomer’s primary contractorWho initiated that contractorRenewa’s roleValue flow to Renewa
energy_consulting (spoken: “EB”)RenewaRenewa-direct saleExecutes the workDirect sales revenue
internal_contractor (spoken: “Provi-KOP”)Renewa-partnered HandwerkerRenewa (introduces the partner to the customer)Coordinates, overseesCommission on the Handwerker’s invoices to the customer
external_contractor (spoken: “Nicht-Provi-KOP”)Customer-chosen HandwerkerThe customer (brings their own Handwerker)Tracks for FUE compliance onlyNone (FUE = Fachunternehmererklärung; the contractor may become a Renewa partner later, but until then no value flow)

The discriminator is projects.engagement_type (Postgres pgEnum, default energy_consulting), denormalized onto workflow_packages.engagement_type so packages without a project_id (manual external_contractor entries) still carry it. It drives lifecycle, billing, dunning, and which workflow template the package instantiates from (template.engagementType must match the project’s).

What “KOP” actually means here

KOP historically stands for Kooperationspartner (cooperation partner). That meaning fits internal_contractor — Renewa really does have a cooperation/commission agreement with that Handwerker. But it does not fit external_contractor — there’s no agreement with that contractor; the customer just brought them in.

That acronym mismatch is exactly why the code-level rename happened (names track current domain scope). The split today:

  • Code identifiers are uniformly contractor: enum values, tables (contractor_customer_inquiries), services (ContractorHandoverService, ContractorCustomerInquiryService), routes (/api/workflow/contractor-engagement/), components (frontend/src/components/workflow/contractor/).
  • Display strings keep “KOP” intentionally — the Renewa team verbally says “KOP”, “Provi-KOP”, “Nicht-Provi-KOP” all day, and HubSpot pipelines, sales materials, and the UI labels match that vocabulary. i18n keys like "KOP-Übergabe", "Intern (KOP)", "Provi-KOP", "Nicht-Provi-KOP" live in frontend/src/locales/de/workflow.json.

How a deal becomes a package

HubSpot Deal (Won)
    │
    ▼ pipeline_id lookup (env-driven map, fail-fast on unknown pipelines)
    │
    ├── HUBSPOT_PIPELINE_ENERGY_CONSULTING    → engagement_type = 'energy_consulting'
    ├── HUBSPOT_PIPELINE_INTERNAL_CONTRACTOR  → engagement_type = 'internal_contractor'
    └── HUBSPOT_PIPELINE_EXTERNAL_CONTRACTOR  → engagement_type = 'external_contractor'
    │
    ▼ workflow_packages row created with status='active' (single-step handover, no draft)
    │
    ├── (energy_consulting) Quote-line-items bestimmen Workflow-Template-Selection (matchTemplates())
    ├── (internal_contractor) commission fields required at handover; rate from
    │       projects.commission_rate (HubSpot deal "provision")
    └── (external_contractor) project_id may be NULL (manual entry); FUE-only

The pipeline-ID → engagement_type mapping lives in env vars (backend/src/lib/hubspot-pipelines.ts), one per environment — not a config table. An unknown pipeline raises UnknownHubspotPipelineError: a HubSpot deal from an unmapped pipeline is not persisted as a workflow package, and there is no silent default to energy_consulting.

There is no contractor metadata side-table: the planned kop_package_metadata never survived review. The assigned contractor relationship flows through the HubSpot association infrastructure (getAssociationsByRenewaName('contractor', …); the “Zugewiesener KOP AP” sync landed in PR#1891).

Lifecycle differences

All three types share the workflow_packages family (workflow_packages, workflow_package_phases, workflow_package_phase_tasks); phases are template-driven per engagement type rather than a hardcoded Planung → Umsetzung → Fertig sequence. Handover is single-step since PR#1855: packages are created active directly (the draft status value remains in the enum for legacy reads only).

Aspectenergy_consultinginternal_contractorexternal_contractor
Trade-start signalBauarbeitsvertrag-driven tasksPlanning signal / manualCustomer portal inquiry “Gewerk gestartet am DATUM” via contractor_customer_inquiries (trade_start_check, responses started / not_yet_started). The recurring scheduler asking the customer is deferred — the inquiry/response flow exists in ContractorCustomerInquiryService
Tranches / billingQuote-line-item-driven via billingTranche tasks (workflow_package_phase_tasks with billing metadata) surfaced in ContractorCommissionInvoicesTable; commission rate from projects.commission_rate, effective rate via effectiveCommissionRate()None — contractor invoices the customer directly (0% to Renewa)
Renewa billing involvementDirect invoicing (billingInvoices, dealType EB)Receives Provi-Rechnung from partner (billingInvoices, dealType KOP)None
FUE trackingn/aOptional (depends on contract)Mandatory (Renewa documents the external Handwerker’s work for funding compliance)

Where to look in the code

WhatWhere
The engagement_type enumrenewa-one/backend/src/db/schema.tsengagementTypeEnum (on projects, denormalized to workflowPackages)
Pipeline-ID lookuprenewa-one/backend/src/lib/hubspot-pipelines.ts (pipelineToEngagementType(), env-driven map)
Package creation logicrenewa-one/backend/src/lib/workflow/workflow-package-factory.ts (branches on engagementType)
Handover / tranche listingrenewa-one/backend/src/services/workflow-package/contractor-handover-service.ts (+ WorkflowPackageHandoverService for project-sourced candidates)
Customer inquiry servicerenewa-one/backend/src/services/workflow-package/contractor-customer-inquiry-service.ts (table contractor_customer_inquiries)
Routesrenewa-one/backend/src/routes/workflow/contractor-engagement/ + consolidated /api/workflow/packages/*
Service-container keyscontractorHandover, contractorCustomerInquiry (create-services.ts)
external_contractor workspace UIrenewa-one/frontend/src/components/workflow/contractor/ExternalContractorWorkspace.tsx
Commission table UIrenewa-one/frontend/src/components/workflow/contractor/ContractorCommissionInvoicesTable.tsx
Commission rate logicrenewa-one/backend/src/lib/contractor-commission.ts (effectiveCommissionRate())
Specs2026-05-09-contractor-engagement-rebuild-design.md (P2, current); 2026-04-24-v3-kop-integration-design.md (V3 reference, retained as-is)

The rename shipped: KOP → Contractor

The “KOP-as-Renewa-internal-acronym” debt described in earlier versions of this page was paid down in PR#1690 (P2 contractor-engagement rebuild). What actually shipped, versus the migration plan once sketched here:

PlannedAs-built
internal_koppartner_contractor, external_kopcustomer_contractorebenergy_consulting, internal_kopinternal_contractor, external_kopexternal_contractor — and the discriminator moved from workflow_packages.package_type to projects.engagement_type
kop_package_metadatacontractor_package_metadataTable dropped entirely; contractor linkage via association infrastructure (no contractor_id FK — I#1675’s pattern was rejected)
kop_customer_inquiriescontractor_customer_inquiriesAs planned (incl. contractor_inquiry_type enum)
KopHandoverServiceContractorHandoverServiceAs planned; later slimmed to tranche-listing by the handover redesign (PR#1855)
hubspot_pipeline_mappings config table updatedConfig table replaced by env vars (HUBSPOT_PIPELINE_*)
Wiki page renamed to “Contractor Integration” + glossary anchorPage kept under “KOP Integration” — KOP remains the spoken/UI term, so this name is still the search anchor

UI display strings deliberately still say “KOP” (team vocabulary; user-facing terminology unchanged). The rule applied was names track current domain scope: code identifiers renamed, coined spoken terms stay.

Workflow v4 status

The package model is evolving under the Workflow v4 umbrella (I#1933):

  • PR-1 (data layer foundation) merged 2026-06-11 (PR#1942): 5-axis weighted Kanban scoring (LIFO / deadline / priority / revenue / customer score), 3-level effective-deadline resolution (task > phase > package), phase dueDate stamping from template average durations, PATCH /api/workflow/packages/:id deadline changes journaled to activity_logs, and projects.customer_score snapshotted onto packages at handover.
  • Siblings pending: I#1934 (Admin Kanban UI), I#1935 (Wochenplan).
  • No new table layer — same workflow_packages family with evolved semantics (vestigial V3 columns dropped per the purify-workflow-packages spec, 2026-05-15).
  • Workflow Engine (TBD — the broader workflow-package model)
  • HubSpot Integration — pipeline configuration + sync flow
  • Financial Calculations — commission rates, billingInvoices, settlement
  • FUE (TBD — Fachunternehmererklärung tracking for external_contractor)