* feat(stripe): add Stripe payment sync and webhook support Introduce Stripe integration for automatic payment ingestion and refund tracking. Adds new fields to the payment model for Stripe IDs and status, Stripe client driver, sync service, cron job, manual API endpoint, and public webhook handler for real-time updates. Includes tests and documentation. Manual cash entry remains supported. * chore(stripe): upgrade to stripe-go v83 Upgrade Stripe SDK from v79 to v83 across the codebase. Update all imports to use github.com/stripe/stripe-go/v83 and refactor client usage to match the new API, including changes to PaymentIntents listing. Update documentation and plans to reference the new version. Remove references to the old version from go.mod and go.sum. * refactor(payment): extract payment logic to new service Moves all payment-related logic (manual payments, Stripe sync, webhook handling) from the booking service into a dedicated payment service (`internal/service/payment`). Updates server, cron, and handler wiring to inject and use the new payment service. Adjusts tests, routes, and documentation to reflect the new separation of concerns. This improves cohesion, clarifies responsibilities, and prepares for future payment features. No database schema changes are introduced. * chore(ci): add Go and templ setup to CI workflow This update enhances the CI workflow by adding steps to set up Go using the version specified in go.mod, add the Go bin directory to the PATH, and install the templ code generation tool. These additions ensure that Go-based tooling is available for subsequent CI steps.
9.2 KiB
Payment Service Extraction Implementation Plan
Overview
Separate payment-related logic from the booking service into a dedicated payment service to improve cohesion, clarify responsibilities, and prepare for future payment features (Stripe sync, manual payments, refunds).
Current State Analysis
- Booking service coordinates booking CRUD, manual payment creation, Stripe import, and webhook handling (
internal/service/booking/service.go:12,internal/service/booking/payment.go:8). - Repository store couples booking and payment persistence behind one interface (
internal/repository/booking/pg_store.go:18). - HTTP handlers, cron job, and Stripe webhook rely on booking service payment methods (
internal/server/handle_payments.go:14,internal/server/handle_stripe_webhook.go:13,internal/cron/job_stripe_sync.go:13). - Tests already cover Stripe sync and webhook flows under booking service namespace (
internal/service/booking/stripe_sync_test.go:14,internal/server/handle_stripe_webhook_test.go:15).
Desired End State
- Dedicated
payment.Serviceencapsulates manual payments, Stripe sync, and webhook handling. - Booking service exposes only booking-specific behaviour, delegating payment tasks via the new service.
- Server/cron wiring injects payment service alongside booking service.
- Tests and documentation reflect the new separation.
Key Discoveries
booking.Serviceconstructor wires parser/pdf/stripe clients, making payment-only scenarios passnil(internal/service/booking/service.go:40).PgStore’s payment helpers already operate onbooking.Paymentrecords without booking-specific context (internal/repository/booking/pg_store.go:150).- Server routes mount payment endpoints with booking service dependency injection (
internal/server/routes.go:30).
Out of Scope
- Database schema changes beyond necessary constructor renaming/ref wiring.
- UI redesign of payment components.
- Feature additions beyond reorganising existing behaviour.
Implementation Approach
Incrementally extract payment logic while preserving behaviour: first introduce payment service and rehome logic, then switch entrypoints, and finally colocate tests/doc updates.
Phase 1: Introduce Payment Service Layer
Overview
Create a dedicated payment service and repository abstraction while keeping booking service focused on bookings.
Changes Required
File: internal/service/payment/service.go
Changes: Add new payment service struct with dependencies (store, stripe, logger) and move manual payment CRUD + Stripe helpers.
File: internal/service/payment/types.go
Changes: Define interfaces (Store, StripeClient) mirroring existing booking counterparts; re-export booking.Payment until domain split later.
File: internal/service/booking/service.go
Changes: Remove payment-related fields (store methods, stripe client) and adjust constructor signature to drop payment deps.
File: internal/service/booking/payment.go
Changes: Delete or convert into thin wrappers invoking payment service (ultimately remove file).
File: internal/service/booking/stripe_sync.go
Changes: Move functionality into payment service; leave shim returning booking.ErrStripeClientNotConfigured if needed until call sites migrate.
File: internal/service/booking/stripe_webhook.go
Changes: Move to payment service with minimal adjustments (reuse mapStripeMethod helper via shared utility or move altogether).
File: internal/service/payment/map.go
Changes: Host Stripe method normalisation logic reused by sync/webhook.
File: internal/service/payment/errors.go
Changes: Rehome ErrStripeClientNotConfigured.
File: internal/repository/payment/store.go
Changes: Introduce payment repository interface implemented by existing PG store.
File: internal/repository/booking/pg_store.go
Changes: Implement new payment store interface while keeping booking-related methods.
File: go.mod
Changes: Update module references only if new packages require (likely no change).
Success Criteria
Automated Verification
go test ./internal/service/payment/...go test ./internal/repository/...
Manual Verification
- Payment service constructor handles nil optional dependencies gracefully.
Phase 2: Rewire Dependency Injection & Interfaces
Overview
Inject payment service into HTTP server and cron job; adjust interfaces accordingly.
Changes Required
File: main.go
Changes: Construct payment.Service, pass to server options; update booking service creation with new signature.
File: internal/server/server.go
Changes: Add payment service field; adjust constructor params/options.
File: internal/server/routes.go
Changes: Swap booking service usage for payment service in payment + Stripe routes; update API sync handler if necessary.
File: internal/server/handle_payments.go
Changes: Replace booking.Service dependency with payment.Service interface (new PaymentService interface capturing needed methods).
File: internal/server/handle_bookings.go
Changes: Adjust paymentViewModelFromBookingPayment to use payment types if moved; delegate payment updates through payment service.
File: internal/server/handle_stripe_sync.go
Changes: Accept payment service sync interface.
File: internal/server/handle_stripe_webhook.go
Changes: Inject payment service event handlers.
File: internal/server/option.go
Changes: Add option for payment service injection.
File: cmd/cron/main.go
Changes: Pass payment service job or separate constructor.
File: internal/cron/job_stripe_sync.go
Changes: Construct payment service instead of booking service; update logging context.
Success Criteria
Automated Verification
go test ./internal/server/...go test ./cmd/cron/...
Manual Verification
- Application starts without DI errors (
go run .).
Phase 3: Consolidate Stripe Sync/Webhook Logic Under Payment Service
Overview
Ensure Stripe integrations use new service and repository, maintaining behaviour.
Changes Required
File: internal/service/payment/stripe_sync.go
Changes: Move sync logic, adjust to new interfaces.
File: internal/service/payment/stripe_webhook.go
Changes: Host webhook handlers and reuse normalisation helpers.
File: internal/service/payment/errors_test.go
Changes: Add unit tests for error propagation, ensuring aggregated error handling preserved.
File: internal/driver/stripe/client.go
Changes: Update imports if package paths change; no functional modifications expected.
Success Criteria
Automated Verification
go test ./internal/service/payment -run Stripe
Manual Verification
- Stripe webhook handler still logs/returns identical responses (simulate via existing tests).
Phase 4: Move & Update Tests, Docs, and Views
Overview
Relocate existing tests to the new service and clean up references; ensure docs and views compile.
Changes Required
File: internal/service/payment/stripe_sync_test.go
Changes: Move current booking tests here; update package reference.
File: internal/server/handle_payments_test.go
Changes: Add/adjust tests if necessary to cover new payment service interface (create if missing).
File: internal/service/booking/stripe_sync_test.go
Changes: Remove or convert to thin wrappers if needed.
File: internal/server/handle_stripe_webhook_test.go
Changes: Update mocks to use payment service interface.
File: README.md
Changes: Reflect new architecture (mention payment service).
File: docs/architecture.md (if exists)
Changes: Update diagrams/descriptions; if absent, skip.
File: internal/view/payment.templ
Changes: Ensure imports compile referencing new payment view models.
Success Criteria
Automated Verification
go test ./...(or targeted packages excluding network-bound tests).templ generate(if required after view adjustments).
Manual Verification
- UI still displays payment list and badge with real data.
Testing Strategy
- Run focused unit tests for payment service and server handlers (
go test ./internal/service/payment ./internal/server). - Execute integration tests for cron job if feasible (
go test ./internal/cron). - Run
templ generate+go build ./...to ensure templates compile after refactor. - Document skipping of network-dependent tests (
internal/driver/parser/parser_test.go) when running full suite.
Performance Considerations
- Payment service introduces no new database queries; ensure repository reuse avoids duplicate fetches.
- Confirm Stripe sync maintains pagination behaviour (existing list iterator already handles this).
Migration Notes
- No schema changes; ensure auto-migrate still runs for payment model when payment service initialises.
- Update any environment variable references if moved (e.g., Stripe keys remain unchanged).
References
- Research:
thoughts/shared/research/2025-10-03-stripe-payment-sync.md - Similar pattern:
internal/service/auth/service.gofor dedicated service struct.