Svet Crnil Pomoc 2.0.2 — SIGNED RELEASE

IMPLEMENTED AND LOCALLY VERIFIED
The empty commercial request screen now offers "Obnovi prejsnjo sejo".
The customer enters a short-lived operator-issued recovery code. The server
requires the same Android RustDesk ID, active attempt, fence and checkpoint,
confirmed fresh payment, no pending action and an offline customer session.
Recovery keeps the existing request/device/payment/conversation/checkpoint.
The new customer credential is saved before the request and can safely retry a
lost response. Recovery does not advertise native readiness or connection
consent. The customer must separately use the existing connection consent flow.
An invalid/corrupt saved local file retains the pre-existing manual-review path.

MATCHING SERVER
The matching app_recovery.py, service.py and PHP proxy allowlist entries have
been deployed and downloaded back for exact SHA256 verification. The updated
worker and agent_ctl.py are running. Health and new-route checks passed.
Review the active case and verify that its exact RustDesk session is closed
before issuing a code using agent_ctl.py app-recovery-code TICKET_ID
--confirm-reviewed --confirm-session-closed. The code expires after 15 minutes.
Do not issue a code for a pending or uncertain remote action. Do not log codes.
No private.json, passwords, payment keys or server settings were changed.

VALIDATION
All four Dart contract files passed, including the new recovery contract.
The matching server/worker suite passed 32 tests; extension reload test passed.
Static analysis of the changed Dart modules and new contract reported no
errors or warnings (existing style hints and two relative-test-import hints).
The universal Android release APK built successfully for ARMv7, ARM64 and x86_64.
APK signature verification passed (v1/v2), package si.svetcrnil.pomoc,
version 2.0.2, versionCode 20002. Signing certificate SHA256:
e34349f140a4182c9cffaaa5125b9933d30a6c507b0b8d325e28cf034ae6847f
This is the same signing identity as release 2.0.1. Native RustDesk and C++
libraries match 2.0.1 byte for byte for all three ABIs. ZIP CRC passed.
The original key was recovered from the existing private signing backup and
is excluded from all public source/artifact packages. No new key was created.
A physical Android update/permission/recovery test remains to be performed.
Install as an update; do not uninstall the app or clear its data.
Build command: flutter build apk --release --no-pub --build-name=2.0.2
--build-number=20002 --target-platform=android-arm,android-arm64,android-x64
Flutter 3.24.5, Dart 3.5.4, OpenJDK 17, Gradle 8.11.1; Android SDK 36.
A transient Maven download error was resolved; the original build retry
completed. The resulting signed APK is paired with this source archive.

REGRESSION SURFACE
- svetcrnil_commercial_api.dart: recovery entry point, durable pending state,
  prevents new orders during an unresolved recovery, and consent gate only
  for recovered sessions. Existing order/checkout/billing paths are retained.
- svetcrnil_commercial_page.dart: recovery card, dialog hook and error text.
- New session-recovery model, dialog and recovery contract test.
- SC_package_source_v2.py: release version/name and required recovery files.
- Matching service.py: two feature dispatch hooks and existing payment refresh
  for code issuance; agent.py/agent_ctl.py: authenticated operator command;
  PHP proxy: only the two new route allowlist entries.

NEXT FEATURE AGREED: 100% COUPON, NOT A SECRET PAYMENT BACKDOOR
Use an explicit "Koda kupona" field and server-side coupon validation. The
existing Printomat model pm95_discount_codes currently restricts percent_off
to 1..99, and its reservations reference print quotes/users. A 100% support
coupon therefore needs a reviewed schema migration and support-specific
reservation/redemption binding, not merely an inserted row. The current
discounts.py implementation and coupon-admin validation must be inspected
before implementing the migration.
The server must calculate and freeze original amount, discount and amount due;
zero due skips SumUp and is recorded as coupon-covered, never a fictitious
provider payment. Preserve limits, expiry, cancellation and idempotent retries.
Restrict the testing coupon by product, validity, recipient and usage count.
Keep a real customer's already accepted/paid order immutable.
The payment/fiscal and worker guards need an explicit server-confirmed coupon
authorization branch; do not set paid/fiscal_confirmed=true just to bypass them.
Coupon implementation, database migration and creation of a live coupon have
NOT been performed in this release.
