Commit Graph
292 Commits
Author SHA1 Message Date
popertots 7f1c649f1e Apply second-round review fixes: idempotency-key length caps, stable-sentinel card keys, test-isolation, naming
Money-safety idempotency hardening (I1, wide):
- validate:"max=45" on CreateTerminalPayment/BookingPayment/Refund/Tip/
  BuyGiftCard idempotency keys (all feed Square's 45-char /v2/payments,
  /v2/refunds, /v2/cards caps); BuyGiftCard corrected from a wrongly-loose
  max=64. Till keeps max=64 (its key also feeds the 64-char terminal-checkout
  endpoint).
- Explicit 45-char guard in RefundPayment: the one handler that decodes
  RefundRequest without running the struct validator, so the tag alone was
  inert; a longer key would 400 at Square and be misclassified as a
  definitive refund decline.
- New TestIdempotencyKey_OverLength_RejectedAcrossPaymentHandlers covers all
  six endpoints (terminal saved-card, booking, tip, gift-card, till, refund).

Stable-sentinel card identity in idempotency keys (C1, wide):
- BookingFlow deposit key now uses the 'new-card' sentinel instead of
  embedding the cnon: nonce (matches UserPaymentModal/account). A re-tokenize
  after a spent nonce no longer regenerates the key, closing a lost-response
  double-charge window.
- TipPayment + UserBookingModal tip keys now include card identity
  (selectedCardId || 'new-card'); previously keyed on amount only, so a
  same-amount tip on a DIFFERENT card reused the key and deduped a distinct
  charge. Resets cleared in every success/close path.

Test isolation (R1): TestRefund_PendingResume_NewKeyAfterModalReopen no
longer t.Parallel — it swaps the package-level SquareClient mid-test and a
concurrent parallel test could observe the swapped instance.

Naming/quality (M1/M2/M4): resolveChargeSource local renamed savedRowID (was
shadowing the cardID *string parameter); BuyGiftCard fallback prefix
"till-" -> "gc-"; saved-card terminal response key "checkout_id" -> "payment_id"
(it holds a DB payment row, not a Square checkout) with matching frontend
fallback. README maintenance-job count corrected 24 -> 25.

Full suite 25/25 + race clean via run-tests.sh lockfile; svelte-check 0
errors/warnings; production build succeeds.
2026-08-22 00:34:49 +01:00
popertots a8d54f1e2a Fix review findings: aggregated-refund/saved-card/legacy-refund idempotency keys, structured Square error classification, CSP for Square SDK
Money-safety idempotency fixes (external review bugs 1-3):
- processChargeGroup: aggregated refund key now hashes the sorted pending-row
  set (chargeID-square-agg-<sha256 suffix>) so a changed group can never mark
  a new row completed against an old smaller refund; >45-char chargeIDs use a
  hashed prefix instead of verbatim truncation (which would collide charges on
  Square's global key dedup). Same-set crash-retry keeps Square's dedup.
- CreateTerminalPayment saved_card: two-tier idempotency key — client-supplied
  per-attempt UUID preferred (distinct identical charges no longer collapse),
  deterministic booking+type+amount+card fallback for no-key retry safety.
  PaymentModal sends a per-charge UUID cleared after success.
- ensureRefundKey: legacy NULL-key manual refunds persist a generated key to
  the row BEFORE the Square call (race-safe AND idempotency_key IS NULL guard),
  so a lost-response retry reuses the key and never double-refunds. Wired into
  resumeManualPendingRefund and the sweep's manual-retry loop.

Classification + money-safety hardening:
- till.go/sweep.go: structured square.ErrorCode/IsNotFound are authoritative
  when present; message-substring matching only for non-structured errors
  (dev mock, client-side status errors). Fixes fragile string-matching driving
  sweep retries and gift-card clawbacks.
- SaveCardForUser: ON CONFLICT (user_id, square_card_id) DO NOTHING + re-select
  (was a latent UNIQUE-violation 500 on save-card retry).
- CreateBookingPayment: partial payments re-validated against remaining balance
  inside the advisory lock (closes concurrent-overpayment race).
- InvalidateSquareCustomerCache on GDPR erasure paths (account.go,
  time-blockers.go stale-guest anonymization).
- GetUserGiftCardBalanceAdmin: in-handler admin check (defense-in-depth).
- getCheckoutHTTP: warn on multi-payment checkouts instead of dropping
  payments[1:].
- Cash/giftcard terminal branch: removed dead idempotency SELECT, "tip-" ->
  "till-" prefix.
- UserPaymentModal: removed vestigial polling state; proper interval cleanup.
- account/+page.svelte: gift-card redeem dialog links /terms.
- nginx CSP: allow *.squarecdn.com and js.squareup.com so the Square Web
  Payments SDK + card iframe can tokenize behind the proxy.

Tests: +8 regression tests covering changed-set refund keys, legacy NULL-key
single-refund, saved-card client-key dedup/no-dedup, concurrent partials, and
cache invalidation. Full suite + race detector clean via run-tests.sh lockfile.
2026-08-22 00:34:49 +01:00
popertots 726ac8cb65 Harden money-safety re-review findings: nonce-independent idempotency keys, reconciliation-required logging, terminal-state classification
Re-review (2 Oracle + security + QA + librarian + context-miner) surfaced fixes, all applied: (1) UserPaymentModal and the account-page gift-card buy now key the cached idempotency key on a stable 'new-card' sentinel instead of the cnon: nonce, so clearing the nonce on a failed charge no longer regenerates the key — a lost-response retry now dedups at Square instead of double-charging (the tip flows already keyed on amount only). (2) The create-with-redeem clawback now logs CRITICAL when the guarded balance reversal is blocked (previously silent), and its transaction DELETE is scoped to this sale instead of deleting every transaction on the card. (3) reconcileStalePaymentAtSquare now treats APPROVED/PENDING as non-terminal (leave pending) instead of definitively failed, matching Square's documented state machine. (4) GetTillCheckoutStatus returns 404 for a sale already swept to failed instead of reporting a live state. (5) The critical-payment scan job skips candidates whose booking was hard-deleted, so one orphan can no longer silence all critical alerts.
2026-08-22 00:34:49 +01:00
popertots 965da86b64 Re-tokenize fresh after a definitive card charge failure in all nonce flows
A cnon: nonce and its SCA verification token are consumed by a definitive charge failure (e.g. declined card) and can never succeed again, but TipPayment, UserBookingModal, UserPaymentModal and the account-page Buy-a-Gift-Card cached them and resubmitted the dead nonce on every retry — a non-retryable failure loop. The nonce/verification-token/amount/timestamp cache is now cleared in each error branch so retries re-tokenize fresh, while the idempotency key is kept for network-timeout dedup.
2026-08-22 00:34:49 +01:00
popertots 439fc16402 Fix sticky Square SDK rejection and clean up script element on failure
A load that resolved the script tag but failed to expose window.Square (or timed out) permanently cached a rejected promise, bricking card entry until reload. sdkPromise now resets and the injected script element is removed on every failure path so later calls retry fresh.
2026-08-22 00:34:49 +01:00
popertots e5c6458ec7 Fix frontend payment flows: BookingFlow fetch loop, shared TipPayment, card icons, terms route
Fix the P0 infinite refetch in BookingFlow (payment-methods fetched once via a guard flag, was looping on empty saved-card arrays and DoS-ing the rate limiter). Extract the shared TipPayment component so tip and pay-tip routes no longer drift; reconcile formatTimeRange override_duration_minutes and subtotal/tipsPaid. CardBrandIcon gains the correct Square enum keys (DISCOVER_DINERS, CHINA_UNIONPAY). PaymentModal reads card_last4. Login links resolve to the new /terms and /privacy-policy routes. Add frontend/.env.example.
2026-08-22 00:34:49 +01:00
popertots 54a5b1024e Implement full Square payment review fixes + frontend polish
Implement every finding from the deep payment review (P0-P2, minors,
nitpicks), then close the post-implementation re-review items, then
align card-form typography and roll out the Square trust badge.

Backend - Square API alignment:
- tip_settings.allow_tipping nested under device_options (was top-level:
  terminal tips were silently lost in prod)
- CreateCardOnFile now accepts customerID and sends card.customer_id;
  saved-card (ccof:) charges forward square_customer_id as CustomerID
- New SquareClient methods GetPayment, CreateCustomer, CancelCheckout
- SCA verification_token accepted + forwarded in all charge paths
- ExpMonth/ExpYear -> *int; URL-path id validation; CancelCheckout
  NOT_FOUND-only no-op (dropped unverified NOOP); exported ErrorCode/
  ErrorDetail helpers; mock rejects raw PANs, RList locks, redacts
  emails, ForceRefundPending hook

Backend - money safety:
- sweepManualPendingSquareRefunds reconciles rows WITH square_refund_id
  instead of stranding them forever
- SweepStalePendingPayments reconciles at Square before failing (tri-state:
  leave pending on transport error, rescue completed, fail definitively)
- GetCheckoutStatus cancellation-recheck; terminal CANCELED resolution;
  SweepStaleTerminalCheckouts covers terminal_checkouts table
- till gift-card clawback on definitive failure incl. retry path +
  INSUFFICIENT_FUNDS/ADDRESS_VERIFICATION_FAILURE/TRANSACTION_LIMIT
- cross-user saved-card collision fixed (UNIQUE(user_id,square_card_id))
- customer provisioning (lazy, save-only); one-off/guest mint no customer
- discount preview/apply unified in discounts.go (global-milestone visible
  in preview, N+1 eliminated, redemption counter preserved on failures)
- webhook event_id dedup; refund loop dedup; stale comment fixes
- test-isolation t.Cleanup on committed sweep tests

Frontend:
- SCA tokenizeWithVerification across all charge flows (amount as
  major-units decimal), 5-min token-expiry re-tokenize, verification_token
  in request bodies
- PaymentModal synchronous double-click + zero/negative-amount guards
- till online-card UI wired to /api/admin/till/sale
- policyPopover generalised; new /privacy-policy route; consent checkbox
  copy + Square privacy link
- Square card iframe styled to app typography (Inter 14px, oklch tokens);
  mock form md:text-sm parity
- 'Secure payment powered by Square' badge on all 8 card-payment flows

Schema/docs: terminal_checkouts + square_customer_id + per-user card
constraint in init-script.sql; README migrations; P14 plan + backlog +
Technical Manual updated.

Includes 39 modified/new test files; full backend suite (25 pkgs),
-race on payments+square, and frontend build are green.
2026-08-22 00:34:49 +01:00
popertots 52e2bfff55 Add dev-only frontend Square mock mode for as-if-live walkthroughs
VITE_SQUARE_ENVIRONMENT=mock renders a plain HTML card form (MockCardForm)
instead of the Square Web Payments SDK iframe, minting the same cnon: tokens
the backend dev mock accepts — all 8 payment flows run end-to-end locally with
zero credentials.

- isSquareMock() gated on import.meta.env.DEV: structurally impossible in a
  production build even if the env var is mis-set
- MockCardForm: Luhn/brand/expiry/CVC validation, Amex 15-digit + 4-digit CVC,
  error states, disabled propagation — mirrors the real form's onReady contract
  so CardSelection.isCardValid and submit guards behave identically
- tokenize() maps typed card -> deterministic cnon: token matching backend
  detectCardInfo (4242->test-card, 4111->visa, 5555->mastercard, 3782->amex)
- lazy-loaded via dynamic import: mock code ships in its own chunk, referenced
  only from the mock branch, never statically imported into the main bundle
- docs: .env.example (mock pairing with SQUARE_ENVIRONMENT=mock), P11 plan
  (mock opt-in + canonical-last4 caveat), Feature Catalog (2.1, 2.5)
- prettier formatting fixes in 10 unrelated files (line wrapping only)
2026-08-22 00:34:49 +01:00
popertots 7439fa86c1 Fix payment review round 3: saved-card idempotency, stale-pending sweep, webhook fail-closed
R1/R4: saved_card branch in CreateTerminalPayment now mirrors CreateTipPayment
- advisory lock (crussell:payment:<bookingID>) serializes concurrent double-clicks
- deterministic key bookingID-sc-type-amount-cardID (<=45 chars) so a lost-response
  retry derives the same key and dedups instead of double-charging
- idempotency switch inside the lock: completed -> dedup, pending -> reuse with
  pence amount-guard, failed -> clean 409
- success response includes card_brand/card_last4 (frontend already reads them)

R2: add 'failed' case to all four retry switches (tip, booking, gift card, till)
- a swept/definitively-rejected record returns 409 instead of 500-ing on the
  idempotency_key UNIQUE constraint

R3: extend SweepStalePendingPayments to till_sales card rows
- sweeps pending till_sales (online_square/in_person_card) past Square's ~24h
  key retention, closing the double-charge window for till sales
- swept rows logged with the same CRITICAL manual-reconciliation marker as the
  refund sweep

Webhook fail-closed: reject 503 when SQUARE_WEBHOOK_SIGNATURE_KEY unset, 403 on
bad signature (was: skip verification in dev)

Refund status resolution: refunds now resolve by Square status
(COMPLETED/PENDING/FAILED/REJECTED) instead of assuming completed; real error
codes (REFUND_AMOUNT_INVALID, PAYMENT_NOT_REFUNDABLE, REFUND_ALREADY_PENDING)
added to the definitive/processed classification

HTTP client: CreateCard key truncated to <=45 chars, device_options always sent
(env SQUARE_TERMINAL_DEVICE_ID fallback), processing_fee reads amount_money,
ListCards cursor loop, refund keys hashed to <=45 chars

Other fixes: payment/till/gift-card advisory-lock + FOR UPDATE asymmetries,
GetPaymentByID NULL scans, loyalty redemption lock, card upsert on conflict,
mock ccof: prefix parity, IsValidSquareCheckoutID for real Square IDs,
isAdminRequest defense-in-depth on all 6 admin payment handlers, webhook
signature docs, M8/L5 debug markers removed

Docs: README/FC/TM/Overview updated (22 jobs, 20 CRITICAL sites, 23-section
GDPR export, sweep jobs, webhook fail-closed); P11 plan marks remaining items
(sandbox smoke test, M-8 customer_id, saved-card key dedup trade-off) as
deferred with rationale; gap backlog pruned of completed items
2026-08-22 00:34:49 +01:00
popertots 9ff591fa4e Fix payment review round 2: refund idempotency, pending-resume safety, terminal-completion lock
Refund idempotency (P2):
- RefundRequest gains an optional client idempotency_key: two DISTINCT equal
  partial refunds of one payment no longer collide on the amount-derived key
  (the second was silently swallowed as a dedup)
- Extract resumeManualPendingRefund: resumes a pending refund with the row's
  OWN stored key, so Square's key dedup returns the original refund if the
  prior attempt completed — never issues a second
- (payment, amount) pending fallback: when the exact-key lookup misses (admin
  reopened the modal, new UUID), resume the matching pending row instead of
  creating a second pending row the sweep would double-process
- 409 in-flight guard: if a pending refund exists for the payment but no
  same-amount row matches, reject a different-amount refund (money state at
  Square is unknown — no new refund is safe until it resolves)
- Frontend (EditBookingModal): UUID per refund attempt, reused on retry,
  mirroring the tip flow

Terminal completion (P3):
- GetCheckoutStatus serializes on pg_advisory_lock('crussell:terminal:' ||
  SquarePayID) on a pinned connection — concurrent polls of the same checkout
  can no longer both pass the dedup SELECT and race the UNIQUE constraint

Card-on-file / doc-only:
- Document why CreateCardOnFile is NOT rolled back on payment failure
  (deterministic sha256 retry returns the same card; deletion breaks it)
- Document HasCompletedPayment's deliberate 'tip' exclusion

Regression tests:
- TestRefund_TwoEqualPartialRefunds_ClientKeyDisambiguates
- TestRefund_PendingResume_NewKeyAfterModalReopen (proves stored-key resume)
- TestRefund_PendingResume_DifferentAmountRejected (409 + no second row)
- TestRefund_GuardCountsPendingRefunds updated: 400 -> 409 (in-flight guard
  fires first — strictly safer, blocks before any Square attempt)
- TestGetCheckoutStatus_ConcurrentPolls_SingleRecord (real two-goroutine race)
2026-08-22 00:34:49 +01:00
popertots 53ca89603d Fix payment review round: till integrity, HTTP client tests, concurrency tests, card-selection consolidation
Addresses the payment review (all 10 blocking + 2 minor findings):

Till money-integrity (CreateTillSale):
- Add pg_advisory_lock on the idempotency key (concurrent same-key double-funding race)
- Guard amount on pending-reuse retry (mirrors tip/gift-card guards)
- Explicitly complete the row for cash/on_the_house pending-reuse
- Reject method-switch on a live card-machine checkout (double-charge guard)
- 3 regression tests (amount-mismatch, cash-completes-row, method-switch)

BookingFlow:
- Fetch saved cards at the deposit step (was dead code)
- Charge the server-computed deposit_amount, not the client estimate

HTTP client tests (was untested): doJSON error parsing, refund sentinel
classification, payment/refund/card wire shapes, checkout polling states,
list-refunds pagination + 20-page guard, sha256 card idempotency key

Concurrency regression tests: real two-goroutine races for BuyGiftCard,
tip, and booking-payment locks asserting exactly-one record each

Frontend:
- Fix CRIT-1: zero-saved-card users blocked (all flows now handle it)
- Consolidate tip/deposit/Buy-Gift-Card card UI onto CardSelection
- Explicit save-card consent checkbox (was silent/inconsistent)
- Fix stale saved-card field names in BookingFlow (last4 -> last_4)
- Unique instance ids (crypto.randomUUID) in CardSelection/SquareCardInput
- UserPaymentModal: keep card form mounted on error + Try Again button

Health/docs: /api/health reports square state (mock/ok, was not_implemented),
close P1 backlog, correct stale webhook and env-var claims
2026-08-22 00:34:49 +01:00
popertots 64d4b65083 Implement P11: Square Web Payments SDK new-card tokenization
Re-enable new-card entry across all 8 flows via Square Web Payments SDK
cnon: nonces (backend was already P11-ready):
- Add square.ts SDK loader (env-gated on VITE_SQUARE_APPLICATION_ID/LOCATION_ID,
  sandbox vs prod URL auto-derived from app-ID prefix) + SquareCardInput.svelte
  (tokenize() via bind:this, onReady state, CardEntryUnavailable fallback)
- CardSelection.svelte: replace newCardDisabled gate with new-card toggle +
  SquareCardInput; expose tokenize() for parent flows
- Wire new-card mode into tip x3, booking payment (UserPaymentModal), deposit
  (BookingFlow incl. guest), Buy a Gift Card + Add a Card (account), and admin
  till online_square (GiftCardsManagement create/topup)
- Retry-safe: each flow caches the one-shot nonce and reuses it on retry so the
  backend idempotency key dedups instead of re-tokenizing
- Docs: README, Gap Backlog P11, Feature Catalog, Technical Manual, P11 plan
2026-08-22 00:34:49 +01:00
popertots ae8735ba2f Close refund system and gate raw-PAN card entry
Refund system (Round 3 fixes + follow-up + alignment):
- Serialize cancellation refunds against the manual handler via
  per-payment advisory locks taken before the prior-refunds read
  (pg_advisory_xact_lock, ascending, same crussell:refund: key space)
- Aggregate pending cancellation refunds into ONE Square refund per
  charge (stable charge-level -square-agg key); atomic group UPDATE
  keeps crash-retry amounts identical for Square key-dedup
- Persist paymentID-square-amount idempotency keys on cancellation
  refunds; scheduler reads the stored key (legacy fallback for old rows)
- Add sweep-pending-square-refunds cron (*/5, concurrency 1) with
  refund_attempts cap; sweep retries stale manual pending refunds with
  each row's own stored idempotency key
- Reconcile at Square (GET /v2/refunds ListPaymentRefunds) before every
  terminal failed transition: tri-state result leaves rows pending on
  reconcile error instead of false-failing; PAYMENT_ALREADY_REFUNDED
  resolves to completed
- Move over-refund guard inside the lock, counting completed + pending
  (excluding failed); ErrRefundDeclined distinguishes definitive vs
  ambiguous outcomes
- forgiveFees now executes a real full refund (forceFullRefund override)
  with admin_forgiven_fees reason threaded to Square
- Surface failed card refunds in the admin notification centre
  (refund_failed enum, RETURNING-id pre-pass inserts, NOT EXISTS dedup)
- Dedup double-cancel refund inserts via ON CONFLICT (idempotency_key)
  DO NOTHING without consuming refundRemaining

Frontend:
- Remove all raw-PAN card entry: zero card_number/card_cvc/new_card_token
  in request bodies; gate new-card entry behind CardEntryUnavailable
  notice + newCardDisabled prop across all 8 flows
- Delete hand-rolled CardInput.svelte; keep CardSelection saved-card UI
  and CardEntryUnavailable fallback
- Update cancellation-policy page to in-person cash pickup wording

Tests:
- Rewrite the two amount-blind dedup tests to assert real money movement
  (single call, aggregated amount, shared refund ID)
- Add coverage: manual refund vs cancellation serialization (concurrent
  goroutines), reconcile error vs no-match branches, stale manual retry,
  forgive-fees real refund row + reason, double-cancel dedup, mock refund
  key dedup, ListPaymentRefunds filtering
- Fix time-dependent booking flakes with fixtures.NextWorkingDayAt
- 25/25 packages pass; -race clean on payments/square/db/jobs/bookings
2026-08-22 00:34:49 +01:00
popertots 54f6bf3c1a Fix P0/P1 review findings: truncation, raw-PAN API edge, refund lock, till pending-retry, idempotency keys
P0 — float truncation: applied math.Round to all remaining int64(x*100)
sites (till penceAmount, refund over-refund guard, GetAlreadyRefundedAmount,
payment summary conversions). A £1.14 till sale previously charged 113p.

P0 — raw PAN stopped at the API edge:
- Deleted CardNumber/CardExpMonth/CardExpYear/CardCVC from TillSaleRequest
  and CardNumber/Expiry/CVC from CreatePaymentMethodRequest. Both now accept
  card_token (Square nonce) and return 400 when absent. PAN+CVV no longer
  transit the application server (PCI-DSS SAQ-A scope).
- Deleted CreateCardOnFileRaw from the SquareClient interface and all
  implementations (MockClient, ProdClient, devProdClient).
- Added idempotency_key column to refunds table (UNIQUE).

P0 — RefundPayment hardened: advisory lock on payment ID (prevents two
concurrent refunds passing the over-refund guard), pending-refund-record-
then-Square pattern (scheduler reprocesses on failure), same-key dedup.

P1 — till sale pending-retry now re-attempts the Square charge instead of
returning the stale 'pending' status (gift card was already funded in the
committed tx — silent money loss otherwise). Sale row reused, not duplicated.

P1 — idempotency key caching in frontend: BuyGiftCard and
UserPaymentModal/BookingFlow now cache the key per amount+card, regenerated
on change and cleared on success — matches the tip-flow pattern so a
lost-response retry dedups instead of double-charging.

P1 — CreateTerminalPayment cash/giftcard INSERTs now persist idempotency_key.
Key is unique per payment (booking+type+amount would wrongly dedup two
legitimate identical payments, e.g. two £50 cash receipts).

P1 — gift-card codes no longer logged (spendable credential; value+recipient
only).

Tests: till pending-retry re-attempt, refund same-key dedup, mock CreatePayment
idempotency dedup, CreatePaymentMethod nonce happy path + raw-PAN rejection,
till online_square card_token required/valid.
2026-08-22 00:34:49 +01:00
popertots 73dd2c2dea Fix regression: UserPaymentModal 'Use a new card' overridden by auto-select effect
Move the saved-card auto-select effect INTO CardSelection, where it owns both
cards and showNewCardForm. The effect is guarded by !showNewCardForm so the
'Use a new card' click (selectedCardId = '') is not immediately re-set to the
default card — previously the parent's unguarded effect (moved from the OLD
showNewCardForm guard during the CardSelection refactor) silently charged the
saved default card instead of the newly entered card.

CardSelection mounts fresh each time the modal opens (conditional {#if}
mounting in UserBookingModal and BookingFlow), so the auto-select fires once
on load, exactly like the tip flows' one-shot load-time selection.
2026-08-22 00:34:49 +01:00
popertots 5a373a3b0b Unify card selection UI via reusable CardSelection component; fix Buy a Gift Card new-card bug
Create CardSelection.svelte reusable component encapsulating the standard
saved-card list + 'Use a new card' + CardInput pattern with blur-based
validation (Luhn, expiry, CVC) — identical to the tip flows and account page.

Refactor UserPaymentModal (Make a Payment submodal) to use CardSelection:
- Removed its bespoke 'Use a different card' expand/collapse UI and inline
  validation derivations (parseExpiryParts, isValidLuhn, touched state)
- Bound selectedCardId + new card fields to the component
- payButtonDisabled now driven by component's onValidityChange callback
- Removed now-unused CardInput import, SvelteDate import, formatCardExpiry

Fix account 'Buy a Gift Card' bug: 'Use a new card' click did nothing because
the auto-select effect immediately re-set buySelectedCard back to the default
card. Added buyShowNewCard flag so the effect only auto-selects on initial load;
reset after successful new-card purchase so the next purchase re-defaults.
2026-08-22 00:34:49 +01:00
popertots 28f0ddb328 Fix tip amount-change false dedup, wire BuyerEmail everywhere, clear ESLint errors
Money-moving fixes:
- Tip idempotency key regenerates when the tip amount changes after a failed
  attempt (all 3 tip flows). Cached key still reused on same-amount retry
  (dedup intact) and cleared on success/modal reset. Prevents silent
  under-charge when a user retries at a different amount.
- Till replay path returns actual till_sales.status (may be 'pending') instead
  of hardcoded 'completed' — no more misreported successful charge.
- BuyerEmail wired for CreateBookingPayment, gift card purchases, and till
  sales (saved_card + online_square), matching the tip flow. Email lookup
  errors logged, non-fatal.
- Till buyer-email errors now logged (was silently swallowed).
- on_the_house till top-up uses cached getIdempotencyKey() for retry-safe dedup
  (was fresh crypto.randomUUID()).

Test/validation fixes:
- Add TestPaymentFromSquare_* unit tests (else-branch + nil card details),
  build tag relaxed to 'test' so they run in the standard dev suite.
- Add TestValidateCardInfo table test (7 cases: both/either/neither/empty).
- Add TestCreateTillSale_TwoIdenticalCreateSales_BothSucceed regression test.
- Remove dead mock pre-registration in TestTipPayment_WithSavedCard.
- Correct misleading till regression-test comment.

ESLint cleanup (12 errors -> 0):
- Remove unused loadingCards in tip + pay-tip pages (dead assignments in
  loadSavedCards).
- Scoped eslint-disable for {@html} in CardBrandIcon (hardcoded brand SVGs).
- Remove dead confirmSaveDefaultHours + unused rescheduleVersion prop in
  WeeklySchedule (and its parent pass-through).
- Replace new Date() with SvelteDate in WeeklySchedule + BusinessHours.
- Fix each-block key in BusinessHours skeleton loader.
- Use void expression for reactivity-tracker reads in effects.
2026-08-22 00:34:49 +01:00
popertots 2459ddc919 Fix review findings: expiry bug (all 8 files), idempotency keys, card_expiry/card_cvc removal, URL encoding, BuyerEmail logging, ValidateCardInfo, saved-card test, future work doc
Backend:
- Fix refund idempotency key: clock.Now() → deterministic (pr.ID + amount)
- Fix ValidateCardInfo: enforce mutual exclusivity, handle empty strings symmetrically
- Fix paymentFromSquare brand fallback (remove dead SourceType fallback)
- Fix URL encoding: PathEscape → QueryEscape for customer_id query param
- Fix BuyerEmail: log warning on DB error instead of silent discard
- Fix idempotency key in createCardOnFileHTTP: time.Now() → deterministic hex hash
- Add BuyerEmail to CreateTipPayment Square request
- Move realBaseURL from shared file to square_dev.go (only used in dev)
- Add TestTipPayment_WithSavedCard test (card_id path coverage)
- Fix AMEX brand in mock (AMEX → AMERICAN_EXPRESS, fix test)

Frontend:
- Fix off-by-month expiry bug in ALL 8 files using year-month arithmetic
  (parseExpiryParts returns 1-indexed, SvelteDate expects 0-indexed)
  Files: tip/+page, pay-tip/[id], UserBookingModal, UserPaymentModal,
  BookingFlow, account/+page (add card + buy gift card sections)
- Remove card_expiry/card_cvc from tip request bodies (backend has no fields)

Docs:
- Mark P9 (placeholder tokens) as completed, add P11 (Square Web Payments SDK)
- Mark T13 (rune arithmetic) as completed
2026-08-22 00:34:49 +01:00
popertots 4abcb324c9 Square payment integration: real HTTP client, tip flow rewrite, card UI/validation overhaul
Backend:
- Create square_http_client.go: real Square REST API client (Payments, Terminal Checkouts, Refunds, Cards, Locations) with proper JSON types, auth, error handling
- Update ProdClient in square.go to delegate to shared HTTP functions
- Wire devProdClient in square_dev.go to also make real HTTP calls for sandbox/prod env
- Rewrite CreateTipPayment handler: accept card_id OR new_card_token (+save_card), advisory lock, idempotency check, max amount validation
- Add ValidateCardInfo, bump ValidateAmount max to £10,000
- Fix mock CreateCardOnFile to detect brand/last4 from raw card numbers
- Fix mock RefundPayment to index by SquarePayID and accept unknown payment IDs
- Remove dead types (ProcessingFee, sqAddress), add Deadline parity
- Fix AMEX brand inconsistency (AMEX -> AMERICAN_EXPRESS)
- Pre-existing fix: remove unused context import in giftcards.go

Frontend:
- CardInput.svelte: add onfieldblur/onfieldinput callbacks for blur-based validation
- CardBrandIcon.svelte: brand SVGs for VISA, MC, AMEX, Discover, Diners, JCB, Square Gift Card, UnionPay, Interac, EFTPOS
- tip/+page, pay-tip/[id], UserBookingModal tip: saved card list + CardInput + Luhn/expiry/CVC validation + blur-based errors + no-saved-cards edge case
- UserPaymentModal, BookingFlow: card validation parity (blur-based, all-valid check)
- account page: replace text brand badges with CardBrandIcon
- Fix handleCustomTip bug (state mutations outside if block)
- Remove dead pageState variable
- Add tip modal scroll (max-h-[90vh] overflow-y-auto)
- Submit button disabled on !isCardValid

Tests:
- 30 square package tests (+new: CreateCardOnFile raw number path, detectCardInfo variants)
- 5 tip handler tests (HappyPath, NoPriorPayment, WrongOwner, MultipleTips, TxFailure)
- All +-race clean, refund tests fixed
2026-08-22 00:34:49 +01:00
popertots f6caaab8a3 feat: redesign homepage, add global footer, fix carousel font
Homepage: restored original v0 design, replaced lorem ipsum with real service descriptions, added BusinessHours (Opening Hours) section, alternating bg-gray-50 section backgrounds. Layout: added global sticky footer (hidden on /admin/schedule, /account, and ?format=pdf pages), wrapped content in min-h-screen flex layout. PortfolioCarousel: set heading to Playfair Display.
2026-08-22 00:34:49 +01:00
popertots 51d29e6bd4 fix: remove card shadows from prices page to match site-wide border-style
All other pages (contact, admin, account, today, book) use border-based card styling without drop shadows. Removes shadow-sm, hover:shadow-md, and transition classes from all Card.Root instances on the prices page.
2026-08-22 00:34:49 +01:00
popertots 3c0c4dd962 feat: sort price list by booking popularity over last 6 months
Adds GET /api/services/popular endpoint that returns services sorted by booking count (desc) then price (desc) for ties. Prices page now fetches from this endpoint instead of the default alphabetical sort.
2026-08-22 00:34:49 +01:00
popertots 8384197ef0 fix: clear date selection when clicking an unavailable/closed day
bits-ui blocks onValueChange for unavailable dates, leaving stale selection. Adds native click detection on [data-unavailable] elements to call onchange(undefined) so the time picker hides and the user knows nothing was picked.
2026-08-22 00:34:49 +01:00
popertots a991642157 fix: show only differing days in scheduled hours change section
Replace unreactive @const with  for the changed-days filter. Normalize PostgreSQL microsecond times before comparing (TIME::text produces '17:00:00.000000' but staged hours are '17:00'). Change header text to 'These opening hours will change from' when fewer than 7 days differ.
2026-08-22 00:34:49 +01:00
popertots 0323313921 fix: add conflict re-check guard before saving holiday hours and time blockers
Re-check conflicts immediately before finalizing holiday hours and time blocker saves to prevent race conditions. Add Refresh button to conflict banners. Fix prettier formatting in login page.
2026-08-22 00:34:49 +01:00
popertots 6470a3f6c9 feat: add scheduled change UI and conflict display to weekly schedule
Convert WeeklySchedule to schedule staged changes with an effective date picker and conflict detection UI. Show pending scheduled changes in BusinessHours component. Update admin page to pass through props.
2026-08-22 00:34:49 +01:00
popertots 3eec71a56c fix: sanitize API error text display and add time_blockers tests
Add extractErrorMessage helper for JSON error body parsing and apply sanitizeText across all toast displays. Add time_blockers test coverage for new holiday placeholder cleanup and overlapping scenarios.
2026-08-22 00:34:48 +01:00
popertots 5deefa1205 fix: prevent empty login form submission
Fix isFormComplete derived always returning true for login mode. Now requires email and password to be non-empty before enabling Sign In button. Add early-return guard in handleSubmit to prevent sending empty credentials.
2026-08-22 00:34:48 +01:00
popertots 9170990340 feat: add conflict resolution UI to holiday hours modal
Add conflict detection to the Create Exception Schedule modal with auto-checking, amber warning display, and View Booking/View Client buttons. Wire openUserModal and openBookingModal props from admin page. Fix TimeBlockers placeholder duration from hardcoded 60 to booking.duration_minutes. Remove dead placeholder creation code (isFormValid prevents save while conflicts exist). Fix formatTime overwriting raw hour data with display strings.
2026-08-22 00:34:48 +01:00
popertots 04d5c21f8c feat: show live availability status on ContactCard 2026-08-22 00:34:48 +01:00
popertots bea1582088 feat: add BusinessHours component and update contact page 2026-08-22 00:34:48 +01:00
popertots 24af3a1fca fix: enable eslint-plugin-svelte a11y rules and fix violations
CI / Env docs check (push) Successful in 30s
CI / Nginx config check (push) Successful in 37s
CI / Docker compose check (push) Successful in 38s
CI / Frontend deps check (push) Successful in 46s
CI / Frontend major deps (push) Successful in 51s
CI / Secrets scan (push) Successful in 52s
CI / Go build (push) Successful in 56s
CI / Frontend build (push) Successful in 1m9s
CI / Knip (push) Successful in 46s
CI / Go vet (prod) (push) Successful in 1m59s
CI / Frontend a11y check (push) Successful in 2m7s
CI / Go vet (dev) (push) Successful in 2m4s
CI / go mod tidy (push) Successful in 25s
CI / Staticcheck (prod) (push) Successful in 2m43s
CI / Frontend QC (audit) (push) Successful in 1m39s
CI / Staticcheck (dev) (push) Successful in 3m47s
CI / Go vulnerabilities (push) Successful in 1m48s
CI / golangci-lint (push) Successful in 3m57s
CI / Frontend QC (typecheck) (push) Successful in 1m49s
CI / Security scan (prod) (push) Successful in 4m1s
CI / Security scan (dev) (push) Successful in 4m30s
CI / Frontend QC (lint) (push) Successful in 2m5s
CI / Svelte strict check (push) Failing after 988h42m2s
CI / Race (dev) (push) Failing after 988h42m18s
CI / Race (prod) (push) Failing after 988h42m19s
CI / Tests (dev) (push) Failing after 988h42m19s
CI / Tests (prod) (push) Failing after 988h42m20s
2026-07-11 18:17:49 +01:00
popertots 8ae592d0c5 fix: add golangci config, restore CI timeouts, svelte-check warnings, RespondError helper
CI / Env docs check (push) Successful in 13s
CI / Nginx config check (push) Successful in 36s
CI / Frontend major deps (push) Successful in 37s
CI / Docker compose check (push) Successful in 38s
CI / Frontend deps check (push) Successful in 41s
CI / Secrets scan (push) Successful in 42s
CI / Go build (push) Successful in 42s
CI / Frontend build (push) Successful in 49s
CI / go mod tidy (push) Successful in 26s
CI / Go vet (dev) (push) Has been cancelled
CI / Go vet (prod) (push) Has been cancelled
CI / golangci-lint (push) Has been cancelled
CI / Staticcheck (dev) (push) Has been cancelled
CI / Staticcheck (prod) (push) Has been cancelled
CI / Security scan (dev) (push) Has been cancelled
CI / Security scan (prod) (push) Has been cancelled
CI / Tests (prod) (push) Has been cancelled
CI / Tests (dev) (push) Has been cancelled
CI / Race (prod) (push) Has been cancelled
CI / Race (dev) (push) Has been cancelled
CI / Go vulnerabilities (push) Has been cancelled
CI / Knip (push) Has been cancelled
CI / Frontend a11y check (push) Has been cancelled
CI / Svelte strict check (push) Has been cancelled
CI / Frontend QC (audit) (push) Has been cancelled
CI / Frontend QC (typecheck) (push) Has been cancelled
CI / Frontend QC (lint) (push) Has been cancelled
2026-07-11 17:38:50 +01:00
popertots 7d6cb0c375 fix: prettier formatting on EditRequestModal.svelte
CI / Docker compose check (push) Successful in 14s
CI / Env docs check (push) Successful in 14s
CI / Nginx config check (push) Successful in 16s
CI / Frontend deps check (push) Successful in 52s
CI / Frontend major deps (push) Successful in 51s
CI / Frontend build (push) Successful in 1m8s
CI / Secrets scan (push) Successful in 1m8s
CI / Go build (push) Successful in 1m8s
CI / Knip (push) Successful in 45s
CI / Go vet (prod) (push) Successful in 1m19s
CI / Go vet (dev) (push) Successful in 1m37s
CI / Frontend a11y check (push) Successful in 2m21s
CI / go mod tidy (push) Successful in 51s
CI / Frontend QC (audit) (push) Successful in 37s
CI / Staticcheck (prod) (push) Successful in 3m34s
CI / Staticcheck (dev) (push) Successful in 3m35s
CI / golangci-lint (push) Successful in 3m37s
CI / Frontend QC (typecheck) (push) Successful in 1m52s
CI / Go vulnerabilities (push) Successful in 2m26s
CI / Security scan (prod) (push) Successful in 4m9s
CI / Security scan (dev) (push) Successful in 4m43s
CI / Frontend QC (lint) (push) Successful in 2m12s
CI / Svelte strict check (push) Successful in 1m23s
CI / Tests (prod) (push) Successful in 3m25s
CI / Tests (dev) (push) Successful in 3m24s
CI / Race (prod) (push) Successful in 7m7s
CI / Race (dev) (push) Successful in 7m32s
2026-07-11 16:37:33 +01:00
popertots c8051a76d6 fix: replace time.Sleep with poll loops in tests, fix a11y target=_blank violations
CI / Env docs check (push) Successful in 16s
CI / Nginx config check (push) Successful in 22s
CI / Docker compose check (push) Successful in 23s
CI / Frontend major deps (push) Successful in 23s
CI / Frontend deps check (push) Successful in 28s
CI / Secrets scan (push) Successful in 36s
CI / Go build (push) Successful in 37s
CI / Frontend build (push) Successful in 43s
CI / Knip (push) Successful in 52s
CI / Frontend a11y check (push) Successful in 1m48s
CI / Go vet (prod) (push) Successful in 1m36s
CI / Go vet (dev) (push) Successful in 2m11s
CI / go mod tidy (push) Successful in 1m0s
CI / Frontend QC (audit) (push) Successful in 35s
CI / Staticcheck (prod) (push) Successful in 2m47s
CI / Staticcheck (dev) (push) Successful in 3m4s
CI / golangci-lint (push) Successful in 3m24s
CI / Go vulnerabilities (push) Successful in 1m52s
CI / Frontend QC (lint) (push) Failing after 1m2s
CI / Frontend QC (typecheck) (push) Successful in 1m23s
CI / Svelte strict check (push) Has been skipped
CI / Security scan (prod) (push) Successful in 4m15s
CI / Security scan (dev) (push) Successful in 4m54s
CI / Tests (prod) (push) Successful in 3m48s
CI / Tests (dev) (push) Failing after 4m2s
CI / Race (prod) (push) Failing after 7m15s
CI / Race (dev) (push) Failing after 7m20s
2026-07-11 16:16:23 +01:00
popertots d410dce0e0 fix: gift card friend purchase notifies admin, frontend no longer falsely claims email sent 2026-07-11 14:39:54 +01:00
popertots 28620f69a5 fix: restore dead functions properly, match test expectations, fix vet/lint
CI / Docker compose check (push) Successful in 13s
CI / Env docs check (push) Successful in 14s
CI / Nginx config check (push) Successful in 14s
CI / Frontend major deps (push) Successful in 25s
CI / Frontend deps check (push) Successful in 25s
CI / Secrets scan (push) Successful in 39s
CI / Go build (push) Successful in 39s
CI / Frontend build (push) Successful in 45s
CI / Knip (push) Successful in 27s
CI / Frontend a11y check (push) Successful in 1m27s
CI / Go vet (prod) (push) Successful in 1m53s
CI / go mod tidy (push) Successful in 43s
CI / Go vet (dev) (push) Successful in 2m6s
CI / Frontend QC (audit) (push) Successful in 45s
CI / Staticcheck (prod) (push) Successful in 2m51s
CI / Staticcheck (dev) (push) Successful in 3m5s
CI / Frontend QC (typecheck) (push) Successful in 1m50s
CI / Go vulnerabilities (push) Successful in 2m8s
CI / golangci-lint (push) Failing after 4m3s
CI / Security scan (prod) (push) Successful in 4m35s
CI / Security scan (dev) (push) Successful in 4m47s
CI / Tests (prod) (push) Has been skipped
CI / Tests (dev) (push) Has been skipped
CI / Race (prod) (push) Has been skipped
CI / Race (dev) (push) Has been skipped
CI / Frontend QC (lint) (push) Successful in 2m8s
CI / Svelte strict check (push) Successful in 38s
2026-07-11 13:23:27 +01:00
popertots 294d844493 fix: replace {__} workaround with clean range() helper in Svelte templates 2026-07-11 12:50:13 +01:00
popertots d172adf392 fix: enable svelte a11y linting and fix violations 2026-07-11 12:41:10 +01:00
popertots ae2acc45c3 chore: bump eslint 9.39.4 -> 9.39.5
CI / Env docs check (push) Successful in 1m46s
CI / Docker compose check (push) Successful in 51s
CI / Nginx config check (push) Successful in 55s
CI / Frontend deps check (push) Successful in 1m52s
CI / Frontend major deps (push) Failing after 1m6s
CI / Go build (push) Successful in 2m14s
CI / Frontend build (push) Successful in 1m29s
CI / Secrets scan (push) Successful in 2m26s
CI / Knip (push) Successful in 1m4s
CI / Frontend a11y check (push) Successful in 2m18s
CI / Go vet (prod) (push) Successful in 1m51s
CI / Go vet (dev) (push) Successful in 2m11s
CI / go mod tidy (push) Successful in 40s
CI / Staticcheck (prod) (push) Successful in 2m43s
CI / Frontend QC (audit) (push) Successful in 58s
CI / Go vulnerabilities (push) Successful in 1m27s
CI / Staticcheck (dev) (push) Successful in 3m20s
CI / golangci-lint (push) Successful in 3m30s
CI / Frontend QC (typecheck) (push) Successful in 1m26s
CI / Frontend QC (lint) (push) Successful in 1m54s
CI / Security scan (dev) (push) Successful in 4m38s
CI / Security scan (prod) (push) Successful in 4m2s
CI / Svelte strict check (push) Successful in 57s
CI / Tests (prod) (push) Failing after 3m55s
CI / Tests (dev) (push) Failing after 4m9s
CI / Race (prod) (push) Failing after 7m35s
CI / Race (dev) (push) Failing after 7m44s
2026-07-11 00:31:40 +01:00
popertots 1e4460271b fix: fix frontend a11y and lint errors 2026-07-11 00:21:31 +01:00
popertots d787c9a94e fix: remove duplicate green lunch warning, green card always shows Time selected
CI / Nginx config check (push) Successful in 18s
CI / Docker compose check (push) Successful in 19s
CI / Env docs check (push) Successful in 58s
CI / Frontend deps check (push) Successful in 36s
CI / Frontend major deps (push) Failing after 37s
CI / Secrets scan (push) Successful in 1m21s
CI / Go build (push) Successful in 45s
CI / Frontend build (push) Successful in 53s
CI / Frontend a11y check (push) Failing after 16s
CI / Knip (push) Successful in 26s
CI / Go vet (prod) (push) Successful in 1m37s
CI / Go vet (dev) (push) Successful in 1m38s
CI / go mod tidy (push) Successful in 1m38s
CI / Frontend QC (audit) (push) Successful in 1m46s
CI / Go vulnerabilities (push) Successful in 1m57s
CI / Staticcheck (prod) (push) Successful in 3m35s
CI / golangci-lint (push) Successful in 3m38s
CI / Staticcheck (dev) (push) Successful in 3m39s
CI / Security scan (dev) (push) Successful in 4m3s
CI / Frontend QC (lint) (push) Failing after 58s
CI / Frontend QC (typecheck) (push) Successful in 2m36s
CI / Svelte strict check (push) Has been skipped
CI / Security scan (prod) (push) Successful in 4m29s
CI / Tests (prod) (push) Successful in 2m41s
CI / Tests (dev) (push) Failing after 2m55s
CI / Race (prod) (push) Successful in 6m50s
CI / Race (dev) (push) Successful in 7m14s
2026-07-10 21:27:34 +01:00
popertots a2b4f84503 chore: bump @eslint/js 9.39.4 → 9.39.5
CI / Env docs check (push) Successful in 1m14s
CI / Secrets scan (push) Successful in 1m17s
CI / Go build (push) Successful in 1m17s
CI / Frontend deps check (push) Successful in 1m17s
CI / Frontend major deps (push) Failing after 1m11s
CI / Docker compose check (push) Successful in 1m38s
CI / Nginx config check (push) Successful in 1m40s
CI / Go vet (dev) (push) Has been cancelled
CI / Go vet (prod) (push) Has been cancelled
CI / golangci-lint (push) Has been cancelled
CI / Staticcheck (dev) (push) Has been cancelled
CI / Staticcheck (prod) (push) Has been cancelled
CI / Security scan (dev) (push) Has been cancelled
CI / Security scan (prod) (push) Has been cancelled
CI / go mod tidy (push) Has been cancelled
CI / Tests (prod) (push) Has been cancelled
CI / Tests (dev) (push) Has been cancelled
CI / Race (prod) (push) Has been cancelled
CI / Race (dev) (push) Has been cancelled
CI / Go vulnerabilities (push) Has been cancelled
CI / Knip (push) Has been cancelled
CI / Frontend a11y check (push) Has been cancelled
CI / Frontend build (push) Has been cancelled
CI / Svelte strict check (push) Has been cancelled
CI / Frontend QC (audit) (push) Has been cancelled
CI / Frontend QC (typecheck) (push) Has been cancelled
CI / Frontend QC (lint) (push) Has been cancelled
2026-07-10 21:25:22 +01:00
popertots 7833e87aab fix: add split-lunch detection with formatted time range warnings
CI / Env docs check (push) Successful in 29s
CI / Frontend deps check (push) Failing after 27s
CI / Knip (push) Has been skipped
CI / Frontend a11y check (push) Has been skipped
CI / Docker compose check (push) Successful in 20s
CI / Nginx config check (push) Successful in 43s
CI / Frontend major deps (push) Failing after 52s
CI / Go build (push) Successful in 1m5s
CI / Secrets scan (push) Successful in 1m8s
CI / Frontend build (push) Successful in 53s
CI / Svelte strict check (push) Has been skipped
CI / Frontend QC (audit) (push) Has been skipped
CI / Frontend QC (typecheck) (push) Has been skipped
CI / Frontend QC (lint) (push) Has been skipped
CI / go mod tidy (push) Successful in 1m17s
CI / Go vet (dev) (push) Successful in 1m47s
CI / Go vet (prod) (push) Successful in 2m2s
CI / Go vulnerabilities (push) Successful in 1m24s
CI / Staticcheck (prod) (push) Successful in 2m54s
CI / Staticcheck (dev) (push) Successful in 3m4s
CI / golangci-lint (push) Successful in 3m24s
CI / Security scan (prod) (push) Successful in 4m29s
CI / Security scan (dev) (push) Successful in 4m29s
CI / Tests (prod) (push) Has been cancelled
CI / Tests (dev) (push) Has been cancelled
CI / Race (prod) (push) Has been cancelled
CI / Race (dev) (push) Has been cancelled
2026-07-10 21:16:59 +01:00
popertots 7c8fd94fcb fix: restore admin lunch warning tier (30-60min) with gap-worsening comparison
CI / Nginx config check (push) Successful in 25s
CI / Docker compose check (push) Successful in 25s
CI / Env docs check (push) Successful in 26s
CI / Frontend major deps (push) Failing after 26s
CI / Frontend deps check (push) Successful in 34s
CI / Secrets scan (push) Successful in 38s
CI / Go build (push) Successful in 38s
CI / Frontend build (push) Successful in 44s
CI / Frontend a11y check (push) Failing after 31s
CI / Knip (push) Successful in 42s
CI / go mod tidy (push) Successful in 31s
CI / Go vet (prod) (push) Successful in 1m58s
CI / Go vet (dev) (push) Successful in 2m15s
CI / Frontend QC (audit) (push) Successful in 1m37s
CI / Staticcheck (prod) (push) Successful in 3m39s
CI / Go vulnerabilities (push) Successful in 2m48s
CI / golangci-lint (push) Successful in 4m36s
CI / Staticcheck (dev) (push) Successful in 4m47s
CI / Frontend QC (typecheck) (push) Successful in 2m42s
CI / Security scan (dev) (push) Successful in 4m57s
CI / Security scan (prod) (push) Successful in 4m33s
CI / Tests (prod) (push) Has been cancelled
CI / Tests (dev) (push) Has been cancelled
CI / Race (prod) (push) Has been cancelled
CI / Race (dev) (push) Has been cancelled
CI / Svelte strict check (push) Has been cancelled
CI / Frontend QC (lint) (push) Has been cancelled
2026-07-10 21:10:00 +01:00
popertots 50ce98d729 fix: remove dead GenerateRefreshToken calls (tokens never consumed) 2026-07-10 20:52:47 +01:00
popertots e896591098 chore: upgrade npm deps — vite 8, prettier plugins, @types/node, @eslint/compat
CI / Docker compose check (push) Successful in 14s
CI / Env docs check (push) Successful in 15s
CI / Nginx config check (push) Successful in 18s
CI / Frontend deps check (push) Successful in 27s
CI / Frontend major deps (push) Failing after 27s
CI / Go build (push) Successful in 35s
CI / Secrets scan (push) Successful in 41s
CI / Frontend build (push) Successful in 43s
CI / Knip (push) Successful in 28s
CI / Frontend a11y check (push) Successful in 1m35s
CI / Go vet (prod) (push) Successful in 2m11s
CI / go mod tidy (push) Successful in 42s
CI / Go vet (dev) (push) Successful in 2m18s
CI / Frontend QC (audit) (push) Successful in 48s
CI / Staticcheck (prod) (push) Successful in 2m57s
CI / Staticcheck (dev) (push) Successful in 3m1s
CI / Go vulnerabilities (push) Successful in 1m27s
CI / golangci-lint (push) Successful in 3m41s
CI / Frontend QC (typecheck) (push) Successful in 1m35s
CI / Frontend QC (lint) (push) Successful in 1m51s
CI / Security scan (prod) (push) Successful in 4m29s
CI / Security scan (dev) (push) Successful in 4m44s
CI / Svelte strict check (push) Successful in 1m49s
CI / Tests (prod) (push) Successful in 3m30s
CI / Tests (dev) (push) Successful in 3m57s
CI / Race (prod) (push) Successful in 7m14s
CI / Race (dev) (push) Successful in 7m25s
Upgrades applied:
  @types/node: 22.20.1 → 26.1.1
  @eslint/compat: 1.4.1 → 2.1.0
  prettier-plugin-tailwindcss: 0.7.4 → 0.8.0
  prettier-plugin-svelte: 3.5.2 → 4.1.1 (formatted textarea.svelte)
  vite: 7.3.6 → 8.1.4
  @sveltejs/vite-plugin-svelte: 6.2.4 → 7.2.0

Left at current (blocked by deps chain):
  eslint / @eslint/js — typescript-eslint needs eslint 10 support
  typescript — typescript-eslint needs TS 7 support

Added CI TODO note for when vite-plugin-svelte-inspector catches up.
2026-07-10 20:03:41 +01:00
popertots c0442d4ebd ci: enable coverage on Tests (prod), remove unrealistic threshold, fix prettier
CI / Env docs check (push) Successful in 20s
CI / Nginx config check (push) Successful in 20s
CI / Frontend major deps (push) Failing after 26s
CI / Docker compose check (push) Successful in 30s
CI / Frontend deps check (push) Successful in 32s
CI / Secrets scan (push) Successful in 1m0s
CI / Go build (push) Successful in 1m1s
CI / Frontend build (push) Successful in 1m0s
CI / Knip (push) Successful in 58s
CI / Go vet (prod) (push) Successful in 1m38s
CI / Frontend a11y check (push) Successful in 2m12s
CI / Go vet (dev) (push) Successful in 2m2s
CI / go mod tidy (push) Successful in 35s
CI / Frontend QC (audit) (push) Successful in 39s
CI / Staticcheck (prod) (push) Successful in 2m59s
CI / Go vulnerabilities (push) Successful in 1m26s
CI / Staticcheck (dev) (push) Successful in 3m15s
CI / golangci-lint (push) Successful in 3m31s
CI / Frontend QC (typecheck) (push) Successful in 1m31s
CI / Frontend QC (lint) (push) Successful in 2m14s
CI / Security scan (prod) (push) Successful in 4m32s
CI / Security scan (dev) (push) Successful in 5m2s
CI / Svelte strict check (push) Successful in 28s
CI / Tests (prod) (push) Successful in 1m54s
CI / Tests (dev) (push) Failing after 2m20s
CI / Race (prod) (push) Successful in 3m41s
CI / Race (dev) (push) Successful in 5m15s
2026-07-10 13:18:23 +01:00
popertots 990c86495c fix: suppress unused nonDepositPaymentType in prod-staticcheck
CI / Docker compose check (push) Successful in 1m6s
CI / Env docs check (push) Successful in 1m6s
CI / Frontend deps check (push) Successful in 1m9s
CI / Frontend major deps (push) Failing after 1m9s
CI / Secrets scan (push) Successful in 1m9s
CI / Go build (push) Successful in 1m10s
CI / Frontend build (push) Successful in 1m10s
CI / Nginx config check (push) Successful in 1m12s
CI / Knip (push) Successful in 25s
CI / Go vet (prod) (push) Successful in 2m1s
CI / Frontend a11y check (push) Successful in 2m13s
CI / Go vet (dev) (push) Successful in 2m20s
CI / go mod tidy (push) Successful in 1m18s
CI / Staticcheck (prod) (push) Successful in 3m23s
CI / Staticcheck (dev) (push) Successful in 3m25s
CI / golangci-lint (push) Successful in 3m51s
CI / Frontend QC (audit) (push) Successful in 2m9s
CI / Security scan (prod) (push) Successful in 4m5s
CI / Security scan (dev) (push) Successful in 4m31s
CI / Go vulnerabilities (push) Successful in 2m22s
CI / Frontend QC (lint) (push) Failing after 1m11s
CI / Frontend QC (typecheck) (push) Successful in 1m21s
CI / Svelte strict check (push) Has been skipped
CI / Tests (prod) (push) Successful in 1m52s
CI / Tests (dev) (push) Failing after 2m12s
CI / Race (prod) (push) Successful in 3m31s
CI / Race (dev) (push) Successful in 5m0s
2026-07-10 13:00:33 +01:00
popertots 19d1d8dd47 fix: correct prop names in Svelte templates after a11y cleanup 2026-07-10 12:27:08 +01:00