Phase 2 backend: Google Wallet pass + profile contact form

- cardclaws-wallet::google — inline GenericObject + RS256 `savetowallet` JWT
  (Rs256Signer via jsonwebtoken; FakeGoogleSigner test double)
- POST /v1/cards/{id}/wallet/google → { saveUrl }
- POST /v1/profile/{handle}/contact — validate, rate-limit, record
  contact_form_submission, email the owner (HTML-escaped, Resend)
- WalletConfig gains google issuer id + service account email

84 backend tests; fmt + clippy clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
Omar Sobh
2026-06-04 12:32:21 -05:00
co-authored by Claude Opus 4.8
parent 4770efd861
commit 8ae1d8f263
20 changed files with 545 additions and 1 deletions
@@ -63,3 +63,4 @@ uuid = { workspace = true }
sqlx = { workspace = true }
async-trait = { workspace = true }
zip = { workspace = true }
base64 = { workspace = true }