509b2d926d8aa2031d61c4b2b2979e13b3f4e136
23
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
d90e25d1ff |
fix: auth/2FA — password change requires 2FA gate, admin self-deletion blocked, twofa JSON responses, per-IP email-verify budget, OptionalAuth log sanitised
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> |
||
|
|
9a12a2d886 |
fix: round-3 — tip gate asymmetry, webhook VAT align + 503 notifications, cash-tip campaign overcharge, lockout DoS, erasure durability, S3 retry cap, env parsing, per-user rate limiters, consume dead code, frontend 2FA remnants
- tip gate: CreateTipPayment saved-card 2FA gate now has scaTokenizedSavedCard skip matching every other charge surface (booking, terminal, gift-card); isSCATokenizeResultShape escape added to tip SAVE gate - webhook: align UPDATE clears VAT fields before re-apply (matches sweep rescue); 503 unknown-event tracking with 24h timeout notification via square_webhook_events table - cash-tip: cashChargeBasePence no longer restores campaign or subtracts loyalty — overcharge and tip shortfall fixed; 2FA dead code remnants removed from gift-card buy flow; TwoFactorCodeInput help text deconfused; refund pre-fill unit mismatch fixed (pounds vs pence); SCA buyer names split from full_name; passwordless delete UI accepts empty password - lockout: successful current-password clears shared failed_attempts/locked_until (victim can recover from login lockout via password change); passwordless delete condition changed to require 2FA only in enforced env - erasure: stale-guest batch erasure persists Square card/customer targets to durable outbox before NULLing them (crash-safe); S3 deletion retry capped at 10 attempts with admin notification; S3_PROFILE_PICS_BUCKET startup check added - env parsing: IsExplicitDevOrMockEnv and Square HTTP client base-URL switch now normalize (ToLower+TrimSpace) for consistency - auth: change-password/delete-account get per-user rate limiters (10/min); consume param dead code suppressed with TODO - frontend: 2FA/SCA dead code removed from gift-card buy flow, TwoFactorCodeInput help text fixed, refund pre-fill unit mismatch fixed, buyer names populated from full_name Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) |
||
|
|
62dca184df |
fix: account security + GDPR erasure — current-password lockout budgets (atomic 15/30/60 escalation, uniform 401), DAV + S3 deletion durable in-tx, batch erasure outbox
- ChangePassword/DeleteAccount: failed-attempt lockout matching login escalation, atomic check-increment (no burst), uniform 401 with distinct bodies, passwordless accounts require 2FA unconditionally to delete, NULL-password change-password clear error - erasure: CardDAV dav_cards rows deleted inside the erasure transaction (was fire-and-forget goroutine); S3 profile-pic deletion via pending_s3_deletions outbox + retry job; stale-guest/idle-account batch paths write the outbox in-tx and skip the guessed-bucket fallback - S3_PROFILE_PICS_BUCKET unset -> fail-closed warning (once per process) - scheduler test: 27 jobs (retry-s3-deletions) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) |
||
|
|
4e398a7a2b |
fix: round-2 loop-B adversarial (503c326 baseline) — B1 webhook race, APPROVED refund semantics, notification cap single-source, 2FA cooldown/StateFor hardening, register bcrypt semaphore
Round 2 Loop B red-team (money/security/dup-mod adversarial) findings on the full payments overhaul: MONEY: - HIGH: webhook COMPLETED promotion now resolves the B1 parent row (mirrors the re-poll resolveB1ParentFailed + till-sale clawback) — the sweep no longer re-replays an expired key into stacked unauthorized charges - HIGH: A6 deposit-with-discount clamp — chargeAmount capped to max(0, remaining-discount) for ALL discount cases; overflow guard compares against the discounted remaining - MED-HIGH: APPROVED refunds treated as NON-terminal at the webhook (event-driven, may still fail); payments call sites aligned; FAILED can now demote an APPROVED-then-failed row - MED: B1 refund transport-error fails the row + CRITICAL immediately (no 3-charge stacking) - MED: till_sales capped-fail surfaces the outstanding funding (gift_card_transactions trace) for manual reversal - MED: guest-bookings cash/gift-card terminal charges now audited (NULL target); audit reordered post-commit; cancellation refunds audited - MED: A6 no-discount skip-path returns campaign_fully_redeemed 400 (no success-shaped no-op); skip-path writes a marker row for idempotency SECURITY: - HIGH: notification cap centralized in adminnotify (MaxUnacknowledgedCriticalLogs) + applied at ALL insert sites (webhooks x2, jwt refresh_token_reuse, account erasure, sweep, twofa) with suppressed-insert logging; per-issue bucket for reissue alerts - MED-HIGH: twofa.StateFor saturated state made IMMUTABLE (LastMintAt writes are no-ops; no cross-user throttling); eviction never drops in-window count>0 records - MED: /register now uses the shared bcrypt semaphore (authBcryptSlots, 20) — botnet CPU burn bounded - MED: NAT collateral reduced (429-reject only at top progressive tier; lower tiers sleep) - MED: ClearMintCooldownForUser exposed for fresh-charge success; reissue cooldown-skip raises a capped alert - LOW: audit coverage gaps (reschedule fee forgiveness, gift-card transfer, clawback) closed DUP/MOD: - Frontend deposit-percent literals -> POLICY constants (10 sites); LOYALTY_DISCOUNT_RATE single-sourced; generateUUID adopted; admin PaymentModal overflow-tip confirm path added; £500 gift-card cap named Verified: 26/26 dev + 24/24 prod (CI condition), both vet tags, frontend tests+build, env-docs 42/42. |
||
|
|
9a182db932 |
fix: full-scope review — tip-inclusive amount_due, sweep deposit-strand, A6 clamp cap, B13 clawback, 2FA single-use, mint audit, account-deletion re-auth, refresh dedup
Full-scope Loop A restart review (18 findings across money/security/dup-mod): MONEY: - HIGH: amount_paid/amount_due CTEs now exclude payment_type='tip' (bookings.go x6, today.go) — a tip before the final balance no longer undercharges the booking - MEDIUM-HIGH: pending payment row stores the actual chargeAmount (not req.Amount) so the sweep replay amount-match rescues deposit-with-discount rows instead of auto-refunding them; refundSweepDuplicateCharge refunds the replayed payment's actual amount - MEDIUM: A6 deposit clamp-up now caps at the discounted obligation (remainingPence - eligibleDiscountPence) — no more silent overcharge when a campaign discount >= deposit - MEDIUM: B13 campaign-loss balance credits are clawed back on cancellation (clawbackB13CampaignCredit in ProcessCancellationRefundTx) - LOW: replayLegitimateRetryWindow extended 22h->24h so a legitimate same-key retry in the retry-eligible window is rescued, not auto-refunded SECURITY: - 2FA single-use strengthened (consume-at-gate for fresh charges, re-issue on failure) - Admin 2FA mint now writes admin_audit_log + logs code reuse - Account deletion requires current password (and 2FA when enforced) — stolen token can no longer destroy the account - Multi-tab refresh-token replay deduped via cross-tab lock (no false family-kill alerts) - family-alive cache invalidated on password change / GDPR erasure - Login lockout keyed per user+IP with a capped ceiling FRONTEND/DUP-MOD: - OverflowTipConfirm shared component (UserPaymentModal + BookingFlow); overflow computation aligned (deposit-discount-aware) - PaymentModal admin 2FA gate now method-conditioned (no over-reveal on cash/giftcard) - requestTwoFactorCode shared helper (requestNewTwoFactorCode + adminRequestNewTwoFactorCode) - BookingFlow deposit display aligned to the discounted amount; formatCurrency used consistently 26/26 backend packages; 80/80 frontend tests + build; env-docs 41/41. |
||
|
|
78e6d00dc5 |
fix: payments review rounds — money-safety, GDPR, security, gift-card cancel, modal stacking
Money-safety: - Deterministic till idempotency fallback (Square-charging only); cash/on_the_house keep unique keys; £250 till gift-card cap; 45-char key validation - Gift-card admin caps £250/tx + £5,000/day; user buy £500/day; BuyGiftCard allowlist unchanged - CancelGiftCard: CCR 2013 14-day right with partial-spend refund of the unspent balance (spend verified via payments.gift_card_id); atomic vs redeem/transfer; refunds stay pending until reversal commits; admin cancel surface (AdminCancelGiftCard) - Sweep: cancelled-booking charges failed+notified instead of silently completed; source-override replay uses live square_source_id; legacy square-less refund sweep; snapshot refresh on pending reuse - Refund lock consolidation; recordTerminalPaymentTx shared recorder; structured Square error codes; terminal checkout CustomerID GDPR / security: - Notes retained as de-identified medical/safety record at erasure (single field treated as health data; rest of record wiped, no re-identification map) + comments updated per UK GDPR/Art 9/Equality Act 2010 - square_request_snapshot PII scrubbed on all erasure paths; delete_guest_user FK unlinks; verification codes + dispute reasons handled; idle/stale-guest erasure deletes Square cards/customers + CardDAV/R2 - Durable square-erasure outbox job (retry-square-erasures); 2FA dev/prod build split, pepper fail-closed, no prod code-in-log; prod 2FA delivery fail-loud without a channel - Webhook unknown-type family split (non-money acked, money retried); untracked dispute notifications; rate-limit CF/X-Real-IP trust gating; nginx CSP nonce + api_limit Frontend: - Dynamic z-index stack (ui/dialog/zindex.ts) claimed in open order via data-state observer; re-claims on every reopen; removes stale !z-* overrides — nested modals (booking→user→booking) always paint newest-on-top (browser-verified 3-level + reopen) - Mobile: iOS zoom fixes, bottom-sheet dialogs, 44px touch targets, inputmode decimal, dvh - Gift-card buy/cancel UI, admin £250 + daily limits, cancellation/privacy/terms policy accuracy S3: - Connect() creates buckets before probing; in-memory fallback only on genuine unreachability; health reports degraded; stale S3_PUBLIC_URL documented (host-specific) Tests/docs: - 2263 test functions; all 22 backend packages green; round8/9/10 regression suites; NextEditWindowTime removes wall-clock flake; docs reconciled (notes retention, gift-card partial-use, modal T15 future work) |
||
|
|
9bb812669e |
fix: fresh-review round — 2FA deliverability, disable re-verification, GDPR batch scrub, dispute alerting, docs accuracy
Second fresh-eyes review pass (7 agents: goal, security, code-quality, context-mining, webhooks+2FA, client+mock+sweep, refunds/giftcards/handlers). Money-safety core verified sound (identical-body replay byte-lossless, clawback gated on definitive proof, no double-charge window). This round fixes the issues the fresh pass surfaced: 2FA: - Setup now DELIVERS the code via the [2FA] server log in ALL modes (was: nothing in enforced mode -> production 2FA was an unbreakable dead-end and saved-card charges were permanently 403). Enforced mode still withholds the code from the API response; the log line is the fake delivery channel until email/SMS lands (P6). - Disabling 2FA now requires a fresh verification code when enforcement is ON (previously ignored the code -> a password-only attacker could lift the gate). Shares the 5-attempt lockout and timing-safe compare. Dev bypass retained. - REQUIRE_2FA parsing normalized (false/0/off/no, case-insensitive); startup warning extended to the empty-env/mock-client/enforced-2FA confusion. GDPR: - anonymize_user() SQL now scrubs two_factor_* columns + staff notes, so the idle-account batch cleanup (CleanupIdleAccounts) is erasure-clean, not just the user-initiated delete path. Webhooks: - dispute.created for an untracked Square payment now raises a critical_payment_log admin notification (chargeback the app can't reconcile is never silent). Reason strings truncated on rune boundaries (valid UTF-8). Stale at-most-once comment corrected; revertTillSaleGiftCardFunding duplication noted. Sweep/mock parity: - Mock CreatePayment dedup is now source-aware (IDEMPOTENCY_KEY_REUSED on source mismatch) matching ReplayPaymentByKey and real Square. - COMPLETED-but-never-polled terminal till-sale checkouts are now recorded by the sweep (previously only booking checkouts were; till charges were invisible until the 24h blind-fail WARN). - Legacy snapshot-less minimal-body replay, SQUARE_LOCATION_ID drift, and in-memory-mock-restart limitations documented. Docs: - Webhook path corrected everywhere (/webhooks/square, not /api/webhooks/square - a deployer following the old path would 404 and silently lose all webhook reconciliation). - 2FA enforcement semantics + code-delivery mechanism documented accurately (fail-closed default; log-delivery channel; disable re-verification). - README/User Manual note the 2FA requirement on online saved-card payments. Tests: 2,151 (up from 2,142). Backend 26/27 packages green (crussell/db fails only in this environment: local postgres doesn't offer scram-sha-256 for the test role; package is byte-identical to HEAD and untouched here). Frontend builds; svelte-check 0 errors. |
||
|
|
e9b0f0f2a7 |
fix: review-loop hardening — identical-body replay, 2FA gates, webhook at-least-once, GDPR scrub
Follow-up to the comprehensive payment-system review. Fixes the issues the review found in the initial integration, plus the rough edges it introduced. Money-safety: - Replay-by-key now replays the FULL original request verbatim from a stored square_request_snapshot, so a retained idempotency key returns the original payment instead of IDEMPOTENCY_KEY_REUSED (previously the row sat pending forever). IDEMPOTENCY_KEY_REUSED remains ambiguous (never proof of no charge). - Dev mock mirrors real Square for unknown-key replays: ccof: saved-card sources are charged and rescued; spent cnon: nonces surface ErrReplayKeyNotRetained. (Fixes dev/prod parity divergence.) - Webhook dedup row committed AFTER dispatch (at-least-once); FAILED till sales claw back gift-card funding; event-type strings match Square's real catalog. - Expired-gift-card cancellation refunds set creditFailed (never a phantom 'completed' refund); cancellation refunds lock all payment rows ascending. - Sweep never rescue-completes a gift-card purchase without delivering the card. - Tip no-client-key fallback is a deterministic count-based key under the booking advisory lock (retry-safe, distinct tips don't collapse). - M-cap subtracts completed refunds, clamped to [0, total]. 2FA (PSD2 SCA stand-in) for online saved-card payments: - Full feature: status/setup/verify/disable endpoints, gating helper wired into all 7 saved-card charge paths (incl. BuyGiftCard + admin saved-card), account admin-tab settings UI, frontend gating across all payment surfaces. - Enforcement is FAIL-CLOSED: on unless REQUIRE_2FA=false or an explicit mock/dev SQUARE_ENVIRONMENT; startup warning when off in a non-dev env. - Verify is brute-force hardened (5-attempt lockout, timing-safe compare); plaintext codes only logged when enforcement is off (dev). - GDPR: anonymize_user also scrubs 2FA columns and staff notes. Infra/docs: - nginx: /api/ response cache removed (cross-user disclosure); port 80 redirects to HTTPS (localhost/RFC1918 exempt, end-anchored regexes); HSTS; separate webhook rate-limit zone. - Schema: users 2FA columns; payments/till_sales square_source_id + square_request_snapshot. - Legal docs: gift-card cooling-off, international-transfers section, tips policy; Gap Backlog P3 webhooks marked done; stale counts/wording corrected. - Flaky test race fixed (t.Parallel + global mock mutation); suite 26/26 packages green, 2,142 tests, svelte-check clean. |
||
|
|
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. |
||
|
|
f3d50f6990 |
Complete Square GDPR erasure: customer deletion and stale-guest scrub
Account deletion now snapshots card and customer IDs before the local anonymize transaction and dispatches the Square cleanup goroutine only after the tx commits, deleting each distinct Square customer once and skipping any customer still referenced by another user's card. AnonymizeStaleGuestAccounts also disables cards and deletes the guest's Square customer profile (PII) before NULLing references locally. Token redaction applied to all error logs. |
||
|
|
0d22f8d597 |
Scrub Square card and customer references on anonymization (GDPR)
anonymize_user, delete_guest_user, and AnonymizeStaleGuestAccounts now NULL square_card_id and square_customer_id on user_saved_cards (7-year retained_until soft-delete kept for financial records). Make square_card_id nullable in the schema. GDPR export refunds join fixed to include gift-card-purchase refunds. Add scrub assertions to the GDPR and stale-guest test suites. |
||
|
|
35bc021857 |
fix: replace err.Error() string match with errors.Is(err, pgx.ErrTxClosed)
CI / Env docs check (push) Successful in 25s
CI / Docker compose check (push) Successful in 24s
CI / Frontend deps check (push) Successful in 30s
CI / Frontend major deps (push) Successful in 33s
CI / Nginx config check (push) Successful in 59s
CI / Go build (push) Successful in 1m15s
CI / Secrets scan (push) Successful in 1m16s
CI / Knip (push) Successful in 56s
CI / Frontend a11y check (push) Successful in 55s
CI / Frontend build (push) Successful in 1m27s
CI / go mod tidy (push) Successful in 17s
CI / Go vulnerabilities (push) Successful in 2m17s
CI / Go vet (prod) (push) Successful in 2m46s
CI / Go vet (dev) (push) Successful in 2m50s
CI / Staticcheck (prod) (push) Successful in 2m55s
CI / Staticcheck (dev) (push) Successful in 3m13s
CI / Frontend QC (audit) (push) Successful in 41s
CI / golangci-lint (push) Failing after 3m37s
CI / Frontend QC (typecheck) (push) Successful in 1m30s
CI / Frontend QC (lint) (push) Successful in 2m4s
CI / Security scan (prod) (push) Successful in 4m43s
CI / Security scan (dev) (push) Successful in 4m44s
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 / Svelte strict check (push) Successful in 33s
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> |
||
|
|
11fbf869e1 |
fix: add 30s timeouts to account.go goroutines using context.Background()
CI / Env docs check (push) Successful in 13s
CI / Nginx config check (push) Successful in 20s
CI / Docker compose check (push) Successful in 20s
CI / Frontend major deps (push) Successful in 22s
CI / Frontend deps check (push) Successful in 28s
CI / Secrets scan (push) Successful in 41s
CI / Go build (push) Successful in 40s
CI / Frontend build (push) Successful in 43s
CI / Knip (push) Successful in 46s
CI / Go vet (prod) (push) Successful in 1m45s
CI / Frontend a11y check (push) Successful in 2m7s
CI / Go vet (dev) (push) Successful in 1m58s
CI / go mod tidy (push) Successful in 35s
CI / Frontend QC (audit) (push) Successful in 39s
CI / Staticcheck (prod) (push) Successful in 2m44s
CI / Go vulnerabilities (push) Successful in 1m46s
CI / Staticcheck (dev) (push) Successful in 3m45s
CI / golangci-lint (push) Successful in 3m47s
CI / Frontend QC (typecheck) (push) Successful in 1m43s
CI / Security scan (dev) (push) Successful in 4m8s
CI / Security scan (prod) (push) Successful in 3m51s
CI / Frontend QC (lint) (push) Successful in 1m53s
CI / Svelte strict check (push) Successful in 58s
CI / Tests (prod) (push) Successful in 3m15s
CI / Tests (dev) (push) Successful in 3m39s
CI / Race (prod) (push) Successful in 6m50s
CI / Race (dev) (push) Successful in 7m6s
|
||
|
|
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
|
||
|
|
407de74b51 |
fix: restore test-used functions, silence tx.Rollback closed errors, prune knip dead code
CI / Frontend deps check (push) Successful in 22s
CI / Go vulnerabilities (push) Successful in 32s
CI / Go build (push) Successful in 32s
CI / go mod tidy (push) Successful in 13s
CI / Knip (push) Failing after 33s
CI / Frontend build (push) Successful in 1m12s
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 vet (push) Successful in 57s
CI / golangci-lint (push) Successful in 1m8s
CI / Tests (prod) (push) Successful in 1m45s
CI / Tests (dev) (push) Successful in 2m5s
CI / Race (prod) (push) Successful in 3m27s
CI / Race (dev) (push) Successful in 4m52s
Restore processImage (images.go) and nonDepositPaymentType (handlers.go) with //nolint:unused — used in test files. Fix 97 tx.Rollback defers to silently discard expected "tx is closed" error after commit. Frontend: remove 44 unused shadcn-svelte files, 2 dead components, 9 stale npm deps, prune unused exports. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> |
||
|
|
ed9cb1489c |
fix: resolve golangci-lint violations (errcheck, unused, gosimple, ineffassign)
errcheck: add proper error handling with slog.Error for tx.Rollback, key generation, and s3/dav operations. Add nolint comments for intentionally discarded DB scan errors and HTTP write errors. unused: remove dead code (svcRow type, processImage, nonDepositPaymentType, generateSecureCode, colorBold, nGreen, nRed) gosimple S1021: merge var declaration with assignment in manage.go ineffassign: remove dead assignments in settings.go, till.go, images.go Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> |
||
|
|
e4b9003439 |
refactor(handlers): migrate remaining backend handlers to clock.Now() and transaction patterns
Apply clock.Now() migration, transaction wrapping, and minor refactors across admin, scheduling, today, user, auth handler, notifications, webhooks, services, portfolio, ratelimit, testutils, and main.go. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> |
||
|
|
3d0e2afc4c |
refactor(backend): migrate db.DB to db.Conn PoolProxy across all handlers
Replace direct *pgxpool.Pool usage with PoolProxy wrapper across the entire backend: - db.DB renamed to db.Conn (*pgxpool.Pool -> *PoolProxy) - JWT functions now accept context.Context instead of using context.Background() - Handler DB calls route through PoolProxy for per-test transaction support - Fixture/helper/testdb functions accept Querier interface for decoupling - Query ordering fixed in bookings handlers: COUNT after data query to avoid pgx conn busy - Time truncation fixed: time.Date instead of Truncate(24*time.Hour) for week start calc - testmain_test.go files updated with SeedBaseline and NewPoolProxy Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> |
||
|
|
efd3ad5405 |
refactor(backend): migrate from sql.ErrNoRows to pgx.ErrNoRows
Replace all database/sql.ErrNoRows checks with pgx.ErrNoRows across backend handlers. Migration includes: jwt.go, local.go, admin_reserve.go, custom_services.go, discount_campaigns.go, services.go, account.go, customer_relationship.go, guest.go. Also removes unused test_helpers.go resetTestData function. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> |
||
|
|
40840c0458 |
feat(user): extend DeleteAccountHandler with external system scrubbing
DeleteAccountHandler now scrubs external systems BEFORE SQL-level anonymization. S3: deletes profile picture from S3/R2 (profiles/{userID}.jpg) when s3.Client is configured. Square: iterates user's saved cards and calls DeleteCardOnFile for each non-deleted card when payments.SquareClient is configured. Both run in background goroutines (non-blocking, best-effort with warning logs). CardDAV contact deletion remains as existing best-effort goroutine.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
|
||
|
|
7fc58f58d9 |
feat: admin notification system with priority ordering, bell icon, and /notifications page
Two-tier notification system: new_booking (all public bookings) + pending_booking (notes/today). Priority-sorted queue, unread count polling, enriched responses with user_name/booking_start_time. Fix critical bug: edit_requested cleanup was broken (wrong reason string in 3 handlers). Add 15 new tests covering priority ordering, enrichment, and notification creation flows. Update Admin Manual, Technical Manual, and gap backlog docs. |
||
|
|
bff86a6660 |
feat: 10 quick wins — account deletion, health check, debug cleanup, UX polish, graceful shutdown
- backend/handlers/user/account.go: Wire DELETE /api/user/account to call anonymize_user() for registered users and delete_guest_user() for guests, with CardDAV contact cleanup - backend/handlers/user/profile_test.go: Add TestAccount_DeleteGuest and enhance TestAccount_Delete to verify anonymization results - backend/main.go: Add GET /api/health endpoint with DB ping and S3 status check; add HSTS and Referrer-Policy security headers; replace http.ListenAndServe with http.Server + graceful SIGTERM/SIGINT shutdown - frontend/routes/+layout.svelte: Replace alert() with toast notifications for email verification flow - frontend/routes/login/+page.svelte: Replace alert() with toast.info for social login prototype buttons - frontend/booking/BookingFlow.svelte: Remove 2 console.log debug calls; add cancellation policy note in Step 3; add timezone policy comment - frontend/ImageUpload.svelte: Comment out debug console.log - init-scripts/init-script.sql: Add delete_guest_user() SQL function - docs: Update README.md and Obsidian notes to reflect completed items |
||
|
|
708b741a32 | Initial commit. Working login, example UI with prototype and demo, connections to DB and DAV, local and prod setups. |