Files
Crussell/obsidian/Crussell/Future Work - Gap Backlog.md
T
popertotsandSisyphus 93be93f86c docs: README + obsidian parity — test counts 2,656, frontend 160, 27 maintenance jobs, 2FA log-relay opt-in contradiction fixed, Future-Work P4 count, stale line refs de-referenced
- backend test function count 2,554 -> 2,656; frontend vitest 130 -> 160 (93+37 -> 110+37); maintenance jobs 26 -> 27 (retry-s3-deletions)
- README + User Manual: removed the false 'operator opt-in [2FA] log relay' claim — production has no delivery channel, fails closed (503)
- Future Work P4: 20 -> 32 log.Printf('CRITICAL ... manual reconciliation required') sites; T7 job-count note updated
- Technical Manual: stale main.go line references removed (line numbers drift); verified thresholds consistent across docs

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
2026-08-22 00:34:51 +01:00

22 KiB
Raw Blame History

Future Work — Gap Backlog

Last Updated: August 2026 Status: Living backlog — add to this as gaps are discovered Previous version: OUT OF DATE — this replaces the prior document. Completed items removed, new items added from exhaustive codebase audit.

This document has three lists: Pre-Launch (integration tasks), MVP (missing features for daily ops), Stretch (nice-to-have). Items are numbered sequentially. All done items are removed without tracking (see "Previously Completed" sections).

Development Context

Much of the application was built rapidly in development mode. External integrations (Square payments, S3/R2 storage, SMTP email, OAuth, error monitoring) were stubbed out as the business logic evolved — mocks and placeholders that let us move fast without configuring real services. Square payments has since been fully implemented; the remaining integrations (S3/R2 storage, SMTP email, OAuth, error monitoring) are the upcoming bodies of work.

Those dev placeholders have not kept pace with the application's feature growth. As we approach production, each needs:

  1. A production-side implementation wired alongside the dev mock
  2. The dev stub itself may need updating to better reflect real-world behaviour
  3. End-to-end alignment between what the application expects and what the integration delivers

Some items in this backlog are genuine missing features — these sit in MVP/Stretch. But many are simply "the app finished its dev journey and needs its production integrations wired up."


Pre-Launch — Production Integration Tasks

These are things that work fine in dev (with mocks) but need real implementations hooked in before production goes live. Each is an expected step in the dev→prod journey — the app was built this way deliberately to stay fast.

# Task Effort Area Dev Status Notes
P2 S3/R2 storage: implement prod side of the abstraction M (2-3d) Backend Dev works (internal/s3/s3_dev.go — RustFS + in-memory fallback). Prod side (internal/s3/s3.go:52-62) returns "not implemented" for Upload/Download/Delete. The prod S3Client struct lacks the *s3.Client field entirely — it was never populated. The storage abstraction was defined early and the dev side got a full implementation. The prod side needs the AWS SDK v2 dependency and real S3/R2 calls. Portfolio images and profile pictures will start working in prod once this is done.
P3 Square webhook event handling: from log-only to action S (1d) Backend DONE (Aug 2026)handlers/webhooks/square.go now dispatches events to state-mutating handlers instead of logging only. HMAC-SHA256 verification is fail-closed (503 without the signing key, 403 on bad/missing signature, 400 on an empty event_id). Events are deduplicated by event_id — a fast-path in-memory cache plus a persistent square_webhook_events row committed after successful dispatch (at-least-once: on a dispatch error no dedup row is written and a 5xx is returned so Square retries; the handlers are idempotent). payment.updated/payment.created reconcile pending payments and till_sales (pending-only, with gift-card funding clawback on definitively failed charges), refund.updated/refund.created update refunds, and dispute.created/dispute.state.updated upsert disputes — a lost dispute marks the payment failed and raises a critical_payment_log admin notification. The three background sweeps (sweep-pending-square-refunds, sweep-stale-pending-payments, sweep-stale-terminal-checkouts) remain the eventual backstop for stuck states. Remaining limitation: no in-app dispute-evidence submission — dispute.evidence.* and terminal.checkout.* events are still log-only, so evidence is filed via the Square Dashboard.
P4 Payment reconciliation: add recovery for split-brain scenarios L (3-5d) Backend Partial progress (Aug 2026). 32 log.Printf("CRITICAL: ... manual reconciliation required") calls exist across payment, refund, and till handlers. When Square succeeds but the DB transaction fails afterwards, state diverges with no automated recovery. The three background sweeps now provide interim recovery for pending states (refund sweep retries up to 3 attempts; stale-pending and terminal-checkout sweeps fail/clean stale rows), but a DB-commit failure after a successful Square charge still leaves no automated path to reconcile the orphaned Square-side payment. This happens when the application correctly processes a Square payment but then hits a DB error on commit. In dev, this was handled by just logging it. For prod, we need a reconciliation job or retry mechanism. (Count grew from 18 to 32 with the manual-reconciliation warnings added across the Aug 2026 payment-hardening rounds.)
P5 Till Purchases: wire the backend payment flow M (1d) Frontend + Backend DONE (Aug 2026)backend/handlers/payments/till.go implements the till-sale endpoint (cash, card_machine Terminal checkout + polling, saved_card, online_square Web Payments SDK nonce, on_the_house); TillPurchases.svelte wires all payment methods and the Charge button is enabled (gated only for retail-item carts, which cannot be charged yet). The till UI and backend sale path are fully connected. Only retail-item charging remains deferred (see TillPurchases.svelte canCharge).
P6 Email/SMS notification delivery XL (5-7d) Backend user_notification_preferences table stores delivery preferences. 8 TODO markers reference this blocker. Notification creation works (admin_notifications table), but no delivery channel exists. No SMTP configuration, no SMS provider. 2 tests skipped as "WIP handler." The notification queue works (reasons, priorities, acknowledging). What's missing is the delivery backend. Affects: slot eviction alerts, edit request approvals/denials, gift card codes, unpaid booking reminders, idle account warnings.
P7 Production security headers S (1h) Backend Done (Aug 2026, partially): corsMiddleware (in backend/main.go) now sets HSTS and Referrer-Policy unconditionally; only the stale TODO comments above them remain. The headers are already live. Remaining cleanup is removing the now-misleading TODO markers in main.go and confirming header values against prod nginx/Cloudflare config.
P8 Social auth stubs (Google/Microsoft/Facebook) L (2-3d) Backend + Frontend handlers/auth/social.go is 1 line (package auth). Frontend login page has 3 social buttons that show toast.info("${provider} login coming soon"). The user_social_logins table and account_type enum values exist from early schema design. The schema was designed for social auth from the start (table + enum values). The OAuth flow itself was never implemented. Buttons exist as UI placeholders.
P10 No automated database backups M (1d) Infrastructure PostgreSQL volume is persistent in Docker but no pg_dump cron, no point-in-time recovery. Standard production DB setup task.
P12 Square sandbox smoke test (pre-go-live gate) S-M (1d, once credentials available) E2E BLOCKED — no real Square credentials available. Must exercise the real API path end-to-end: new-card tokenization → payment → saved card → refund → reconcile, against Square's sandbox. Also verifies the M-8 open question (is card.customer_id enforced as Required?). The dev mock cannot exercise Square's real wire contract (key-length limits, device_options, refund statuses, error codes). This is the sole remaining item before the production flip. See plans/p11-square-web-payments-sdk.md Remaining Items.
P13 Reconcile deterministically-keyed saved-card charges S (2-3h) Backend DONE (Aug 2026 payment hardening)deriveBookingPaymentIdempotencyKey (handlers/payments/handlers.go) now sequences repeatable types (partial) and rotates the deterministic fallback key past refunded completed rows, so refund-then-repay and equal-amount repeat charges no longer collapse. An un-refunded completed row still keeps its key, so the double-charge protection holds. See plans/p11-square-web-payments-sdk.md R3. Closed by the payment-hardening review.
P14 Square customer provisioning & consent S-M (1-2d) Backend + Frontend + Docs IMPLEMENTED (Aug 2026) — lazy customer provisioning on card-save, square_customer_id persisted + forwarded to Square as card.customer_id/CreatePayment CustomerID, one-off/guest no-customer, /privacy-policy route + consent pop-over, SCA verificationDetails wired across all charge flows. Remaining: P12 sandbox verification that Square enforces customer_id, and final privacy-policy copy review (the route no longer ships DRAFT-bannered; the {{SUPPORT_EMAIL}} placeholder substitution and owner/solicitor sign-off remain). See plans/p14-square-customer-provisioning-consent.md. Closed out of the deep post-implementation review (Aug 2026).
P15 Accounting integration (Mettle bank feed + FreeAgent bookkeeping export) M (2-3d) Backend Planned upcoming body of work. No code yet. The square_deposits schema (backlog T1) was the placeholder for Square batch deposit reconciliation against Mettle. Mettle bank feed: match Square batch deposits against bank statements. FreeAgent: bookkeeping export (VAT return / P&L data) feeding the existing HMRC MTD SQL functions (see M1/M9).

MVP — Must Do Before Launch

These are missing functionality that prevents daily operations, legal compliance, or basic UX. Unlike the Pre-Launch tasks above, these aren't about wiring production counterparts — they're features that were genuinely deferred or overlooked.

# Gap Effort Area Notes
M1 VAT/Tax export endpoints M (1-2d) Backend 9 VAT/sales SQL functions exist in init-scripts/init-script.sql: get_vat_return_data, export_sales_transactions, get_monthly_business_summary, get_sales_totals, calculate_vat, get_receipt_data, enable_vat_registration, apply_vat_to_payment, apply_vat_to_till_sale. 7 are not exposed by any Go endpoint (the first seven listed); apply_vat_to_payment and apply_vat_to_till_sale ARE wired through handlers/payments/vat.go (applied on booking payments and till sales). Needed for HMRC MTD compliance.
M2 Password reset — no frontend route S (2-3h) Frontend Backend has verification codes with verification_purpose = 'password_reset' and /verify/generate + /verify/check endpoints. No "forgot password" link or reset form exists.
M3 Email verification calls wrong API endpoint S (2h) Frontend +layout.svelte:33 calls /api/verify-email which 404s. Correct endpoints: POST /api/verify/generate and POST /api/verify/check. Every login triggers a silent failure.
M4 CSRF protection S (2-3h) Backend SvelteKit handles CSRF for its own forms, but direct API calls to /api/* bypass it.
M5 XSS input sanitization S (2-3h) Backend Backend validates format (regex, length) but doesn't sanitize HTML entities in stored fields. CSP mitigates but doesn't eliminate risk.
M7 Booking cancellation UI from user account S (2-3h) Frontend UserBookingModal shows details but has no cancel button. Backend DELETE /api/bookings/{id} exists.
M8 Business settings management UI M (1-2d) Frontend GET/PUT /api/admin/settings endpoints exist. No admin page — staff use curl or SQL.
M9 CSV/Excel export for bookings/payments M (1d) Backend No endpoint for accounting software export. SQL functions exist but not wired.
M10 CurrentAppointment action stubs M (1d) Frontend Extend and Cancel buttons on Today page are dead. Edit/TakePayment/Reschedule are already wired.
M11 /terms and /privacy-policy routes — final legal copy review S (1h) Frontend The routes are now substantive pages (booking/deposit/cancellation policy, refund tiers matching the code, SCA-only card-authorisation disclosure, gift-card terms at /gift-card-terms, ICO registration) and no longer carry DRAFT banners. What remains is the final legal review and substituting the {{SUPPORT_EMAIL}} placeholder.
M12 Admin notifications list/acknowledge untested S (2-3h) Backend 2 tests skipped as WIP (today_test.go:940,946). Notification endpoints have zero coverage.
M13 ICO registration (ops) S (30min, owner) Ops The sole-trader controller must register with the ICO and pay the data-protection fee unless exempt, before processing personal data at scale. Operator task — see the Technical Manual Pre-Launch Checklist and the Privacy Policy.

Stretch — Post-Launch

These improve the experience or add features, but the business can operate without them.

# Gap Effort Area Notes
S1 One-off custom services M (1-2d) Full-stack Single-use services must be added to permanent catalog then deleted.
S2 One-off exceptional hours M (1d) Full-stack Single-day open hours require a full exceptional group. Time blockers handle closures but not openings.
S3 Referral system UI M (1-2d) Full-stack Backend complete. Users can't see their code or track uses. No admin campaign management. affiliate role and affiliate_payouts table exist but unused.
S4 Analytics endpoints M (1-2d) Backend analytics.go is 1 line. 4 SQL summary functions exist but no Go handler.
S5 API documentation M (1-2d) Backend No OpenAPI/Swagger spec.
S6 Per-user rate limiting M (1d) Backend Currently IP-based only.
S7 Begin button (Today page) S (2-3h) Full-stack Manual appointment start for early arrivals.
S8 Booking conflict detection for users S (2-3h) Backend Users can double-book themselves in two tabs.
S9 Service category/tag management M (1-2d) Full-stack Flat service list, no grouping.
S10 No-show tracking dashboard S (2-3h) Frontend forgiven_no_shows table exists but no UI.
S11 Dark mode M (1-2d) Frontend Tailwind supports it. No toggle.
S12 PWA support L (3-5d) Frontend No service worker, manifest, or offline support.
S13 Recurring bookings L (3-5d) Full-stack No weekly/monthly booking support.
S14 Gift card self-service portal Frontend DONE (Aug 2026) — customers redeem gift cards to their account balance themselves from Account → Gift Cards (confirmation dialog, FOR UPDATE single-shot redeem); the remaining self-service item is the in-flow Gift Card Terms link (documented in the Feature Catalog §9.5).
S15 Admin audit trail for account anonymization S (1h) Backend No user_anonymized notification when admin deletes a user.
S16 User notification of slot eviction S (2h) Backend When a booking is evicted (deposit not paid, slot reclaimed), the user is never notified. 3 TODO sites reference this.
S17 Password reset should clear lockout state S (1h) Backend TODO in auth/local.go:427 — currently failed_attempts/locked_until aren't cleared on password reset.

Technical Debt — Cleanup

These don't add features but reduce maintenance cost and risk.

# Task Effort Area Notes
T1 Drop orphaned square_deposits table + function S (1h) DB Schema DONE (Aug 2026) — the table and generate_square_deposit_id() function were removed from init-scripts/init-script.sql in the fresh-DB recreate. They had zero Go code references; Square bank reconciliation was planned but never built.
T2 Remove 6 unused DB enum values S (2h) DB Schema account_role: 'affiliate', account_type: 'google'/'microsoft'/'facebook', payment_status: 'failed'/'refunded', discount_campaign_scope: 'first_booking_only'/'new_customers_only', till_item_type: 'retail_product' — defined but never referenced in Go code.
T3 Remove 4 unused admin_notification_reason values S (1h) DB Schema 'rescheduled_booking', 'gift_card_purchased_for_friend', 'edit_request' (code uses 'edit_requested'), 'deposit_paid' (in priority ordering but never inserted).
T4 Create or remove documented update_data_consent() function S (1h) DB Schema Listed in FUNCTION USAGE SUMMARY comment (~line 2401) but no CREATE FUNCTION exists.
T5 Resolve 2 route-conflicted lint-ignored handlers S (1h) Backend manage.go:27,314 — handlers exist only for tests but routes conflict.
T6 Resolve portfolio lint-ignored handler S (1h) Backend images.go:53 — handler referenced from tests only, never routed.
T7 Fix README job count: 22 not 21 S (5min) Docs COMPLETED Aug 2026 — README now documents 27 maintenance jobs (the three payment sweeps: sweep-pending-square-refunds, sweep-stale-pending-payments, sweep-stale-terminal-checkouts, plus sweep-square-webhook-events, scan-critical-payment-logs, and retry-s3-deletions).
T8 Audit 18 silent catch blocks M (1d) Frontend 1 catch (e) {}, 17 catch (_err) — errors swallowed silently. Many should show user-facing toasts.
T9 33 svelte/no-navigation-without-resolve suppressions M (1d) Frontend Create a project-wide goto wrapper instead of suppressing per-file.
T10 Replace as any in HolidayHours S (30min) Frontend HolidayHours.svelte:234(group.hours as any[])?.map(…). Hours array has known shape.
T11 Replace e: any in button onclick S (30min) Frontend button.svelte:101 — click handler typed as e: any.
T12 Former name display (4 TODO sites) S (1d) Frontend + Backend 4 TODOs across GiftCards + notifications needing previousFirstName/previousLastName from backend.
T13 Fix devProdClient rune-arithmetic in test S (30min) Backend COMPLETED July 2026 — rune('0'+idx) replaced with fmt.Sprintf("concurrent-key-%d", idx) for proper numeric formatting beyond index 9.
T14 Error tracking / monitoring (Sentry) M (1-2d) Backend log.Printf() only. No alerting on 5xx. The audit found 39 CRITICAL emission sites (manual-reconciliation warnings) with no operator-facing path; they will never be seen. Stopgap (Aug 2026): a DB-backed critical_payment_log admin-notification sweep job now surfaces these as admin notifications until a real log/alerting pipeline (Sentry) lands. Still OPEN: the sweep is a stopgap, not the alerting pipeline.
T15 Nested-modals: per-trigger instances for arbitrary-depth stacking M (1d) Frontend The dynamic z-index stack (ui/dialog/zindex.ts + data-state MutationObserver in dialog/alert-dialog content) is verified correct: every genuine closed→open transition claims a fresh slot (50, 60, 70…), so the newest dialog always paints on top and reopened dialogs re-claim rather than freezing at a stale slot (browser-verified: 3-level chain 90<100<110, reopen 160→170→180, cancel/alert above parents). Known limitation: /today mounts a single BookingModal + single UserModal toggled by boolean open flags, so re-invoking openBookingModal()/openUserModal() on an already-open instance swaps content in place with no closed→open transition — the alternating booking→user→booking→user chain caps at 2 stacked dialogs. A genuine 3rd layer is reachable only via a distinct component instance (e.g. Reschedule sub-modal). Fix (future): render per-trigger modal instances (keyed/each rendering) or an explicit close→reopen cycle so any nesting depth is expressed as distinct opens; the z-index system already handles arbitrary depth once distinct opens exist.

Previously Completed Items (August 2026 backlog)

  • Square payments: wire prod client alongside dev mock (P1)internal/square/square_http_client.go implements the real REST client (payments, terminal checkouts, refunds, cards, list-refunds). Prod client (internal/square/square.go) and dev devProdClient (square_dev.go) both call real Square when SQUARE_ENVIRONMENT=sandbox|production; mock uses the in-memory client. The health endpoint reports "mock"/"ok" accordingly (was "not_implemented").
  • Square Web Payments SDK: re-enable new-card entry with nonce-based flow (P11)SquareCardInput.svelte tokenizes cards to cnon: nonces via the Web Payments SDK (env-gated on VITE_SQUARE_APPLICATION_ID/VITE_SQUARE_LOCATION_ID); all 8 flows re-enabled (tips ×3, booking payment, deposit, Buy a Gift Card, account Add Card, till online_square); CardEntryUnavailable kept only as the no-credentials fallback. See plans/p11-square-web-payments-sdk.md.
  • Square webhook signature verification — enforce always (M6) — the webhook handler is now fail-closed: rejects with 503 when SQUARE_WEBHOOK_SIGNATURE_KEY is unset and 403 when the signature header is missing/invalid (handlers/webhooks/square.go).
  • Fix README job count (T7) — README updated to 26 maintenance jobs.
  • Fix devProdClient rune-arithmetic in test (T13)rune('0'+idx) replaced with fmt.Sprintf("concurrent-key-%d", idx).

Previously Completed Items (July 2026 backlog)

  • Tip payments: replace placeholder card tokens (P9)card_token: 'placeholder' replaced with real saved card selection + CardInput with Luhn/expiry/CVC validation across all 3 tip pages. CardBrandIcon SVGs added for all Square-supported brands.

Previously Completed Items (June 2026 backlog)

  • Reservation/cleanup background cron — All 20 jobs migrated to centralized scheduler (June 2026 count; the scheduler now runs 26 jobs)
  • XSS input sanitization (partial) — CSP added, error messages sanitized, ICS injection fixed
  • Per-user rate limiting (partial) — L3 ProgressiveRateLimit added for login/register

This catalog was compiled from a full codebase audit (July 2026): 4 parallel deep-dive agents covering backend TODOs, frontend gaps, implied stubs, and DB schema analysis. Every item traces to specific file paths and line numbers.