# 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.Service` encapsulates 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.Service` constructor wires parser/pdf/stripe clients, making payment-only scenarios pass `nil` (`internal/service/booking/service.go:40`). - `PgStore`’s payment helpers already operate on `booking.Payment` records 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 - [x] `go test ./internal/service/payment/...` - [x] `go test ./internal/repository/...` #### Manual Verification - [x] 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 - [x] `go test ./internal/server/...` - [x] `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 - [x] `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.go` for dedicated service struct.