# Bilko — Contact Form + Pricing Restructure (2026-07-14)

*Documents two shipped-and-live-verified changes deployed to demo (app.bilko.cloud) on 2026-07-14. Written for the ZAKON DOC gate covering MC #105588 and MC #105589.*

## MC #105588 — In-app contact form (RESOLVED, live)

### Problem

The "Kontaktiraj nas" CTA (shown on contact-only tiers) executed `window.location.href='mailto:info@bilko.io'`. This was broken in practice: it requires a configured mail client on the visitor's machine, and it pointed at a `.io` domain that looks suspicious to a Balkan SMB user rather than the product's own domain.

### Fix

- New backend endpoint: `POST /api/v1/leads` — public, rate-limited to 5 requests/min/IP via trusted-IP keying, closed tier enum (no arbitrary string injection), no PII echoed back in the response.
- Lead emails are sent via **Resend** (note: the repo uses Resend, not SendGrid) to `LEADS_NOTIFICATION_EMAIL`, which defaults to `alem@alai.no`.
- New shared frontend component, `LeadContactForm`, used as a modal from both `ChangePlanDrawer` and the public `/pricing` page — so both contact-only tiers (Računovođa, Enterprise) route through the same in-app form instead of a mailto link.

### Security review

Parisa Tabriz (Securion) reviewed the public lead endpoint: **PASS WITH FOLLOW-UPS**. Hardening follow-ups tracked as MC #105592: HTML-escape the email body, escape the C0 control-character range in JSON output, add a `RequestBodyLimit`, and add a global request cap.

### Commits / PR

- Backend: `f15dee26`
- Frontend: `07ee9a9b`
- PR144 → merged as `2ce713e2`

### Verification (Angie Jones / Proveo, live UAT)

**PASS** — clicking "Kontaktiraj nas" opens an in-app modal titled "Kontaktirajte nas" with Ime / Email / Poruka fields. No `mailto:` navigation occurs. Evidence captured at `~/system/evidence/deploy-497-uat/`, notably `06-after-kontakt-click.png` (plus `05-before-kontakt-click.png`, `07-modal-closeup.png`, `06-modal-text.txt`, and the run's `uat-report.json`).

---

## MC #105589 — Pricing restructure: base + add-ons spine (RESOLVED, live)

### Decision

CEO decision (2026-07-14), adversarially reviewed by Markos Zachariadis (Finverge) — **ENDORSE WITH CHANGES**. Bilko had two overlapping pricing models running in parallel: a tier-bundle model and an add-on module model. This created two competing paths to full bookkeeping — the Računovođa tier at €39, versus Biznis (€19) + FULL add-on (€18) = €37 — which cannibalized each other. The decision collapses this into **one base + add-ons spine**.

### Changes shipped

- **Removed** the Računovođa tier everywhere in the UI (pricing-matrix.json / TIER\_UI / ChangePlanDrawer).
- Full bookkeeping is now available **only** via the `ACCOUNTING_FULL_ADDON` at €18.
- Multi-org cockpit is now bundled **free** with the FULL add-on (`multiOrg` is derived from `accountingFull`) — consistent with the 2026-06-25 multi-org pricing decision and the Fiken-inspired model. Verified live via the Testcontainers `MeCapabilitiesRoutesTest` (`multiOrg=true` on ENTERPRISE).
- FULL grants an accountant-sized e-invoice quota (~300).
- Added a "vs Pantheon €150+" competitive anchor line on the FULL add-on card.
- HR pricing: PDV running total including 25% shown on `/pretplata`, plus "cijena bez PDV-a (25%)" labels on `/pricing`.
- Kept the BIZNIS bundle tier as-is.
- Enterprise remains the sole contact-only tier.
- Added graceful fallback handling for unknown/legacy `planTier` values.

### Explicitly out of scope

**No Stripe price mutations.** Tier prices in Stripe remain placeholders pending explicit CEO confirmation of final numbers before any `Stripe price create` call.

### Blast-radius check

Live enumeration before removal: 0 organizations on ENTERPRISE or RACUNOVODJA tiers (PRO=5, BASIC=2, PREMIUM=1). Removing the Računovođa tier breaks no live customer.

### Commits / PR

- `eb3b81ef` + `fd439b0e` (cleanup)
- PR145 → merged as `21ad3534`

### Verification (Angie Jones / Proveo, live UAT)

**PASS** — live tiers are Paušalac €9 / Biznis €19 / Enterprise (contact); no Računovođa tier present; FULL add-on shown at €18 with the Pantheon comparison line; PDV labels present as specified. Evidence at `~/system/evidence/deploy-497-uat/` (`02-public-pricing-page.png`/`.txt`, `03-pretplata-page.png`/`.txt`, `08-pretplata-addons-scrolled.png`, `09-addon-add-button.png`).

### Follow-up

MC #105614 — two stale "Računovođa" copy strings remain (Modul B CTA + `/pricing` sidebar) and need a copy cleanup pass.

---

## Deploy note

Both changes were deployed to demo via the **canonical azdo pipeline** `Promote_Demo` stage — self-hosted agent, pipeline service connection, **not** a manual personal `az` deploy (per ZAKON PI2). Build 497 (manual trigger, commit `21ad3534`), approved via PAT, `Promote_Demo` succeeded, and `app.bilko.cloud` returned HTTP 200 post-deploy.

## Evidence index

<table id="bkmrk-itemlocation-live-ua"><thead><tr><th>Item</th><th>Location</th></tr></thead><tbody><tr><td>Live UAT screenshots + reports (both MCs)</td><td>`~/system/evidence/deploy-497-uat/`</td></tr><tr><td>Contact-click before/after</td><td>`05-before-kontakt-click.png`, `06-after-kontakt-click.png`, `06-modal-text.txt`, `07-modal-closeup.png`</td></tr><tr><td>Public pricing page</td><td>`02-public-pricing-page.png`/`.txt`</td></tr><tr><td>Subscription (/pretplata) page</td><td>`03-pretplata-page.png`/`.txt`, `08-pretplata-addons-scrolled.png`, `09-addon-add-button.png`</td></tr><tr><td>Change-plan drawer</td><td>`04-change-plan-drawer.png`/`.txt`</td></tr><tr><td>UAT structured report</td><td>`uat-report.json`</td></tr></tbody></table>

## Related MC tasks

- \#105588 — In-app contact form (this doc)
- \#105589 — Pricing restructure base+add-ons (this doc)
- \#105592 — Lead endpoint hardening follow-up (Parisa)
- \#105614 — Stale "Računovođa" copy cleanup follow-up