Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
7ce9eb8
Add optional dependencies for API and Bundle layers
Korbeil Apr 20, 2026
26de386
Add API exception hierarchy for wallet operations
Korbeil Apr 20, 2026
7a6ae97
Add credential value objects for Apple, Google, and Samsung
Korbeil Apr 20, 2026
17f4ec7
Add authentication layer with Google OAuth2, Samsung JWT, and Apple A…
Korbeil Apr 20, 2026
85d64b7
Add Apple Wallet PKPass packager and APNS push notifier
Korbeil Apr 20, 2026
8a32a61
Add Google Wallet API client and save link generator
Korbeil Apr 20, 2026
d6d165d
Add Samsung Wallet API client
Korbeil Apr 20, 2026
015339b
Add issuance helper for Add to Wallet URLs
Korbeil Apr 20, 2026
5f9c2f5
Extend builder contexts to support API integration
Korbeil Apr 20, 2026
90a8d86
Add Symfony Bundle with controllers, DI, entities, and throttled disp…
Korbeil Apr 20, 2026
9a07413
Document API, Bundle, and per-platform usage
Korbeil Apr 20, 2026
2fbbfc2
Harden Apple pass packaging and fix Samsung deep link
Korbeil Apr 20, 2026
75bdf6c
Fix Google/Samsung API client semantics and add Samsung regions
Korbeil Apr 20, 2026
6df0ac8
Wire Samsung region config and extract route detection helpers
Korbeil Apr 20, 2026
4a0a7e3
Secure Apple Web Service endpoints
Korbeil Apr 20, 2026
b3b5dfa
Make pending operation dequeue atomic and crash-safe
Korbeil Apr 20, 2026
12618c9
Harden processor dispatch against corrupt payloads and typos
Korbeil Apr 20, 2026
b1ae2fd
Add Google Wallet setup tutorial and runnable scripts
Korbeil Apr 21, 2026
7546925
Promote wallet serializer factory and inline class in save links
Korbeil Apr 22, 2026
a468b41
Add Apple Wallet setup tutorial and runnable scripts
Korbeil Apr 22, 2026
297b557
Add Samsung Wallet setup tutorial and runnable scripts
Korbeil Apr 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .php-cs-fixer.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
<?php

$finder = (new PhpCsFixer\Finder())
->in([__DIR__ . '/src', __DIR__ . '/tests'])
->in([
__DIR__ . '/src',
__DIR__ . '/tests',
__DIR__ . '/examples',
])
;

return (new PhpCsFixer\Config())
Expand Down
70 changes: 53 additions & 17 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Guidance for AI agents in this repo.

## Project

wallet-kit PHP 8.3+ library. Fluent builder for Apple/Google/Samsung Wallet JSON payloads via Symfony Serializer. No signing, no `.pkpass` bundling, no API calls.
wallet-kit is a PHP 8.3+ library for Apple Wallet, Google Wallet, and Samsung Wallet. It covers the full lifecycle: fluent builder API for modeling payloads (via Symfony Serializer), `.pkpass` signing and packaging, API clients for Google and Samsung, Apple push notifications, and an optional Symfony Bundle for full integration (DI, routes, controllers, throttled bulk operations).

## Commands

Expand Down Expand Up @@ -59,29 +59,65 @@ Verticals: Generic, Offer, Loyalty, EventTicket, Flight, Transit, GiftCard — e
### Namespaces

| Namespace | Purpose |
|---|---|
| `Builder\` | Entry point, platform contexts, BuiltWalletPass |
| `Builder\Internal\` | CommonWalletState, barcode mappers |
| `Builder\{Vertical}\` | Vertical builders |
| `Pass\Apple\{Model,Normalizer}\` | Apple models + normalizers |
| `Pass\Android\{Model,Normalizer}\` | Google class/object models + normalizers |
| `Pass\Samsung\{Model,Normalizer}\` | Samsung Card + 8 card types |
| `Common\` | Shared VOs (Color) |
| `Exception\` | Typed, implement WalletKitException |
|-----------|---------|
| `Builder\` | WalletPass entry point, platform contexts, BuiltWalletPass |
| `Builder\Internal\` | CommonWalletState, barcode mappers, helpers |
| `Builder\{Vertical}\` | Vertical-specific builders |
| `Pass\Apple\Model\` | Apple Pass models (Pass, PassStructure, Field, Barcode, enums) |
| `Pass\Apple\Normalizer\` | Symfony Serializer normalizers for Apple |
| `Pass\Android\Model\` | Google Wallet class/object models by vertical |
| `Pass\Android\Normalizer\` | Google normalizers |
| `Pass\Samsung\Model\` | Samsung Card envelope + 8 card type attributes |
| `Pass\Samsung\Normalizer\` | Samsung normalizers |
| `Api\Credentials\` | Credential value objects (AppleCredentials, GoogleCredentials, SamsungCredentials) |
| `Api\Auth\` | TokenInterface, CachedToken, OAuth2/JWT authenticators (Google, Samsung, Apple APNS) |
| `Api\Apple\` | ApplePassPackager (.pkpass signing+ZIP), ApplePushNotifier (APNs HTTP/2), ApnsPushResponse |
| `Api\Google\` | GoogleWalletClient (REST CRUD), GoogleSaveLinkGenerator (offline save links), GoogleApiResponse |
| `Api\Samsung\` | SamsungWalletClient (Partner API CRUD+push), SamsungApiResponse |
| `Api\` | IssuanceHelper (Add to Wallet URLs for all 3 platforms) |
| `Bundle\` | WalletKitBundle, WalletContextFactory, DI configuration |
| `Bundle\Controller\` | Apple Web Service, Google/Samsung callback controllers |
| `Bundle\Repository\` | PassRegistration and PendingOperation repository interfaces + Doctrine implementations |
| `Bundle\Entity\` | PassRegistration, PendingOperation Doctrine entities |
| `Bundle\Messenger\` | ProcessPendingOperationsMessage + Handler (Symfony Messenger) |
| `Bundle\Processor\` | PendingOperationProcessorInterface + Apple/Google/Samsung processors |
| `Bundle\Push\` | ThrottledPushDispatcher (Apple) |
| `Bundle\Google\` | ThrottledGoogleDispatcher, GoogleCallbackHandlerInterface |
| `Bundle\Samsung\` | ThrottledSamsungDispatcher, SamsungCallbackHandlerInterface |
| `Common\` | Shared value objects (Color) |
| `Exception\` | Typed exceptions implementing WalletKitException |
| `Exception\Api\` | API/packaging exceptions (AuthenticationException, HttpRequestException, ApiResponseException, RateLimitException, PackagingException, MissingExtensionException) |

### Serialization

All JSON via Symfony Serializer normalizers (100+). Tests wire the stack via `BuilderTestSerializerFactory` in `tests/Builder/`.

### Platform shapes

- Apple: one `Pass` → one `pass.json`
- Google: Class + Object per vertical, wrapped in `GoogleWalletPair`
- Samsung: unified `Card` + type attributes; 8 card types (7 cross-platform + DigitalId, PayAsYouGo Samsung-only)
- **Apple Wallet:** Single `Pass` object → one `pass.json`. Packaged into `.pkpass` via `ApplePassPackager`. Push updates via APNs HTTP/2.
- **Google Wallet:** Class + Object pairs per vertical (e.g., `EventTicketClass` + `EventTicketObject`), wrapped in `GoogleWalletPair`. CRUD via `GoogleWalletClient`. Save links via `GoogleSaveLinkGenerator`.
- **Samsung Wallet:** Unified `Card` envelope with type-specific attributes, 8 card types (7 cross-platform + DigitalId and PayAsYouGo are Samsung-only). CRUD + push via `SamsungWalletClient`.

### API Layer

- **No new required dependencies** — all API features are optional (ext-openssl, ext-zip, symfony/http-client in `suggest`)
- **Auth**: each platform has its own authenticator with in-memory token caching via `CachedToken`
- **Exceptions**: all implement `WalletKitException`. `RateLimitException` extends `ApiResponseException` for 429 with `retryAfterSeconds`
- **Symfony Bundle**: no autowiring — all services explicitly defined in PHP config files, conditionally loaded per platform

### Conventions

- PHPStan level 5 with `@phpstan-type` shapes
- Enums throughout (CardType, PassType, GoogleVertical, ReviewStatus, …)
- `mutateApple()` / `mutateSamsung()` for post-build tweaks
- `Color` outputs `rgb()`, `hex()`, `googleColor()`
- PHPStan level 5 with extensive `@phpstan-type` shape annotations for validation
- Enums used throughout (CardTypeEnum, PassTypeEnum, GoogleVerticalEnum, ReviewStatusEnum, WalletPlatformEnum, etc.)
- `mutateApple()` and `mutateSamsung()` callbacks allow post-build platform-specific customization
- Color value object supports `rgb()`, `hex()`, and `googleColor()` output formats
- Use `\array_key_exists()` instead of `isset()` or `empty()` in all PHP code
- All concrete classes are `final class`

### Documentation

- `docs/apple.md` — `.pkpass` packaging, push notifications, standalone usage
- `docs/google.md` — API client, save links, standalone usage
- `docs/samsung.md` — API client, card state management, standalone usage
- `docs/bundle.md` — Symfony Bundle: config, DI, Apple Web Service, callbacks, throttled operations
- `docs/builder-examples.md` — Builder cookbook with examples for all 7 verticals
40 changes: 25 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

## Overview

Wallet Kit helps you build the **JSON payloads** wallet platforms expect. It focuses on **modeling and normalization** (via Symfony Serializer): it does **not** sign Apple passes, bundle `.pkpass` files, call Google Wallet APIs, or tokenize Samsung Wallet payloads.
Wallet Kit helps you build, package, and manage wallet passes across Apple Wallet, Google Wallet, and Samsung Wallet. It covers **modeling and normalization** (via Symfony Serializer), **`.pkpass` signing and packaging**, **API clients** for Google and Samsung, **push notifications** for Apple, and an optional **Symfony Bundle** for full integration.

- **PHP** 8.3+
- **symfony/serializer** ^7.4 || ^8.0
Expand Down Expand Up @@ -94,8 +94,27 @@ composer require jolicode/wallet-kit
- `Jolicode\WalletKit\Pass\Apple` — Apple Wallet `pass.json` payloads
- `Jolicode\WalletKit\Pass\Android` — Google Wallet class and object payloads
- `Jolicode\WalletKit\Pass\Samsung` — Samsung Wallet card payloads
- `Jolicode\WalletKit\Builder` — Fluent builders (`WalletPass`, …) for Apple, Google, Samsung, or all
- `Jolicode\WalletKit\Exception` — Builder context and `BuiltWalletPass` accessor exceptions
- `Jolicode\WalletKit\Builder` — Fluent builders (`WalletPass`, ...) for Apple, Google, Samsung, or all
- `Jolicode\WalletKit\Api\Apple` — `.pkpass` packaging, APNs push notifications
- `Jolicode\WalletKit\Api\Google` — Google Wallet REST API client, save link generation
- `Jolicode\WalletKit\Api\Samsung` — Samsung Wallet Partner API client
- `Jolicode\WalletKit\Api\Auth` — OAuth2/JWT authenticators for Google, Samsung, Apple APNs
- `Jolicode\WalletKit\Api\Credentials` — Credential value objects for each platform
- `Jolicode\WalletKit\Bundle` — Symfony Bundle with DI, routes, controllers, and throttled dispatchers
- `Jolicode\WalletKit\Exception` — Typed exceptions for builders, API, and packaging

## Beyond payloads

The library also handles the operational side of wallet passes:

- **Apple `.pkpass` packaging** — sign and bundle passes into `.pkpass` files with localization support
- **Google Wallet API** — create, update, and patch classes and objects, generate "Add to Google Wallet" save links
- **Samsung Wallet API** — create, update, and manage card lifecycle via the Partner API
- **Apple push notifications** — trigger pass refreshes via APNs HTTP/2 with batch support
- **Throttled bulk operations** — DB-backed queue with configurable batch size and interval for large-scale operations
- **Symfony Bundle** — auto-configured services, Apple Web Service endpoints, Google/Samsung callbacks, and a context factory that pre-fills infrastructure values

See platform-specific guides: [Apple](docs/apple.md) ([setup](docs/setup/apple.md)) | [Google](docs/google.md) ([setup](docs/setup/google.md)) | [Samsung](docs/samsung.md) ([setup](docs/setup/samsung.md)) | [Symfony Bundle](docs/bundle.md)

## API spec checks (with Castor)

Expand All @@ -114,20 +133,11 @@ Scripts live under [`tools/spec/`](tools/spec/) and are also invoked by CI (`spe

## Next steps

The library today stops at **typed payloads and normalization**. Planned extensions include:

- [ ] **Apple `.pkpass` packaging** — assemble the pass bundle (images, `pass.json`, manifest), handle **localized resources** (`*.lproj`, string tables), and optionally integrate **signing** so a complete `.pkpass` can be produced from the models you already build.
- [ ] **Google Wallet API client** — HTTP integration to **create, update, and patch** classes and objects (REST), including the **service-account JWT** flow Google expects, so you can go from `BuiltWalletPass::google()` to live passes without wiring the client yourself.
- [ ] **Push notifications & in-wallet updates** — **APNs** integration to trigger **Apple Wallet** pass refreshes (silent/empty push so PassKit pulls a new `pass.json` from your web service), **Google Wallet** support for **API-driven updates** plus **user-visible messages / notification hooks** where the platform exposes them, and **Samsung Wallet** push updates via the **Partner API**, so pass changes actually reach holders' devices across all three platforms.
- [ ] **Samsung Wallet tokenization & Partner API** — JWT token generation for card payloads, HTTP integration with the **Samsung Wallet Partner API** to **create, update, and expire** cards, and card-state lifecycle management, so you can go from `BuiltWalletPass::samsung()` to live cards without wiring the client yourself.

Other directions that often sit next to “wallet” libraries (for later consideration):
Potential future additions:

- **Apple PassKit Web Service** — register/update HTTP endpoints, authentication token handling, and glue between your backend and the **APNs** flow above.
- **Issuance UX helpers** — stable patterns for **Add to Apple Wallet** / **Save to Google Pay** / **Add to Samsung Wallet** links, deep links, and optional **JWT** flows where platforms require them.
- **Operational tooling** — fixtures for integration tests, optional **CLI or Castor tasks** that mirror production steps (e.g. dry-run Google calls, local `.pkpass` inspection).
- **Operational tooling** — fixtures for integration tests, CLI or Castor tasks for dry-run API calls and local `.pkpass` inspection.

Contributions or design discussion for any of the above are welcome.
Contributions and design discussion are welcome.

## License

Expand Down
16 changes: 15 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,20 @@
"symfony/serializer": "^7.4 || ^8.0"
},
"require-dev": {
"phpunit/phpunit": "^12.0"
"phpunit/phpunit": "^12.0",
"symfony/http-client": "^7.4 || ^8.0",
"symfony/framework-bundle": "^7.4 || ^8.0",
"symfony/routing": "^7.4 || ^8.0",
"symfony/messenger": "^7.4 || ^8.0",
"doctrine/orm": "^3.0"
},
"suggest": {
"symfony/http-client": "Required for Google/Samsung API clients and Apple push notifications",
"symfony/framework-bundle": "Required for the Symfony bundle (routes, DI, controllers)",
"symfony/routing": "Required for the Symfony bundle route generation",
"symfony/messenger": "Required for throttled bulk operations",
"doctrine/orm": "Required for default PassRegistration and PendingOperation Doctrine repositories",
"ext-openssl": "Required for Apple .pkpass signing and JWT generation",
"ext-zip": "Required for Apple .pkpass packaging"
}
}
Loading
Loading