Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
20 changes: 20 additions & 0 deletions apps/dummy-payment/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Local development variables. When developped locally with Saleor inside docker, these can be set to:
#
# APP_IFRAME_BASE_URL = http://localhost:3000, so Dashboard on host can access iframe
# APP_API_BASE_URL=http://host.docker.internal:3000 - so Saleor can reach App running on host, from the container.
#
# If developped with tunnels, set this empty, it will fallback to address the app is reached from (default port 3000).
APP_IFRAME_BASE_URL=
APP_API_BASE_URL=


# Dynamodb apl

AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_REGION=
DYNAMODB_MAIN_TABLE_NAME=

# optional
# DYNAMODB_MAIN_TABLE_TIMEOUT_MS=
# DYNAMODB_MAIN_TABLE_CONNECTION_TIMEOUT_MS=
3 changes: 3 additions & 0 deletions apps/dummy-payment/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": ["next", "prettier"]
}
1 change: 1 addition & 0 deletions apps/dummy-payment/.gitallowed
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
AGENTS.md
48 changes: 48 additions & 0 deletions apps/dummy-payment/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# local env files
.env*.local
.envfile
.saleor-app-auth.json

# vercel
.vercel

# typescript
*.tsbuildinfo

.auth_token

#editor
.vscode
.idea

# Sentry
.sentryclirc

.env
20 changes: 20 additions & 0 deletions apps/dummy-payment/.graphqlrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
schema: graphql/schema.graphql
documents: [graphql/**/*.graphql, src/**/*.ts, src/**/*.tsx]
extensions:
codegen:
overwrite: true
generates:
generated/graphql.ts:
config:
dedupeFragments: true
plugins:
- typescript
- typescript-operations
- urql-introspection
- typescript-urql:
documentVariablePrefix: "Untyped"
fragmentVariablePrefix: "Untyped"
- typed-document-node
generated/schema.graphql:
plugins:
- schema-ast
3 changes: 3 additions & 0 deletions apps/dummy-payment/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
strict-peer-dependencies=false
auto-install-peers=true
save-exact=true
5 changes: 5 additions & 0 deletions apps/dummy-payment/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.next
saleor/api.tsx
pnpm-lock.yaml
graphql/schema.graphql
generated
4 changes: 4 additions & 0 deletions apps/dummy-payment/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"singleQuote": false,
"printWidth": 100
}
148 changes: 148 additions & 0 deletions apps/dummy-payment/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
# Saleor Dummy Payment App

This file provides guidance to coding agents when working with code in this repository.

## Project Overview

This is a Saleor Payment App that implements a dummy payment gateway for testing Saleor's Transactions API. It allows testing payment flows without a real payment provider.

## Development Commands

### Setup
```bash
pnpm install # Install dependencies
```

### Development
```bash
pnpm dev # Start dev server with codegen and Node.js inspector on port 3000
pnpm build # Build for production (runs codegen first)
pnpm start # Start production server
```

### Code Quality
```bash
pnpm lint # Run ESLint
pnpm test # Run tests with Vitest
```

### GraphQL
```bash
pnpm generate # Generate TypeScript types from GraphQL schema and operations
pnpm fetch-schema # Fetch latest Saleor GraphQL schema (version in package.json)
```

GraphQL operations are defined in `graphql/` directory (mutations, queries, fragments, subscriptions). The codegen generates types in `generated/graphql.ts` using urql and typed-document-node.

## Architecture

### Framework & Stack
- **Next.js** with Pages Router (not App Router)
- **tRPC** for type-safe API routes (server & client communication)
- **urql** for GraphQL client with auth exchange
- **Saleor App SDK** for webhook handling and APL (Auth Persistence Layer)
- **Vitest** for testing with jsdom environment
- **OpenTelemetry** for observability (traces & logs)
- **Sentry** for error tracking

### Key Architectural Components

#### APL (Auth Persistence Layer)
Authentication data storage configured in `src/saleor-app.ts`. Supports:
- `FileAPL` (default) - stores auth in `.auth-data.json`
- `UpstashAPL` - for multi-tenant deployments
- `SaleorCloudAPL` - for Saleor Cloud deployments

#### Webhook System
All webhooks are in `src/pages/api/webhooks/`. Each webhook:
- Uses `SaleorSyncWebhook` from `@saleor/app-sdk`
- Wrapped with `wrapWithLoggerContext` and `withOtel` for observability
- Has `bodyParser: false` in config for signature verification
- Validates incoming data with Zod schemas from `src/modules/validation/`

Supported webhooks:
- `PAYMENT_GATEWAY_INITIALIZE_SESSION`
- `TRANSACTION_INITIALIZE_SESSION`
- `TRANSACTION_PROCESS_SESSION`
- `TRANSACTION_REFUND_REQUESTED`
- `TRANSACTION_CHARGE_REQUESTED`
- `TRANSACTION_CANCELATION_REQUESTED`

Check warning on line 69 in apps/dummy-payment/AGENTS.md

View workflow job for this annotation

GitHub Actions / spellcheck

Unknown word (CANCELATION)

#### tRPC Setup
- Server router in `src/server/routers/app-router.ts`
- Context defined in `src/pages/api/trpc/[trpc].ts`
- Client setup in `src/trpc-client.ts`
- Procedures can use `procedureWithGraphqlClient` middleware for Saleor API access

#### GraphQL Client
Created via `createClient` in `src/lib/create-graphql-client.ts`:
- Uses urql with auth exchange
- Custom `Authorization-Bearer` header (note: not standard `Authorization: Bearer`)
- Auth token provided via APL

#### URL Generation
`AppUrlGenerator` in `src/modules/url/app-url-generator.ts` handles:
- External URLs for webhooks (`APP_API_BASE_URL` env var)
- Iframe URLs for dashboard (`APP_IFRAME_BASE_URL` env var)
- Falls back to request host if env vars not set
- Env vars are used for local development with local Saleor instance, tunneling works without setting env vars

#### Transaction Logic
- `transaction-actions.ts` - determines available actions based on event type
- `transaction-psp-finder.ts` - finds PSP reference from transaction events
- `transaction-refund-checker.ts` - validates refund requests
- Response schema validation in `src/modules/validation/sync-transaction.ts`

#### Observability
- Logger with multiple transports (console, Sentry, Vercel) in `src/lib/logger/`
- OpenTelemetry setup in `src/lib/otel/` with traces and logs
- Request context propagation via `logger-context.ts`

### Pages Structure
- `/` - Landing page
- `/app/` - Dashboard pages (must be opened in Saleor Dashboard iframe context):
- `/app/index.tsx` - Main app page
- `/app/configuration.tsx` - App configuration
- `/app/checkout.tsx` - Checkout testing UI
- `/app/transactions/` - Transaction list and details

### Environment Variables
Optional for local development (defaults work without Docker):
- `APP_IFRAME_BASE_URL` - Base URL for iframe (e.g., `http://localhost:3000`)
- `APP_API_BASE_URL` - Base URL for webhooks (e.g., `http://host.docker.internal:3000` for Docker)
- `APL` - Auth persistence layer type: `file` (default), `upstash`, `saleor-cloud`
- APL-specific vars: `FILE_APL_PATH`, `UPSTASH_URL`, `UPSTASH_TOKEN`, `REST_APL_TOKEN`, `REST_APL_ENDPOINT`

## Testing Payment Flows

The app accepts `data` field in `transactionInitialize` and `transactionProcess` mutations to control behavior:

```json
{
"data": {
"event": {
"type": "CHARGE_SUCCESS", // See TransactionEventTypeEnum
"includePspReference": true
}
}
}
```

Valid event types: `CHARGE_SUCCESS`, `CHARGE_FAILURE`, `CHARGE_REQUEST`, `CHARGE_ACTION_REQUIRED`, `AUTHORIZATION_SUCCESS`, `AUTHORIZATION_FAILURE`, `AUTHORIZATION_REQUEST`, `AUTHORIZATION_ACTION_REQUIRED`

Response includes:
- `pspReference` - UUID v7 (if `includePspReference: true`)
- `result` - mirrors the input `type`
- `actions` - available transaction actions (determined by event type)
- `externalUrl` - link to transaction details page in app
- `message` - success or error message

For more details check Saleor GraphQL schema and docs: docs.saleor.io

## Important Notes

- All webhook handlers must have `bodyParser: false` for signature verification
- GraphQL schema version is pinned to Saleor 3.19 (see `package.json`)
- Node version: 18.17.0 - 20.x required
- Uses ES modules (`"type": "module"` in package.json)
- Transaction external URLs link back to app UI for status updates
Loading
Loading