feat(stripe): extract async-stripe StripeService into dunite-stripe (DEV-515 pt 2) #30

Merged
longjacksonle merged 3 commits from feat/DEV-515-dunite-stripe-service into main 2026-08-03 21:25:39 +02:00

What

DEV-515 part 2: extract bunyip's 1642-line Stripe service into the shared dunite-stripe crate - the async-stripe StripeService, runtime StripeConfig, and the webhook-signature verify (delegating to dunite-stripe-core). Includes the DTOs slice (the branch is stacked on it, so those commits appear here too until #29 merges).

Error model: neutral StripeServiceError

Methods return a crate-local StripeServiceError (internal/validation/not_found/unauthorized, mirroring AppError); each consumer maps it with one From impl. Returning dunite_core::AppError directly was tried but forces a whole-tree dunite rev unification (download/oci/oidc) onto an unmerged rev - avoided by staying neutral. Consumer cost: ~27 .map_err, in the wiring PR.

Stays per-consumer

from_env/from_db_model (secret encryption + env conventions), encryption helpers, the DB config model, checkout-URL env defaults, tier reconciliation, admin presentation, webhook dispatch.

Tests

cargo build + clippy -D warnings + fmt --check clean. Carries its own async-stripe 0.37 + reqwest 0.12.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QLd9c7niucrqx68v4AxVss

## What DEV-515 part 2: extract bunyip's 1642-line Stripe service into the shared `dunite-stripe` crate - the async-stripe `StripeService`, runtime `StripeConfig`, and the webhook-signature verify (delegating to `dunite-stripe-core`). Includes the DTOs slice (the branch is stacked on it, so those commits appear here too until #29 merges). ## Error model: neutral `StripeServiceError` Methods return a crate-local `StripeServiceError` (`internal`/`validation`/`not_found`/`unauthorized`, mirroring `AppError`); each consumer maps it with one `From` impl. Returning `dunite_core::AppError` directly was tried but forces a whole-tree dunite rev unification (download/oci/oidc) onto an unmerged rev - avoided by staying neutral. Consumer cost: ~27 `.map_err`, in the wiring PR. ## Stays per-consumer `from_env`/`from_db_model` (secret encryption + env conventions), encryption helpers, the DB config model, checkout-URL env defaults, tier reconciliation, admin presentation, webhook dispatch. ## Tests `cargo build` + `clippy -D warnings` + `fmt --check` clean. Carries its own async-stripe 0.37 + reqwest 0.12. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01QLd9c7niucrqx68v4AxVss
Move bunyip's 1642-line Stripe service into the shared dunite-stripe crate: the async-stripe StripeService (products, prices, subscriptions, invoices, customers, checkout, billing portal, webhook endpoints), the runtime StripeConfig, and the delegating webhook-signature verify (which calls dunite-stripe-core). Framework-agnostic and error-neutral: every method returns the new StripeServiceError (internal / validation / not_found / unauthorized), mirroring the consumers' AppError constructor shapes so the method bodies read identically; each consumer maps it back with one From impl.

Stays per-consumer (removed from the crate): the StripeConfig env/DB constructors (from_env / from_db_model) since they use each app's encryption + env conventions, the secret encryption helpers, the DB config model, and the env-default URL helpers. The crate carries its own async-stripe 0.37 + reqwest 0.12 (the workspace baseline is reqwest 0.11 for dunite-oci; cargo resolves both). build + clippy -D warnings + fmt clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLd9c7niucrqx68v4AxVss
Return the shared-kernel dunite_core::AppError directly rather than a bespoke StripeServiceError. bunyip's AppError IS dunite_core::AppError, so its Stripe call sites keep working through `?` with zero churn (a neutral error would hit the orphan rule: bunyip can't impl From<foreign, foreign>, forcing .map_err at every call site). a8n, which keeps its own AppError, adds one From<dunite_core::AppError> impl (its AppError is local, so the impl is allowed). Drops StripeServiceError + thiserror; adds the dunite-core path dep.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLd9c7niucrqx68v4AxVss
Revert "refactor(stripe): return dunite_core::AppError instead of a neutral error (DEV-515 pt 2)"
All checks were successful
Check / fmt + clippy + test (pull_request) Successful in 1m15s
create-release / create-release (pull_request) Has been skipped
41dbbebf67
This reverts commit d39a39bd7a.
longjacksonle deleted branch feat/DEV-515-dunite-stripe-service 2026-08-03 21:25:39 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/dunite!30
No description provided.