Part of #1279
Depends on #1281 (platformType must be registered in API)
Context
Operators need a way to create and configure an Infakt connection in the OL web UI, and to see KSeF clearance status on invoice detail pages.
Pattern: apps/web/src/plugins/ksef/ structure.
The backend CorrectionIssuer capability is already implemented for inFakt in InfaktInvoicingAdapter (PR #1292, part of this epic #1279), so the correction-flow (KOR) scope item below is real, not speculative.
Scope
1. Plugin descriptor
File: apps/web/src/plugins/infakt/index.ts
export const infaktPlugin = definePlugin({
id: 'infakt',
platformType: 'infakt',
platform: {
displayName: 'inFakt',
setupCard: {
title: 'inFakt',
description: 'Polish accounting platform with native KSeF integration',
},
StructuredConfigSection: InfaktStructuredSection,
CredentialsPanel: InfaktCredentialsPanel,
invoiceDetailSection: InfaktInvoiceDetailSection,
},
});
2. Structured config section
File: apps/web/src/plugins/infakt/components/infakt-structured-section.tsx
Fields:
baseUrl (optional): text input, placeholder https://api.infakt.pl, used only for sandbox override
- Helper text explaining sandbox vs production
Zod schema for form validation.
3. Credentials panel
File: apps/web/src/plugins/infakt/components/infakt-credentials-panel.tsx
- API key display (masked: last 4 chars visible)
- "Rotate API key" button →
PUT /connections/{id}/credentials
- Input field for new API key + confirm
Pattern: apps/web/src/plugins/ksef/components/ksef-credentials-panel.tsx
4. Invoice detail section
File: apps/web/src/plugins/infakt/components/infakt-invoice-detail-section.tsx
Renders conditional on regulatoryStatus:
not-applicable: nothing
submitted: "Pending KSeF clearance..." + spinner
cleared / accepted: "KSeF Cleared" + clearanceReference (KSeF number) as copyable chip
rejected: "KSeF Rejected" + failureReason
Data comes from the InvoiceRecord prop already fetched by host — no additional API call.
Pattern: apps/web/src/plugins/ksef/components/ksef-invoice-detail-section.tsx
5. Invoice correction flow (KOR)
File: apps/web/src/plugins/infakt/components/infakt-invoice-correction-flow.tsx
The inFakt backend adapter (InfaktInvoicingAdapter, PR #1292) implements the CorrectionIssuer capability, so inFakt supports issuing KSeF corrections (KOR) the same way the KSeF plugin does. The backend endpoint POST /invoices/:invoiceId/correct is capability-gated and platform-neutral, and the FE mutation hook useIssueCorrectionMutation (from apps/web/src/features/invoicing) is already generic — this component is mostly a near 1:1 port of the KSeF equivalent.
Pattern: apps/web/src/plugins/ksef/components/ksef-invoice-correction-flow.tsx (near 1:1 reuse of structure/logic):
- Same line-row model: optional free-text reason, repeatable rows of
originalLineNumber / newQuantity / newUnitPriceGross
- Starts with one empty row and an "Add line" affordance
- Content-only component conforming to the
InvoiceCorrectionFlowProps slot contract; the host dialog owns the outer chrome
- Uses the same generic
useIssueCorrectionMutation hook — no inFakt-specific API call needed
Register it on the plugin descriptor's platform.invoiceCorrectionFlow slot (in apps/web/src/plugins/infakt/index.ts, alongside invoiceDetailSection).
6. Register in plugin barrel
File: apps/web/src/plugins/index.ts
import { infaktPlugin } from './infakt';
export const plugins = [ ...existing, infaktPlugin ] as const satisfies readonly OpenLinkerPlugin[];
Acceptance criteria
Part of #1279
Depends on #1281 (platformType must be registered in API)
Context
Operators need a way to create and configure an Infakt connection in the OL web UI, and to see KSeF clearance status on invoice detail pages.
Pattern:
apps/web/src/plugins/ksef/structure.The backend
CorrectionIssuercapability is already implemented for inFakt inInfaktInvoicingAdapter(PR #1292, part of this epic #1279), so the correction-flow (KOR) scope item below is real, not speculative.Scope
1. Plugin descriptor
File:
apps/web/src/plugins/infakt/index.ts2. Structured config section
File:
apps/web/src/plugins/infakt/components/infakt-structured-section.tsxFields:
baseUrl(optional): text input, placeholderhttps://api.infakt.pl, used only for sandbox overrideZod schema for form validation.
3. Credentials panel
File:
apps/web/src/plugins/infakt/components/infakt-credentials-panel.tsxPUT /connections/{id}/credentialsPattern:
apps/web/src/plugins/ksef/components/ksef-credentials-panel.tsx4. Invoice detail section
File:
apps/web/src/plugins/infakt/components/infakt-invoice-detail-section.tsxRenders conditional on
regulatoryStatus:not-applicable: nothingsubmitted: "Pending KSeF clearance..." + spinnercleared/accepted: "KSeF Cleared" +clearanceReference(KSeF number) as copyable chiprejected: "KSeF Rejected" +failureReasonData comes from the
InvoiceRecordprop already fetched by host — no additional API call.Pattern:
apps/web/src/plugins/ksef/components/ksef-invoice-detail-section.tsx5. Invoice correction flow (KOR)
File:
apps/web/src/plugins/infakt/components/infakt-invoice-correction-flow.tsxThe inFakt backend adapter (
InfaktInvoicingAdapter, PR #1292) implements theCorrectionIssuercapability, so inFakt supports issuing KSeF corrections (KOR) the same way the KSeF plugin does. The backend endpointPOST /invoices/:invoiceId/correctis capability-gated and platform-neutral, and the FE mutation hookuseIssueCorrectionMutation(fromapps/web/src/features/invoicing) is already generic — this component is mostly a near 1:1 port of the KSeF equivalent.Pattern:
apps/web/src/plugins/ksef/components/ksef-invoice-correction-flow.tsx(near 1:1 reuse of structure/logic):originalLineNumber/newQuantity/newUnitPriceGrossInvoiceCorrectionFlowPropsslot contract; the host dialog owns the outer chromeuseIssueCorrectionMutationhook — no inFakt-specific API call neededRegister it on the plugin descriptor's
platform.invoiceCorrectionFlowslot (inapps/web/src/plugins/infakt/index.ts, alongsideinvoiceDetailSection).6. Register in plugin barrel
File:
apps/web/src/plugins/index.tsAcceptance criteria
pnpm lintpassespnpm type-checkpasses/connections/newshows inFakt cardinfaktplatformTyperegulatoryStatus: 'cleared'shows KSeF numberregulatoryStatus: 'submitted'shows pending stateregulatoryStatus: 'rejected'shows rejection reason