diff --git a/REVAMP_PLAN.md b/REVAMP_PLAN.md deleted file mode 100644 index 5359091ce2..0000000000 --- a/REVAMP_PLAN.md +++ /dev/null @@ -1,131 +0,0 @@ -## Payments Revamp Plan - -### 1. Background & Review Feedback - -- PR [#10573](https://github.com/appwrite/appwrite/pull/10573) review (eldadfux) requires moving subscription logic into a dedicated `v1/payments` service, aligned with post-1.7 module architecture and REST plural conventions. -- Avoid extending `/v1/account` and prevent Stripe vendor lock-in; design must allow alternate providers ("UltraPayments" mention) and attach subscriptions to both users and teams. -- Internal usage tracking is still required for quota enforcement while syncing with external billing systems. - -### 2. Current Draft Gaps (auth-subscriptions branch) - -- Controllers: `app/controllers/api/account.php` and `api/auth-plans.php` house payments logic, diverging from modular HTTP action classes (`src/Appwrite/Platform/Modules/*/Http/...`). -- Data Coupling: `app/config/collections/platform.php` and `collections/common.php` now embed Stripe-specific columns (`authStripeSecretKey`, `stripeCustomerId`, etc.), making migration to other providers costly. -- Service Registry: `app/config/services.php` declares an `authPlans` controller entry rather than using a module-driven service (contrast with `functions`/`sites` entries that leave `controller` empty and rely on modules). -- User Records: Subscription status fields live directly on `users`, preventing team sharing and complicating multi-actor ownership. -- Tests & Specs: No module-style route tests or worker coverage; OpenAPI specs patched manually via controller paths. - -### 3. Architectural Principles to Mirror - -- **Module Composition:** Each platform module provides `Module.php` registering `Services/Http.php` (and optional `Services/Workers.php`) (e.g., `src/Appwrite/Platform/Modules/Functions` and `Sites`). Classes extend `Utopia\Platform\Service`, where HTTP service constructors call `addAction()` for each route class (`Create`, `Get`, `XList`, etc.). -- **Route Classes:** HTTP actions extend `Appwrite\Platform\Modules\Compute\Base` (where applicable), use the `HTTP` trait, describe metadata (scopes, events, SDK information), inject dependencies, and implement an `action()` method (see `Functions/Http/Functions/Create.php` and `Sites/Http/Deployments/Template/Create.php`). -- **Platform Bootstrap:** `src/Appwrite/Platform/Appwrite.php` registers modules. New services must follow this pattern so the factory loads them automatically. -- **Collections:** Core metadata uses JSON blobs for provider-specific config (e.g., `projects` collection attributes `services`, `auths`, `smtp` with `json` filter) instead of expanding columns per provider. Use this precedent when storing payments integrations. -- **Testing:** Route behavior is covered via module-specific tests under `tests/e2e/Services` and unit tests for validators. Payment routes must follow same structure. - -### 4. Implementation Roadmap - -#### Phase A – Module Bootstrapping - -- Create `src/Appwrite/Platform/Modules/Payments/Module.php` mirroring `Functions\Module`/`Sites\Module`, registering an HTTP service and (if needed) worker service(s). -- Add `src/Appwrite/Platform/Modules/Payments/Services/Http.php`; register route action classes (Plans, Subscriptions, Usage, Configuration). Maintain naming parity: `Plans\Create.php`, `Plans\Update.php`, `Plans\XList.php`, etc. -- Wire module in `src/Appwrite/Platform/Appwrite.php` via `$this->addModule(new Payments\Module());`. -- Update DI autoload if required (Composer PSR-4 should already include `src/Appwrite`). - -#### Phase B – REST Surface Definition - -- Design plural endpoints under `/v1/payments/...` (e.g., `/v1/payments/plans`, `/v1/payments/subscriptions`, `/v1/payments/subscriptions/{subscriptionId}`, `/v1/payments/providers`). -- Each route should expose scope labels (new `payments.*` scopes) and SDK metadata similar to `Functions` routes. Provide responses using dedicated models (plan, subscription, usage event) under `src/Appwrite/Utopia/Response/Model`. -- Implement both project-admin endpoints (plan management) and authenticated actor endpoints (user/team subscription management). Accept `actorType` and `actorId` to allow teams or users. -- Remove or deprecate `/v1/account/subscription*` routes, replacing them with thin adapters or erroring with migration notice once clients are updated. - -#### Phase C – Scope, Permissions & Service Registry - -- Update `app/config/scopes.php` to introduce `payments.read`, `payments.write`, `payments.subscribe`, and console equivalents. Ensure console/admin scopes map to UI flows. -- Amend `app/config/services.php` to add a `payments` entry with empty `controller` (module-managed), similar to `functions` and `sites`, and expose docs metadata when available. -- Ensure new scopes appear in e2e scope tests (`tests/e2e/Scopes/`) and update SDK generation metadata if necessary. - -#### Phase D – Data Model Restructuring - -- Introduce `app/config/collections/payments.php` (or reuse existing file with new namespace) describing: - - `payments_plans`: plan metadata, generic fields (name, price(s), billing cycle, features) plus `providers` JSON mapping provider IDs/handles. - - `payments_features`: reusable feature definitions with type (`boolean`, `metered`), description, and provider metadata (if applicable). - - `payments_plan_features`: join table storing feature assignments per plan with tiering/usage caps; provider-specific IDs live inside a `providers` JSON object. - - `payments_subscriptions`: subscription records linking `projectId`, `actorType` (`user`/`team`), `actorInternalId`, `planId`, `status`, `lifecycle timestamps`, `quota progress`, and `providers` JSON (customer IDs, subscription IDs, invoice sync state). - - `payments_usage_events`: internal usage ledger capturing increments, reconciliation status, and optional provider receipt IDs. -- Remove Stripe-specific attributes from `app/config/collections/platform.php` and `common.php`; replace with: - - `projects.payments` JSON attribute storing provider configuration (`{"providers": {"stripe": {...}}}`) with `json` and `encrypt` filters for sensitive values. - - Users/teams should no longer carry plan IDs or Stripe identifiers; instead, join via `payments_subscriptions`. -- Provide migration helpers to seed existing data into new collections (see Phase G). - -#### Phase E – Provider Abstraction Layer - -- Define `src/Appwrite/Payments/Provider/ProviderAdapterInterface` encapsulating operations used today (`ensureProduct`, `ensurePrice`, `ensureMeter`, `createCheckoutSession`, `createPortalSession`, `switchPlan`, `cancel`, `reportUsage`, etc.). -- Move `src/Appwrite/Auth/Subscription/StripeService.php` into `src/Appwrite/Payments/Provider/StripeAdapter.php`, implementing the new interface. Update namespaces and dependency injection accordingly. -- Introduce a provider registry/factory (e.g., `src/Appwrite/Payments/Provider/Registry.php`) to resolve adapters based on project configuration (`payments.providers` JSON). Support multiple providers by iterating adapters when needed. -- Relocate validator/exception classes under `src/Appwrite/Payments/` namespace (`Validator/StripeKey.php` → `Payments/Validator/StripeKey.php`) and replace Stripe-specific names with provider-neutral naming where possible. - -#### Phase F – Business Logic Implementation - -- Plan CRUD: Route classes should validate payloads, persist records in `payments_plans`, and delegate provider provisioning via the adapter interface (creating products/prices/meters for configured providers). -- Feature assignment: Manage assignments in `payments_plan_features`, including meter provisioning and tiered pricing via provider adapters. -- Subscription lifecycle: Implement routes for creating/updating/canceling subscriptions. Logic should: - - Resolve actor (user/team) and existing subscription record. - - Ensure plan compatibility and usage caps. - - Call provider adapter to create/update external subscription IDs. - - Persist status, period boundaries, and cancellation flags in `payments_subscriptions`. -- Usage enforcement: Provide endpoints/services to increment usage (`payments_usage_events`), compute current consumption, and determine cap breaches synchronously for feature gating. Expose summary endpoints to clients. -- Configuration flows: Rebuild project-level configuration endpoints (`/v1/projects/:projectId/payments/providers`) under the module, enabling/disabling providers and storing credentials in `projects.payments` JSON. Ensure `StripeAdapter` initialization replicates existing `initializeAccount()` behavior. - -#### Phase G – Background Processing & Workers - -- If asynchronous tasks are required (e.g., syncing usage to providers, handling webhooks), create `src/Appwrite/Platform/Modules/Payments/Services/Workers.php` and worker action classes (pattern from `Functions/Services/Workers.php`). -- Hook into existing queues (`queueForEvents`, `queueForStatsUsage`, etc.) where appropriate to emit events/audits similar to other services. -- Evaluate need for cron tasks to reconcile usage or handle grace periods. - -#### Phase H – Migration & Backward Compatibility - -- Author migration script (CLI task under `src/Appwrite/Platform/Tasks` or a dedicated maintenance script) to: - - Read existing `auth_plans`, `auth_plan_features`, and user subscription fields. - - Populate new `payments_*` collections and JSON config fields. - - Update user/team documents to remove deprecated attributes. -- Provide database migration documentation and fallback strategy (e.g., how to disable payments before upgrade). -- For installations already using the draft branch, document manual steps to transfer customer data. - -#### Phase I – Specification & SDK Updates - -- Regenerate OpenAPI/Swagger specs via existing tooling (`bin/specs` / `src/Appwrite/Platform/Tasks/Specs.php`) after new routes are in place. Confirm console/client/server specs include `payments` namespace. -- Update SDK code generation inputs and ensure new endpoints appear in client/server SDKs with correct grouping. -- Adjust console UI integrations to consume the new endpoints and models (plan lists, subscription management, usage dashboards). - -#### Phase J – Testing Strategy - -- **Unit Tests:** - - Adapter tests mocking Stripe client interactions. - - Validators under `tests/unit/Payments/Validator/*`. -- **Module Route Tests:** - - Add new classes in `tests/e2e/Services/Payments/` covering admin plan management, actor subscription flows, and usage queries for both users and teams. - - Include negative cases (disabled provider, cap exceeded, missing permissions). -- **Integration Tests:** - - Mock provider webhook handling and ensure idempotency. - - Test migrations by seeding legacy data and verifying conversion results. -- Update benchmark/security CI workflows if the new module introduces additional containers or environment variables. - -#### Phase K – Documentation & Developer Experience - -- Draft developer docs (`/docs/services/payments.md`) describing configuration, APIs, and migration steps. -- Update console copy and CLI help text to match new terminology (plans, features, subscriptions, usage events). -- Provide sample scripts for common tasks (e.g., creating plans via CLI/SDK). - -### 5. Open Questions / Follow-Up Items - -- **Multi-provider Support:** Should multiple providers operate simultaneously per project or is it a single active provider? Decide how `providers` JSON is structured (array vs keyed map). -- **Team Billing Semantics:** Clarify how team-owned subscriptions map to team members—do all members share quotas automatically? Need UX decisions in console. -- **Usage Reconciliation:** Define authoritative source when provider usage differs from internal tracking; plan for dispute resolution. -- **Webhook Processing:** Determine whether payments module handles Stripe webhooks or leverages existing generic webhook processor; adjust architecture accordingly. -- **Legacy Clients:** Agree on deprecation timeline for `/v1/account/subscription*` endpoints and provide compatibility shims if required. - -### 6. Next Steps - -- Validate this plan with stakeholders (product + engineering) to confirm scope. -- Sequence implementation into incremental PRs (module scaffolding → data model → provider abstraction → endpoint migration → migrations/tests). -- Reserve time for console integration and documentation updates before GA release. diff --git a/REVAMP_PLAN_DETAILED.md b/REVAMP_PLAN_DETAILED.md deleted file mode 100644 index ebb6d5cc28..0000000000 --- a/REVAMP_PLAN_DETAILED.md +++ /dev/null @@ -1,306 +0,0 @@ -## Payments Revamp Detailed Blueprint - -### Executive Summary - -- Replace draft `/v1/account/subscription*` endpoints with a dedicated `/v1/payments` service implemented as an Appwrite platform module, satisfying Eldad’s review. -- Deliver provider-agnostic APIs and data model so multiple payment vendors can plug in without breaking clients. -- Introduce robust internal usage controls and enable subscriptions for both users and teams, matching multi-tenant requirements. - -### 1. Service Architecture - -1. **Module Registration** - - - Add `Appwrite\Platform\Modules\Payments\Module` mirroring existing modules (`Functions`, `Sites`). - - Register in `Appwrite\Platform\Appwrite::__construct` via `$this->addModule(new Payments\Module());`. - - Provide `Services/Http.php` and optional `Services/Workers.php` classes inheriting `Utopia\Platform\Service`. - - Use registrar pattern if route count grows (similar to `Databases\Services\Registry`). - -2. **Route Classes (per Endpoint)** - - - Location: `src/Appwrite/Platform/Modules/Payments/Http/...`. - - Each class extends `Appwrite\Platform\Modules\Compute\Base` or a lighter abstract if no compute needs, uses `use HTTP;`, configures metadata (`setHttpMethod`, `setHttpPath`, `desc`, `groups`, `label`, `param`). - - Inject dependencies via `->inject()` matching established pattern (response, db, queue, project, user/team documents, adapter registry). - - Return models defined in `src/Appwrite/Utopia/Response/Model` (new models for payments entities). - -3. **SDK & Metadata Integration** - - Add `->label('sdk', new Method(...))` for each route to define namespace/group (`payments`) and auth types. - - Define new permission scopes (`payments.read`, `payments.write`, `payments.subscribe`) and map in `app/config/scopes.php` for client, server, console contexts. - - Ensure each action sets `resourceType`, `event`, `audits.*` labels where relevant to integrate with events/auditing infrastructure. - -### 2. API Surface - -Below is the proposed REST contract (subject to iterative refinement). All endpoints live under `/v1/payments` unless noted. - -| Endpoint | Method | Description | Auth scopes | Notes | -| --------------------------------------------------- | ------ | ----------------------------------------- | ---------------------------------------- | ----------------------------------------------------------------------------------------- | -| `/v1/payments/plans` | POST | Create plan | `payments.write` (project admin) | Accepts plan metadata, pricing options, feature definitions. Returns plan model. | -| `/v1/payments/plans` | GET | List plans | `payments.read` | Supports queries/filtering; returns paginated list. | -| `/v1/payments/plans/:planId` | GET | Get single plan | `payments.read` | | -| `/v1/payments/plans/:planId` | PUT | Update plan | `payments.write` | Provider-specific updates routed through adapters while preserving API stability. | -| `/v1/payments/plans/:planId` | DELETE | Archive/deactivate plan | `payments.write` | Soft-delete toggles `active=false`. | -| `/v1/payments/plans/:planId/features` | POST | Assign/Reconfigure features | `payments.write` | Handles metered tiers, usage caps. | -| `/v1/payments/plans/:planId/features` | GET | List assigned features | `payments.read` | | -| `/v1/payments/plans/:planId/features/:featureId` | DELETE | Remove feature | `payments.write` | | -| `/v1/payments/features` | POST | Create reusable feature definition | `payments.write` | Feature types: `boolean`, `metered`, potential future types. | -| `/v1/payments/features` | GET | List features | `payments.read` | | -| `/v1/payments/features/:featureId` | PUT | Update feature | `payments.write` | | -| `/v1/payments/features/:featureId` | DELETE | Archive feature | `payments.write` | | -| `/v1/payments/providers` | GET | Get project payments configuration | `payments.read` (admin) | Returns provider statuses, capabilities. | -| `/v1/payments/providers` | PUT | Configure providers | `payments.write` (admin) | Accepts provider credentials/options; triggers adapter bootstrap (webhooks, products). | -| `/v1/payments/providers/:providerId/actions/test` | POST | Validate provider credentials | `payments.write` | Optional sanity check endpoint per provider. | -| `/v1/payments/subscriptions` | POST | Create subscription | `payments.subscribe` (actor) | Body contains `actorType` (`user`/`team`), `actorId`, `planId`, optional payment options. | -| `/v1/payments/subscriptions` | GET | List subscriptions | `payments.read` | Filters: actor, plan, status, provider. | -| `/v1/payments/subscriptions/:subscriptionId` | GET | Retrieve subscription | `payments.read` | Validates access (actor membership, admin). | -| `/v1/payments/subscriptions/:subscriptionId` | PATCH | Update subscription (plan switch, cancel) | `payments.subscribe` or `payments.write` | Handles upgrade/downgrade, cancellation, metadata updates. | -| `/v1/payments/subscriptions/:subscriptionId/cancel` | POST | Explicit cancel endpoint | `payments.subscribe` | Sets cancel at period end or immediate cancel. | -| `/v1/payments/subscriptions/:subscriptionId/resume` | POST | Resume cancelled subscription | `payments.subscribe` | | -| `/v1/payments/subscriptions/:subscriptionId/usage` | GET | Get detailed usage summary | `payments.read` | Combines internal events with provider sync status. | -| `/v1/payments/subscriptions/:subscriptionId/usage` | POST | Report usage event | `payments.subscribe` (server key) | For services to emit usage increments (e.g., rate limiting). Supports batching. | -| `/v1/payments/usage/events` | GET | Query raw usage events | `payments.read` | For analytics/monitoring. | -| `/v1/payments/usage/reconcile` | POST | Trigger reconciliation with provider | `payments.write` | Optional admin action to force sync. | -| `/v1/payments/webhooks/:providerId` | POST | Provider webhook endpoint (internal) | Auth via signature | Each provider adapter registers handler. Routed outside public docs. | - -**Compatibility:** - -- Terminate legacy `/v1/account/subscription*` routes after transitional period. Provide compatibility wrappers that call `payments` module while returning same payload shape to avoid immediate SDK breakage. - -### 3. Provider Plug-in System - -1. **Core Concepts** - - - Interface: `src/Appwrite/Payments/Provider/Adapter.php` (or `ProviderAdapterInterface`) defines actions consumed by module. - - Responsibilities: product/price lifecycle, customer management, subscription lifecycle, metered usage reporting, invoice retrieval, webhook verification, credential validation. - -2. **Adapter Interface Sketch** - -```php - { productId, priceIds, metadata }. - - `features` summary JSON for quick lookup. - - Indexes: unique (`projectId`, `planId`), key on `status`, fulltext `search` combining name/description. - -2. **`payments_features`** - - - Definition list available for assignment to plans. - - Attributes: `featureId`, `name`, `type`, `description`, `defaultIncludedUnits`, `defaultTiers`, etc. - - `providers` JSON storing mapping to external meter IDs or feature codes. - - Indexes: unique (`projectId`, `featureId`), key on `type`. - -3. **`payments_plan_features`** - - - Join table linking plans to feature configs. - - Attributes: `planId`, `featureId`, `type`, `enabled`, `currency`, `interval`, `includedUnits`, `tiersMode`, `tiers`, `usageCap`, `overagePrice`, `providers` JSON (price/meter references), `metadata` JSON. - - Indexes: unique (`projectId`, `planId`, `featureId`), key on `type`, `active` flag. - -4. **`payments_subscriptions`** - - - Tracks active/past subscriptions. - - Attributes: `subscriptionId` (Appwrite ID), `projectId`, `actorType` (`user`/`team`), `actorId`, `actorInternalId`, `planId`, `status`, `trialEndsAt`, `currentPeriodStart`, `currentPeriodEnd`, `cancelAtPeriodEnd`, `canceledAt`, `providerStatus`, `providers` JSON (customerId, subscriptionId, invoiceId, lastSyncedAt), `usageSummary` JSON, `tags` array, `search` field. - - Indexes: key on (`projectId`, `actorType`, `actorId`), key on `status`, key on `planId`, fulltext search. - -5. **`payments_usage_events`** - - - Internal usage ledger. - - Attributes: `projectId`, `subscriptionId`, `actorType`, `actorId`, `planId`, `featureId`, `quantity`, `timestamp`, `providerSyncState`, `providerEventId`, `metadata`. - - Indexes: key on (`projectId`, `subscriptionId`, `featureId`, `timestamp`), key on `providerSyncState`. - -6. **`payments_provider_logs`** (optional) – store provider interactions/webhook payloads for debugging. - -**Migration Strategy** - -- Update `app/config/collections.php` to load `payments.php` similar to other modules. - -### 5. Business Logic Flow - -1. **Plan Creation** - - - Validate request (IDs, pricing structure) using new validators (`Payments\Validator\PlanPayload`). - - Persist plan document in `payments_plans` (without provider references initially). - - For each enabled provider, call adapter->ensurePlan. Merge returned references into `providers` JSON and persist. - - Emit events/audits (`payments.plans.[planId].create`). - -2. **Feature Assignment** - - - Validate feature definitions exist and types are allowed. - - Persist in `payments_plan_features`, call adapter->ensureFeature where required (e.g., create metered price). Update plan document summary. - -3. **Subscription Lifecycle** - - - `POST /subscriptions`: Determine actor document (fetch user or team). If team, ensure membership + permissions. - - Check existing active subscription; depending on config, allow multiple or enforce single. - - For free plans: create internal subscription record without provider interaction. - - For paid plans: adapter->ensureSubscription (create customer if needed, attach payment method, start subscription). Store provider subscription ID and status. - - Update `payments_subscriptions` with internal status (`active`, `trialing`, `past_due`, etc.). - - Trigger usage initialization jobs and optionally send welcome events. - -4. **Usage Tracking** - - - Services emit usage via `POST /subscriptions/:id/usage` (server key or internal worker). Each entry stored in `payments_usage_events` and aggregated for quick reads. - - Cron/worker picks unsynced events, groups by provider, calls adapter->reportUsage or other relevant API. - - `GET /subscriptions/:id/usage` returns aggregated totals (internal vs provider synced) plus detail entries. - -5. **Provider Webhooks** - - - Webhook endpoint verifies signature (adapter->handleWebhook). Update subscription statuses (e.g., `past_due`, `canceled`), record invoice IDs, mark usage sync states. - - Fire events to notify console or automation flows. - -6. **Project Configuration** - - `PUT /payments/providers`: Accept provider configs, run validations (fields required per provider). Adapter->configure may create webhook endpoints, check API keys. Persist sanitized config in `project.payments` JSON and update `projects` document. - - Provide GET endpoint returning provider status for console (enabled, last sync, warnings). - -### 6. Security & Permissions - -- Scope mapping: - - `payments.read`: Admins or service keys retrieving plan/subscription data. - - `payments.write`: Admin actions to manage plans, providers, migrations. - - `payments.subscribe`: Actors initiating subscription changes (users/teams). Distinguish between user session vs team owner in access control. -- Authorization logic uses existing role helpers (e.g., `Role::user`, `Role::team`). Ensure team endpoints check membership + `owner` or `billing` roles. -- Sensitive provider credentials stored encrypted; route responses never expose secrets. -- Webhook endpoints use provider-specific secret validation; avoid exposing under public documentation. - -### 7. Testing & QA - -- **Unit Tests:** - - Provider adapter contract (mock HTTP clients) verifying plan creation, subscription lifecycle, error propagation. - - Validators for plan payloads, provider configs. -- **E2E Tests:** - - Add `tests/e2e/Services/Payments/` with scenarios: plan CRUD, subscription flow (user + team), usage reporting, provider configuration failure. - - Use mock provider adapter for deterministic responses. -- **Integration Tests:** - - Worker tests simulating usage reconciliation. - - Migration tests verifying data transformation from legacy schemas. -- **Benchmarks:** - - Evaluate overhead of usage events and plan operations under load to adjust indexes. - -### 8. Migration & Rollout - -1. **Phase Gate** - - - Ship module behind feature flag (`project.payments.enabled`). Default disabled until admin configures provider. - - Provide CLI to enable module per project post-migration. - -2. **Data Migration** - - - CLI script reads existing `auth_*` collections and populates new schema. - - Migrate user-level `planId`, `stripeCustomerId`, etc., into `payments_subscriptions` records with `actorType=user`. - - Generate default team subscriptions if teams had equivalent data (if none, start blank). - -3. **Documentation & Console Update** - - Update console to consume `/v1/payments` endpoints (plan management UI, subscription views, usage dashboards). - - Provide developer docs describing multi-actor support, provider configuration, usage APIs, error handling. - -### 9. Open Issues & Decisions Needed - -- **Team billing semantics**: define allowed team roles for subscription management, and how consumption is aggregated across team members. -- **Multiple providers simultaneously**: Determine whether a project can use multiple providers concurrently (failover vs multi-market). Data model supports multiple by design; confirm product direction. -- **Self-hosted provider**: Consider built-in “Manual” provider for on-prem setups wanting internal invoicing without external gateway. -- **Plan versioning**: Decide if plan updates create new versions or mutate in place; consider locking for existing subscriptions. -- **Grace periods**: Align with Stripe-style grace or immediate suspension rules; ensure configurable per provider/project. - -### 10. Next Steps - -1. Validate blueprint with stakeholders (engineering leads, product). -2. Break implementation into milestones: module skeleton → data schema → provider abstraction → endpoints → migrations/tests. -3. Allocate time for console integration and documentation once backend stabilizes. diff --git a/REVAMP_STEPS.md b/REVAMP_STEPS.md deleted file mode 100644 index 11847a349e..0000000000 --- a/REVAMP_STEPS.md +++ /dev/null @@ -1,350 +0,0 @@ -# Payments Revamp Stepbook - -This stepbook sequences the end-to-end implementation of the payments revamp. Each step is agent-friendly, with explicit prerequisites, work instructions, deliverables, and verification guidance. Follow the steps in order unless a dependency explicitly states otherwise. - -## Legend - -- **Prereqs**: Conditions or artifacts required before tackling the step. -- **Core Tasks**: Ordered instructions for human/AI agents. -- **Outputs**: Expected tangible results (code, docs, configs). -- **Verification**: Commands or checks that confirm completion. -- **Handoff**: Follow-up steps or consumers of the outputs. - ---- - -## Step 1 – Module Scaffolding - -- **Prereqs** - - Workspace prep complete. -- **Core Tasks** - 1. Create module namespace: `src/Appwrite/Platform/Modules/Payments/`. - 2. Add `Module.php` mirroring structure of `Functions\Module`. - 3. Create `Services/Http.php` (and placeholder `Services/Workers.php` if background work planned) extending `Utopia\Platform\Service`. - 4. Register module within `src/Appwrite/Platform/Appwrite.php` constructor via `$this->addModule(new Payments\Module());`. - 5. Ensure Composer autoload already covers `src/Appwrite` (confirm `composer.json` PSR-4 mapping). If gaps exist, patch accordingly. -- **Outputs** - - Module skeleton files committed with minimal placeholder logic. -- **Verification** - - `composer dump-autoload` executes without errors. - - `vendor/bin/phpunit --filter Payments` (should report zero tests but no failures). - - `php -l` on new files passes. -- **Handoff** - - Step 4 uses module skeleton to register HTTP actions. - -## Step 4 – HTTP Route Class Framework - -- **Prereqs** - - Module skeleton registered; app boots without fatal errors. -- **Core Tasks** - 1. Design folder structure under `src/Appwrite/Platform/Modules/Payments/Http/` matching endpoint domains (e.g., `Plans`, `Features`, `PlanFeatures`, `Subscriptions`, `Usage`, `Providers`, `Webhooks`). - 2. For each endpoint group, create base action classes extending `Appwrite\Platform\Modules\Compute\Base` (or appropriate lightweight variant) and `use HTTP` trait. - 3. In `Services/Http.php`, call `addAction(new Plans\Create())`, etc., for every planned route. - 4. Stub methods: set `setName`, `setHttpMethod`, `setHttpPath`, `setDescription`, `setGroup`, placeholder `->param` definitions. - 5. Add TODO comments referencing Step 8/9 tasks for actual business logic. -- **Outputs** - - Skeleton route classes with metadata scaffolding. -- **Verification** - - `php -l` on all HTTP files. - - Application boot (via `php -d detect_unicode=0 app/init.php`) logs no missing class errors. -- **Handoff** - - Step 5 introduces scope/SDK metadata consumed by these classes. - -## Step 5 – Scope & SDK Metadata Wiring - -- **Prereqs** - - Route classes stubbed. -- **Core Tasks** - 1. Update `app/config/scopes.php` to define `payments.read`, `payments.write`, `payments.subscribe` (client/server/console mappings per blueprint). - 2. Add console/admin scope entries and ensure scope descriptions reflect usage. - 3. In each route class, register SDK metadata via `$this->label('sdk', new Method(...))` specifying group `payments`, auth types, and method name. - 4. Annotate routes with `->label('scope', 'payments.read')` etc.; include `resourceType`, `event`, and `audits.*` labels where applicable. - 5. Update scope tests under `tests/e2e/Scopes` (add cases ensuring new scopes exist and map to correct roles). - 6. Regenerate scope documentation if automation expects (`bin/specs scopes`). -- **Outputs** - - Scopes defined and linked; routes enriched with metadata. -- **Verification** - - `vendor/bin/phpunit tests/e2e/Scopes` passes (or targeted test command). - - `bin/specs` (or relevant generator) succeeds without missing scope errors. -- **Handoff** - - Step 6 relies on new scopes for permission configuration. - -## Step 6 – Data Model Definition - -- **Prereqs** - - Scope wiring complete; DBA consulted for index strategy (if required). -- **Core Tasks** - 1. Create `app/config/collections/payments.php` describing all new collections: - - `payments_plans` - - `payments_features` - - `payments_plan_features` - - `payments_subscriptions` - - `payments_usage_events` - - optional `payments_provider_logs` - 2. For each collection, define attributes (types, filters, required flags) exactly as blueprint specifies (IDs, JSON fields, indexes, encryption flags). - 3. Update `app/config/collections.php` to include the new config file. - 4. Remove/flag legacy Stripe-specific attributes from `app/config/collections/platform.php` and `app/config/collections/common.php`; add `projects.payments` JSON attribute with `encrypt` filter for secrets. - 5. Draft migration notes describing how new collections replace old fields (feeds into Step 11). -- **Outputs** - - Payments collections configuration file with indexes and attribute metadata. - - Legacy collection definitions cleaned up. -- **Verification** - - Run `php -d detect_unicode=0 app/init.php` to ensure config loads. - - `vendor/bin/phpunit tests/unit/Database/Collections` (or relevant) passes. -- **Handoff** - - Step 7 implements provider abstractions referencing new schema. - -## Step 7 – Provider Abstraction Layer - -- **Prereqs** - - Data model defined; requirements for provider interactions clarified. -- **Core Tasks** - 1. Create namespace `src/Appwrite/Payments/Provider/`. - 2. Implement `Adapter` interface (or `ProviderAdapterInterface`) as per blueprint signature (plan management, subscriptions, usage, webhooks, testing). - 3. Define supporting value objects (`ProviderState`, `ProviderPlanRef`, `ProviderFeatureRef`, `ProviderSubscriptionRef`, `ProviderCheckoutSession`, `ProviderPortalSession`, `ProviderUsageReport`, `ProviderWebhookResult`, `ProviderTestResult`). - 4. Build `Registry` class to resolve adapters by identifier, instantiate with project-specific config, and cache where appropriate. - 5. Migrate existing Stripe logic (`src/Appwrite/Auth/Subscription/StripeService.php`) into `Payments\Provider\StripeAdapter` implementing interface. - 6. Relocate validators and exceptions into `src/Appwrite/Payments/Validator` and `src/Appwrite/Payments/Exception\PaymentException.php`. - 7. Ensure adapter error handling maps provider-specific issues to standardized `PaymentException` codes (`PROVIDER_AUTH_FAILED`, `PLAN_CONFLICT`, etc.). -- **Outputs** - - Provider interface and registry. - - Stripe adapter aligned with new abstractions. -- **Verification** - - Unit tests for registry and adapter contract (`tests/unit/Payments/Provider/`) passing. - - Static analysis (`vendor/bin/phpstan analyse src/Appwrite/Payments`). -- **Handoff** - - Step 8 integrates registry into route actions. - -## Step 8 – Business Logic Integration (Plans & Features) - -- **Prereqs** - - Provider layer functional; data model available. -- **Core Tasks** - 1. Implement `Plans` routes (`Create`, `Get`, `List`, `Update`, `Delete`) to validate payloads (`Payments\Validator\PlanPayload`), persist documents in `payments_plans`, and invoke provider adapters for provisioning. - 2. Build `Features` routes for reusable feature definitions, including create/update/delete flows with provider interactions (`ensureFeature`). - 3. Implement `PlanFeatures` routes (`Assign`, `List`, `Remove`) to link plans and features, manage tiered pricing, and update plan summaries. - 4. Ensure events/audits triggered (`payments.plans.{planId}.create`, etc.). - 5. Write unit tests for validators and repository interactions; add e2e tests covering positive/negative plan scenarios. -- **Outputs** - - Fully functioning plan and feature endpoints with provider provisioning. -- **Verification** - - `vendor/bin/phpunit tests/unit/Payments/Plans` and `tests/e2e/Services/Payments/Plans`. - - Manual API smoke tests via `docs/scripts` or HTTP client verifying CRUD operations. -- **Handoff** - - Step 9 builds subscription lifecycle using same abstractions. - -## Step 9 – Business Logic Integration (Subscriptions & Usage) - -- **Prereqs** - - Plans/features endpoints operational; provider adapter tested. -- **Core Tasks** - 1. Implement subscription routes: - - `POST /v1/payments/subscriptions` - - `GET /v1/payments/subscriptions` - - `GET /v1/payments/subscriptions/:subscriptionId` - - `PATCH /v1/payments/subscriptions/:subscriptionId` - - `POST /v1/payments/subscriptions/:subscriptionId/cancel` - - `POST /v1/payments/subscriptions/:subscriptionId/resume` - 2. Logic should: - - Resolve actor documents (user/team) with permission checks. - - Handle free vs paid plan flows (internal-only vs provider interactions). - - Persist subscription state in `payments_subscriptions` with lifecycle timestamps. - - Trigger events/audits and queue initialization jobs. - 3. Implement usage endpoints: - - `GET /v1/payments/subscriptions/:subscriptionId/usage` - - `POST /v1/payments/subscriptions/:subscriptionId/usage` - - `GET /v1/payments/usage/events` - - `POST /v1/payments/usage/reconcile` - 4. Wire usage reporting to adapters (`reportUsage`, `syncUsage`) and internal ledger (`payments_usage_events`). - 5. Add permission checks for `payments.subscribe` vs `payments.write`; ensure team role enforcement (`owner`, `billing`). - 6. Unit + e2e tests covering actor scenarios, cancellations, resumes, usage reporting, reconciliation. -- **Outputs** - - Subscription and usage endpoints with provider interoperability. -- **Verification** - - `vendor/bin/phpunit tests/unit/Payments/Subscriptions` & `Usage` suites. - - `tests/e2e/Services/Payments/Subscriptions` scenarios. - - Manual smoke test (create plan, assign feature, create subscription, report usage, reconcile). -- **Handoff** - - Step 10 handles provider configuration endpoints and webhooks. - -## Step 10 – Provider Configuration & Webhooks - -- **Prereqs** - - Adapter registry in place; subscription flows implemented. -- **Core Tasks** - 1. Build provider management routes: - - `GET /v1/payments/providers` - - `PUT /v1/payments/providers` - - `POST /v1/payments/providers/:providerId/actions/test` - 2. Persist provider configuration in `projects.payments` JSON (encrypted fields) with validation per provider. - 3. Implement webhook handler `POST /v1/payments/webhooks/:providerId` with signature validation delegating to adapter `handleWebhook`. - 4. Ensure webhook updates subscription status, invoices, usage sync states, and emits relevant events. - 5. Add unit tests for configuration validators and webhook processing; e2e tests simulating webhook payloads (mock provider). -- **Outputs** - - Provider configuration endpoints and webhook infrastructure. -- **Verification** - - `vendor/bin/phpunit tests/unit/Payments/Providers`. - - `tests/e2e/Services/Payments/Providers` including webhook scenarios. -- **Handoff** - - Step 11 introduces background workers for async tasks. - -## Step 11 – Background Workers & Queues - -- **Prereqs** - - Provider webhooks implemented; need for async operations confirmed. -- **Core Tasks** - 1. If required, implement `Services/Workers.php` under payments module registering worker actions (usage sync, webhook replay, reconciliation, notifications). - 2. Connect workers to relevant queues (`queueForEvents`, `queueForStatsUsage`, etc.). - 3. Implement worker handlers for: - - Processing unsynced usage events in batches. - - Retrying failed provider interactions. - - Emitting audit logs/notifications. - 4. Add configuration toggles/cron definitions if periodic jobs required. - 5. Write worker unit/integration tests (simulate queue payloads, ensure idempotency) and update CI to execute them. -- **Outputs** - - Worker services handling async tasks with tests. -- **Verification** - - `vendor/bin/phpunit tests/unit/Payments/Workers`. - - Manual queue dry-run via `php bin/queue --capture payments-usage-sync` (or equivalent) shows successful execution. -- **Handoff** - - Step 12 manages migrations and data backfill. - -## Step 12 – Data Migration & Compatibility Layer - -- **Prereqs** - - Core functionality ready; legacy schema inventoried. -- **Core Tasks** - 1. Develop migration CLI (e.g., `src/Appwrite/Platform/Tasks/MigratePayments.php`) to read legacy `auth_*` collections and user fields, populate new `payments_*` collections. - 2. Handle user-level Stripe data conversion into subscriptions (`actorType=user`) and generate team records as needed. - 3. Provide dry-run mode producing migration report. - 4. Implement compatibility wrappers for legacy `/v1/account/subscription*` endpoints (if transitional period required) calling new module while preserving response shape. - 5. Document manual fallback steps (disable module, rollback) and update upgrade scripts (`bin/upgrade`, `bin/migrate`). -- **Outputs** - - Migration CLI + documentation. - - Optional compatibility endpoints bridging legacy clients. -- **Verification** - - `php bin/migrate payments --dry-run` (or equivalent) generates expected report. - - Integration test seeding legacy data and validating converted records. -- **Handoff** - - Step 13 regenerates specifications and SDKs. - -## Step 13 – Specification & SDK Updates - -- **Prereqs** - - API routes finalized; migration plan approved. -- **Core Tasks** - 1. Update OpenAPI spec generation tooling (`bin/specs`, `src/Appwrite/Platform/Tasks/Specs.php`) to include `/v1/payments` endpoints with accurate schemas/models. - 2. Create new response models under `src/Appwrite/Utopia/Response/Model` (Plan, PlanList, Feature, Subscription, UsageEvent, etc.) and ensure routes reference them. - 3. Regenerate SDKs (`bin/sdks generate all`) and verify new payments namespace appears across client/server SDKs. - 4. Audit console web client to ensure TypeScript models integrate new endpoints (update `public/sdk-console` if required). -- **Outputs** - - Updated specs, generated SDK artifacts, and console types. -- **Verification** - - `git diff` shows updated spec JSON + SDK source. - - Run sample SDK script invoking payments endpoints successfully (smoke test). -- **Handoff** - - Step 14 focuses on testing strategy. - -## Step 14 – Testing & Quality Assurance - -- **Prereqs** - - Functional code complete; tests implemented alongside earlier steps. -- **Core Tasks** - 1. Ensure unit, e2e, integration, and worker tests cover: - - Plan/feature CRUD - - Subscription lifecycle (user/team) - - Usage reporting & reconciliation - - Provider configuration + webhooks - - Migration scripts - 2. Add benchmark tests if usage events need performance validation. - 3. Execute full test matrix: `vendor/bin/phpunit`, `npm run test` (if console updated), `bin/bench` (if available). - 4. Collect coverage report and ensure thresholds met (update `phpunit.xml` if needed). - 5. Document manual QA scenarios (console UI walk-through, webhook replay). -- **Outputs** - - Comprehensive passing test suite and QA checklist. -- **Verification** - - CI pipeline green across all stages. - - QA sign-off recorded in tracker. -- **Handoff** - - Step 15 handles documentation and developer experience. - -## Step 15 – Documentation & Developer Experience - -- **Prereqs** - - Testing complete; product sign-off on functionality. -- **Core Tasks** - 1. Author `docs/services/payments.md` covering configuration, endpoints, usage reporting, migration notes. - 2. Update console documentation and copy (billing UI, error messages). - 3. Refresh developer tutorials (CLI scripts for plan creation, sample usage reporting). - 4. Update CHANGELOG/RELEASE notes summarizing payments revamp. - 5. Provide sample automation scripts in `docs/examples` demonstrating typical flows. -- **Outputs** - - Updated documentation stack. -- **Verification** - - Docs build (if applicable) passes (`npm run docs:build` or similar). - - Technical writers/product review completed. -- **Handoff** - - Step 16 manages rollout and feature flagging. - -## Step 16 – Rollout & Feature Flag Management - -- **Prereqs** - - Documentation ready; QA sign-off. -- **Core Tasks** - 1. Implement feature flag gating (`project.payments.enabled`) with default disabled; ensure configuration endpoint toggles it. - 2. Prepare rollout plan (beta projects, staged enablement, monitoring dashboards). - 3. Update CLI tooling or admin UI to toggle flag per project post-migration. - 4. Coordinate with support to craft customer communication, fallback procedures. - 5. Monitor metrics (errors, webhook failures, subscription churn) during rollout. -- **Outputs** - - Feature flag controls, rollout schedule, monitoring plan. -- **Verification** - - Dry-run enabling flag on staging succeeds end-to-end. - - Monitoring alerts configured with thresholds. -- **Handoff** - - Step 17 covers legacy deprecation. - -## Step 17 – Legacy Endpoint Deprecation - -- **Prereqs** - - Rollout underway; compatibility shims deployed. -- **Core Tasks** - 1. Announce deprecation timeline for `/v1/account/subscription*` endpoints. - 2. Implement logging/metrics to detect lingering usage of legacy endpoints. - 3. Provide migration guidance to SDK consumers (release notes, upgrade guides). - 4. Schedule removal window; when ready, retire compatibility shims and delete legacy controllers/config. - 5. Update specs/SDKs to remove legacy endpoints once EOL date passes. -- **Outputs** - - Legacy endpoints officially deprecated and removed per schedule. -- **Verification** - - No production traffic to legacy routes (dashboards confirm zero hits). - - Codebase free of legacy controllers/paths. -- **Handoff** - - Step 18 finalizes project closure. - -## Step 18 – Project Closure & Retrospective - -- **Prereqs** - - Legacy endpoints removed; new payments module stable in production. -- **Core Tasks** - 1. Conduct retrospective documenting successes, challenges, follow-up actions. - 2. Archive decision log updates, migration scripts outcomes, and open issues resolved/deferred. - 3. Confirm tracker tasks closed and post-rollout monitoring handed to operations. - 4. Celebrate with team acknowledgement (optional but recommended!). -- **Outputs** - - Retrospective report, cleaned tracker, knowledge captured. -- **Verification** - - All project artifacts stored in agreed knowledge base. - - Stakeholders acknowledge completion. -- **Handoff** - - None; project concluded. - ---- - -### Supporting References - -- `REVAMP_PLAN_DETAILED.md` – Deep blueprint for architecture, API, adapters, data model. -- `REVAMP_PLAN.md` – High-level roadmap and phase breakdown. -- Existing module patterns: `src/Appwrite/Platform/Modules/Functions`, `Sites`. -- Provider integration precedents: `src/Appwrite/Messaging/Provider`, `src/Appwrite/Auth/Subscription/StripeService.php` (legacy). - -Use this stepbook as the authoritative sequencing for agents and humans collaborating on the payments revamp. Update the document if scope adjustments or new decisions arise. diff --git a/TEST_PLAN.md b/TEST_PLAN.md deleted file mode 100644 index 6762c61ed7..0000000000 --- a/TEST_PLAN.md +++ /dev/null @@ -1,370 +0,0 @@ -## Payments Revamp Test Plan (Step-by-step, with sample bodies) - -Variables used below: - -- BASE: https://your-appwrite-endpoint -- PROJECT_ID: your project ID -- API_KEY: Admin API key with payments.write/read/subscribe -- USER_ID: existing user ID (payer for user subscriptions and team payer) -- TEAM_ID: existing team ID (for team subscriptions) - -Common headers (Admin key): - -``` --H "X-Appwrite-Project: PROJECT_ID" \ --H "X-Appwrite-Key: API_KEY" \ --H "Content-Type: application/json" -``` - -### 1) Configure provider (Stripe) and enable payments - -Request: - -```bash -curl -X PUT "$BASE/v1/payments/providers" \ - -H "X-Appwrite-Project: PROJECT_ID" \ - -H "X-Appwrite-Key: API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "config": { - "enabled": true, - "providers": { - "stripe": { - "secretKey": "sk_test_xxx", - "publishableKey": "pk_test_xxx" - } - } - } - }' -``` - -Verify (secrets masked): - -```bash -curl -X GET "$BASE/v1/payments/providers" \ - -H "X-Appwrite-Project: PROJECT_ID" \ - -H "X-Appwrite-Key: API_KEY" -``` - -Optional: test credentials - -```bash -curl -X POST "$BASE/v1/payments/providers/stripe/actions/test" \ - -H "X-Appwrite-Project: PROJECT_ID" \ - -H "X-Appwrite-Key: API_KEY" -``` - -### 2) Create feature definitions - -2a. Boolean feature (e.g., builds): - -```bash -curl -X POST "$BASE/v1/payments/features" \ - -H "X-Appwrite-Project: PROJECT_ID" -H "X-Appwrite-Key: API_KEY" -H "Content-Type: application/json" \ - -d '{ - "featureId": "builds", - "name": "Builds", - "type": "boolean", - "description": "Ability to run builds" - }' -``` - -2b. Metered feature (e.g., requests): - -```bash -curl -X POST "$BASE/v1/payments/features" \ - -H "X-Appwrite-Project: PROJECT_ID" -H "X-Appwrite-Key: API_KEY" -H "Content-Type: application/json" \ - -d '{ - "featureId": "requests", - "name": "Requests", - "type": "metered", - "description": "Metered API requests" - }' -``` - -List features: - -```bash -curl -X GET "$BASE/v1/payments/features" \ - -H "X-Appwrite-Project: PROJECT_ID" -H "X-Appwrite-Key: API_KEY" -``` - -### 3) Create a plan with pricing - -```bash -curl -X POST "$BASE/v1/payments/plans" \ - -H "X-Appwrite-Project: PROJECT_ID" -H "X-Appwrite-Key: API_KEY" -H "Content-Type: application/json" \ - -d '{ - "planId": "pro", - "name": "Pro", - "description": "Pro plan", - "isDefault": false, - "isFree": false, - "pricing": [ - { "amount": 1999, "currency": "usd", "interval": "month" }, - { "amount": 19900, "currency": "usd", "interval": "year" } - ] - }' -``` - -Get plan: - -```bash -curl -X GET "$BASE/v1/payments/plans/pro" \ - -H "X-Appwrite-Project: PROJECT_ID" -H "X-Appwrite-Key: API_KEY" -``` - -### 4) Assign features to the plan - -4a. Assign boolean feature (type inferred from feature): - -```bash -curl -X POST "$BASE/v1/payments/plans/pro/features" \ - -H "X-Appwrite-Project: PROJECT_ID" -H "X-Appwrite-Key: API_KEY" -H "Content-Type: application/json" \ - -d '{ - "featureId": "builds", - "currency": "usd", - "interval": "month", - "includedUnits": 0 - }' -``` - -4b. Assign metered feature (type inferred from feature): - -```bash -curl -X POST "$BASE/v1/payments/plans/pro/features" \ - -H "X-Appwrite-Project: PROJECT_ID" -H "X-Appwrite-Key: API_KEY" -H "Content-Type: application/json" \ - -d '{ - "featureId": "requests", - "currency": "usd", - "interval": "month", - "includedUnits": 10000 - }' -``` - -4c. Tiered (graduated) pricing (note): - -- The current route accepts the documented fields: `featureId`, `currency`, `interval`, `includedUnits`. Type is inferred from the feature definition. -- Keys like `tiersMode`, `tiers`, `usageCap`, `overagePrice` are not read by the current implementation and will be ignored if sent. -- Below is a future-facing example body for reference only (not applied by current code): - -```bash -curl -X POST "$BASE/v1/payments/plans/pro/features" \ - -H "X-Appwrite-Project: PROJECT_ID" -H "X-Appwrite-Key: API_KEY" -H "Content-Type: application/json" \ - -d '{ - "featureId": "requests", - "type": "metered", - "currency": "usd", - "interval": "month", - "includedUnits": 10000, - "tiersMode": "graduated", - "tiers": [ - { "up_to": 10000, "unit_amount": 0 }, - { "up_to": 100000, "unit_amount": 10 }, - { "up_to": "inf", "unit_amount": 8 } - ], - "usageCap": null, - "overagePrice": null - }' -``` - -List plan features: - -```bash -curl -X GET "$BASE/v1/payments/plans/pro/features" \ - -H "X-Appwrite-Project: PROJECT_ID" -H "X-Appwrite-Key: API_KEY" -``` - -### 5) Create subscriptions - -5a. User subscription: - -```bash -curl -X POST "$BASE/v1/payments/subscriptions" \ - -H "X-Appwrite-Project: PROJECT_ID" -H "X-Appwrite-Key: API_KEY" -H "Content-Type: application/json" \ - -d '{ - "actorType": "user", - "actorId": "USER_ID", - "planId": "pro" - }' -``` - -5b. Team subscription (payer must be team member with owner/billing): - -```bash -curl -X POST "$BASE/v1/payments/subscriptions" \ - -H "X-Appwrite-Project: PROJECT_ID" -H "X-Appwrite-Key: API_KEY" -H "Content-Type: application/json" \ - -d '{ - "actorType": "team", - "actorId": "TEAM_ID", - "planId": "pro", - "payerUserId": "USER_ID" - }' -``` - -List subscriptions (optional filters): - -```bash -curl -X GET "$BASE/v1/payments/subscriptions?actorType=user&actorId=USER_ID" \ - -H "X-Appwrite-Project: PROJECT_ID" -H "X-Appwrite-Key: API_KEY" -``` - -Get subscription by ID: - -```bash -curl -X GET "$BASE/v1/payments/subscriptions/SUBSCRIPTION_ID" \ - -H "X-Appwrite-Project: PROJECT_ID" -H "X-Appwrite-Key: API_KEY" -``` - -### 6) Update, cancel, resume - -6a. Update plan (switch): - -```bash -curl -X PATCH "$BASE/v1/payments/subscriptions/SUBSCRIPTION_ID" \ - -H "X-Appwrite-Project: PROJECT_ID" -H "X-Appwrite-Key: API_KEY" -H "Content-Type: application/json" \ - -d '{ "planId": "pro" }' -``` - -6b. Cancel at period end (explicit cancel endpoint): - -```bash -curl -X POST "$BASE/v1/payments/subscriptions/SUBSCRIPTION_ID/cancel" \ - -H "X-Appwrite-Project: PROJECT_ID" -H "X-Appwrite-Key: API_KEY" -``` - -Alternative using PATCH (sets cancelAtPeriodEnd): - -```bash -curl -X PATCH "$BASE/v1/payments/subscriptions/SUBSCRIPTION_ID" \ - -H "X-Appwrite-Project: PROJECT_ID" -H "X-Appwrite-Key: API_KEY" -H "Content-Type: application/json" \ - -d '{ "cancelAtPeriodEnd": true }' -``` - -6c. Resume: - -```bash -curl -X POST "$BASE/v1/payments/subscriptions/SUBSCRIPTION_ID/resume" \ - -H "X-Appwrite-Project: PROJECT_ID" -H "X-Appwrite-Key: API_KEY" -``` - -### 7) Report usage (metered features) - -Emit usage events (e.g., requests): - -```bash -curl -X POST "$BASE/v1/payments/subscriptions/SUBSCRIPTION_ID/usage" \ - -H "X-Appwrite-Project: PROJECT_ID" -H "X-Appwrite-Key: API_KEY" -H "Content-Type: application/json" \ - -d '{ - "featureId": "requests", - "quantity": 2500 - }' -``` - -Get usage summary: - -```bash -curl -X GET "$BASE/v1/payments/subscriptions/SUBSCRIPTION_ID/usage" \ - -H "X-Appwrite-Project: PROJECT_ID" -H "X-Appwrite-Key: API_KEY" -``` - -List raw usage events: - -```bash -curl -X GET "$BASE/v1/payments/usage/events?subscriptionId=SUBSCRIPTION_ID&featureId=requests" \ - -H "X-Appwrite-Project: PROJECT_ID" -H "X-Appwrite-Key: API_KEY" -``` - -Reconcile (aggregate summary + optional provider sync): - -```bash -curl -X POST "$BASE/v1/payments/usage/reconcile" \ - -H "X-Appwrite-Project: PROJECT_ID" -H "X-Appwrite-Key: API_KEY" -``` - -### 7.1) Optional: Update plan and feature definitions - -Update plan metadata/pricing (only send fields you want to change): - -```bash -curl -X PUT "$BASE/v1/payments/plans/pro" \ - -H "X-Appwrite-Project: PROJECT_ID" -H "X-Appwrite-Key: API_KEY" -H "Content-Type: application/json" \ - -d '{ - "name": "Pro Updated", - "description": "Updated desc", - "isDefault": false, - "isFree": false, - "pricing": [ { "amount": 2499, "currency": "usd", "interval": "month" } ] - }' -``` - -Delete plan: - -```bash -curl -X DELETE "$BASE/v1/payments/plans/pro" \ - -H "X-Appwrite-Project: PROJECT_ID" -H "X-Appwrite-Key: API_KEY" -``` - -Update feature: - -```bash -curl -X PUT "$BASE/v1/payments/features/requests" \ - -H "X-Appwrite-Project: PROJECT_ID" -H "X-Appwrite-Key: API_KEY" -H "Content-Type: application/json" \ - -d '{ "name": "Requests (updated)", "description": "Updated" }' -``` - -Delete feature: - -```bash -curl -X DELETE "$BASE/v1/payments/features/requests" \ - -H "X-Appwrite-Project: PROJECT_ID" -H "X-Appwrite-Key: API_KEY" -``` - -### 8) Webhooks (Stripe) - -Endpoint: - -``` -POST $BASE/v1/payments/webhooks/stripe/PROJECT_ID -Headers: - Content-Type: application/json - Stripe-Signature: t=timestamp,v1=signature -Body: (Stripe event payload, e.g., customer.subscription.updated) -``` - -Example minimal payload (adjust to Stripe test fixtures): - -```bash -curl -X POST "$BASE/v1/payments/webhooks/stripe/PROJECT_ID" \ - -H "Content-Type: application/json" \ - -H "Stripe-Signature: t=1700000000,v1=REPLACE_WITH_VALID_SIGNATURE" \ - -d '{ - "type": "customer.subscription.updated", - "data": { "object": { "id": "sub_123", "status": "active", "current_period_start": 1700000000, "current_period_end": 1702592000 } } - }' -``` - -Note: Use the `webhookSecret` returned in providers state to compute a valid Stripe signature for real tests. - -### 9) Feature flag toggle (block writes when disabled) - -Disable payments and verify write routes return 403: - -```bash -curl -X PUT "$BASE/v1/payments/providers" \ - -H "X-Appwrite-Project: PROJECT_ID" -H "X-Appwrite-Key: API_KEY" -H "Content-Type: application/json" \ - -d '{ "enabled": false, "providers": {} }' -``` - -Then try, for example, creating a plan (should fail with 403): - -```bash -curl -X POST "$BASE/v1/payments/plans" \ - -H "X-Appwrite-Project: PROJECT_ID" -H "X-Appwrite-Key: API_KEY" -H "Content-Type: application/json" \ - -d '{ "planId": "test", "name": "Test", "pricing": [] }' -``` - -### 10) (Optional) Worker & scheduler - -- Start usage sync worker: `php app/worker.php payments-usage-sync` -- Periodic scheduler (enqueue usage sync for active projects): `php app/cli.php schedule-payments-usage`