---
phase: 118-fakturownia-single-instance
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
  - database/migrations/20260512_000109_fakturownia_single_instance.sql
  - src/Modules/Settings/FakturowniaIntegrationRepository.php
  - src/Modules/Settings/FakturowniaIntegrationController.php
  - src/Modules/Settings/IntegrationsHubController.php
  - src/Modules/Settings/InvoiceConfigRepository.php
  - src/Modules/Settings/InvoiceConfigController.php
  - src/Modules/Accounting/InvoiceService.php
  - resources/views/settings/fakturownia.php
  - resources/views/settings/fakturownia-edit.php
  - resources/views/settings/accounting-invoice-edit.php
  - routes/web.php
  - DOCS/DB_SCHEMA.md
  - DOCS/ARCHITECTURE.md
  - DOCS/TECH_CHANGELOG.md
autonomous: true
delegation: off
---

<objective>
## Goal
Convert Fakturownia from a multi-account integration to one global integration instance, like HostedSMS/SMSPLANET.

## Purpose
The operator should configure Fakturownia once. Invoice configs may still delegate invoice issuing to Fakturownia, but they must all point to the single global Fakturownia integration row.

## Output
One migration, one single-instance repository/controller/UI flow, updated invoice config handling, and updated technical documentation.
</objective>

<context>
<clarifications>
- **Migracja** - Co zrobic z istniejacymi wieloma kontami Fakturowni, jesli sa juz w bazie?
  -> Odpowiedz: Wybrac aktywne konto.
- **Kontrakty** - Czy delegowane konfiguracje faktur maja nadal trzymac `integration_id`, ale zawsze wskazywac jedyna globalna Fakturownie?
  -> Odpowiedz: Tak.
- **UI** - Jak ma wygladac UI Fakturowni?
  -> Odpowiedz: Jedna strona z formularzem konfiguracji i testem polaczenia, bez dodawania wielu instancji.
</clarifications>

## Project Context
@.paul/PROJECT.md
@.paul/ROADMAP.md
@.paul/STATE.md
@DOCS/DB_SCHEMA.md
@DOCS/ARCHITECTURE.md

## Source Files
@src/Modules/Settings/FakturowniaIntegrationRepository.php
@src/Modules/Settings/FakturowniaIntegrationController.php
@src/Modules/Settings/HostedSmsIntegrationRepository.php
@src/Modules/Settings/IntegrationsHubController.php
@src/Modules/Settings/InvoiceConfigRepository.php
@src/Modules/Settings/InvoiceConfigController.php
@src/Modules/Accounting/InvoiceService.php
@resources/views/settings/fakturownia.php
@resources/views/settings/fakturownia-edit.php
@resources/views/settings/accounting-invoice-edit.php
@routes/web.php

## Prior Work
@.paul/phases/113-fakturownia-integration/113-01-SUMMARY.md
@.paul/phases/114-accounting-configs-refactor/114-01-SUMMARY.md
@.paul/phases/115-invoice-from-order/115-01-SUMMARY.md
@.paul/phases/116-hostedsms-integration/116-01-SUMMARY.md
</context>

<skills>
## Required Skills

No blocking skills before APPLY.

Project SPECIAL-FLOWS requires `sonar-scanner` after APPLY and before UNIFY when available in PATH.
</skills>

<acceptance_criteria>

## AC-1: Jedna globalna konfiguracja Fakturowni
```gherkin
Given the operator opens /settings/integrations/fakturownia
When the page renders
Then there is one settings form with save and test actions, and no UI for adding, listing, or deleting multiple Fakturownia accounts
```

## AC-2: Migracja wybiera aktywna instancje
```gherkin
Given multiple integrations with type "fakturownia" exist before migration
When the migration runs
Then the active integration is preserved as the single global row, invoice_configs.integration_id values are reassigned to it, settings are preserved for that row, and extra unused Fakturownia rows are removed or detached safely
```

## AC-3: Delegacja faktur pozostaje kompatybilna
```gherkin
Given an invoice config has is_delegated = 1
When it is saved or used to issue an invoice
Then it points to the single global Fakturownia integration_id and InvoiceService can still call Fakturownia without schema changes
```

## AC-4: Hub integracji pokazuje pojedynczy status
```gherkin
Given the integrations hub is opened
When Fakturownia row is displayed
Then it shows one provider row with configured/active/token/test status for the global instance, not a count of instances
```

## AC-5: Dokumentacja jest aktualna
```gherkin
Given the implementation is complete
When DOCS are reviewed
Then DB_SCHEMA, ARCHITECTURE, and TECH_CHANGELOG describe Fakturownia as a fixed single-instance integration and note the migration behavior
```

</acceptance_criteria>

<tasks>

<task type="auto">
  <name>Task 1: Add single-instance migration</name>
  <files>database/migrations/20260512_000109_fakturownia_single_instance.sql, DOCS/DB_SCHEMA.md</files>
  <action>
    Create an idempotent migration that enforces the single-instance Fakturownia model without dropping existing invoice history.
    - Pick the preserved row by priority: active Fakturownia integration first, then the one referenced by invoice_configs, then the lowest id.
    - Ensure a base integrations row exists with type=fakturownia and name=Fakturownia if none exists.
    - Ensure one fakturownia_integration_settings row exists for the preserved integration.
    - Reassign invoice_configs.integration_id for delegated configs to the preserved integration.
    - Remove extra fakturownia_integration_settings/integrations rows only after reassignment, using prepared migration SQL and FK-safe order.
    - Add/adjust constraints so settings are fixed to id=1 when feasible without breaking MySQL compatibility.
    Avoid: deleting invoices, changing invoices.config_id, or removing the invoice_configs.integration_id column.
  </action>
  <verify>C:\xampp\php\php.exe bin\migrate.php on a database with zero, one, and multiple Fakturownia rows; inspect integrations/fakturownia_integration_settings/invoice_configs after migration.</verify>
  <done>AC-2 and AC-3 satisfied.</done>
</task>

<task type="auto">
  <name>Task 2: Refactor Fakturownia repository/controller/UI to single settings page</name>
  <files>src/Modules/Settings/FakturowniaIntegrationRepository.php, src/Modules/Settings/FakturowniaIntegrationController.php, resources/views/settings/fakturownia.php, resources/views/settings/fakturownia-edit.php, routes/web.php, src/Modules/Settings/IntegrationsHubController.php</files>
  <action>
    Replace the multi-account behavior with HostedSMS-style single settings behavior.
    - Repository exposes getSettings(), saveSettings(), getCredentials()/getDecryptedToken() and getIntegrationId() for the fixed integration.
    - Save updates the single integration row and single settings row; empty token preserves the old encrypted token.
    - Controller index renders one page with the form and test panel; save/test redirect back to /settings/integrations/fakturownia.
    - Remove or neutralize /new, /edit, /delete routes and links for Fakturownia.
    - Hub row uses the single settings object and no longer displays instance counts.
    Avoid: native alert()/confirm(), inline CSS in new view code, and SQL string concatenation.
  </action>
  <verify>C:\xampp\php\php.exe -l on touched PHP files; manually open /settings/integrations and /settings/integrations/fakturownia, save settings, and run connection test.</verify>
  <done>AC-1 and AC-4 satisfied.</done>
</task>

<task type="auto">
  <name>Task 3: Keep invoice config delegation compatible with the global integration</name>
  <files>src/Modules/Settings/InvoiceConfigRepository.php, src/Modules/Settings/InvoiceConfigController.php, src/Modules/Accounting/InvoiceService.php, resources/views/settings/accounting-invoice-edit.php, DOCS/ARCHITECTURE.md, DOCS/TECH_CHANGELOG.md</files>
  <action>
    Update invoice config handling so delegated configs always use the single Fakturownia integration.
    - When saving delegated invoice configs, ignore user-supplied multi-account choice and resolve the global Fakturownia integration_id from the repository.
    - Simplify accounting invoice edit UI so delegation does not show a multi-account selector; show a compact hint/status that Fakturownia must be configured globally.
    - Ensure InvoiceService still reads config integration_id and retrieves credentials through the updated repository.
    - Update docs and changelog with new single-instance contract and migration behavior.
    Avoid: schema removal of invoice_configs.integration_id and behavior changes for local non-delegated invoice configs.
  </action>
  <verify>C:\xampp\php\php.exe -l on touched PHP files; create/edit local and delegated invoice configs; issue a delegated invoice against a configured Fakturownia account in manual UAT.</verify>
  <done>AC-3 and AC-5 satisfied.</done>
</task>

</tasks>

<boundaries>

## DO NOT CHANGE
- Do not remove `invoice_configs.integration_id`.
- Do not change existing `invoices` rows or invoice PDF rendering.
- Do not add `invoice.created` automation event.
- Do not implement Fakturownia double-POST idempotency in this plan.
- Do not change HostedSMS/SMSPLANET behavior.

## SCOPE LIMITS
- This plan only changes Fakturownia account configuration from multi-instance to single-instance.
- Existing delegated invoice issuing remains functionally the same after it resolves the global account.
- Live Fakturownia API testing depends on operator credentials and network access.

</boundaries>

<verification>
Before declaring plan complete:
- [ ] `C:\xampp\php\php.exe bin\migrate.php`
- [ ] `C:\xampp\php\php.exe -l` for all touched PHP files
- [ ] Manual UI smoke: integrations hub, Fakturownia settings save, Fakturownia test
- [ ] Manual UI smoke: invoice config create/edit for local and delegated modes
- [ ] Delegated invoice issue still calls Fakturownia with the global account
- [ ] DOCS/DB_SCHEMA.md, DOCS/ARCHITECTURE.md, DOCS/TECH_CHANGELOG.md updated
- [ ] `sonar-scanner` run after APPLY if available in PATH
</verification>

<success_criteria>
- Fakturownia has exactly one configurable instance from the UI.
- Migration preserves one active Fakturownia row and rewires delegated invoice configs to it.
- No route or view offers adding/deleting multiple Fakturownia accounts.
- Delegated invoice configs and delegated invoice issuing remain compatible.
- All verification checks pass or environment-dependent gaps are documented in SUMMARY.md.
</success_criteria>

<output>
After completion, create `.paul/phases/118-fakturownia-single-instance/118-01-SUMMARY.md`.
</output>
