rentease/thoughts/shared/plans/2025-10-05-payment-service-extraction.md
Ruidy 23f3ceec21
Some checks are pending
CI / checks (push) Waiting to run
Feat/stripe integration (#50)
* 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.
2025-11-21 15:47:01 +01:00

9.2 KiB
Raw Blame History

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).
  • PgStores 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

  • 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.go for dedicated service struct.