Core Systems Introduction — Payment Flow, UFS, UES, Redis
Use case: Internal team systems introduction / New hire onboarding
Suggested duration: 30–60 minutes
Document source: Pay Core Workspace - Microservices
Table of Contents
1. System Overview
📖 References: Microservices main doc | Core Systems Brief Introduction
Focus of this session: Payment Core payment flow + the three Basic infrastructure components UES / UFS / Redis.
2. Payment Flow (Focus)
📖 References:
The complete APP payment main flow consists of 5 stages:
2.1 Stage Description
| Stage | Description | Main Applications | Main Tables |
|---|---|---|---|
| 1. Create Order & Get Token | Business places order + token-order binding cached in Redis | tradeii, cashdesk | Business order table, tradeii.t_trade_order |
| 2. Invoke Cashier & Auth | Look up order by token + query user's supported payment methods | cashdesk, authpay, member, pbs, grc | cashdesk.t_group / t_filter_scheme / t_filter_node |
| 3. Select Payment Method & Risk Verification | Risk scoring + match verification rules (password/3DS) | grc, aml | aml.t_identity_decision, aml.t_identity_rule |
| 4. Initiate Payment | Fee calculation + channel routing + channel request + dpm debit/credit | tradeii, pbs, pfs, payment, cmf, router, dpm, grc | tradeii.t_trade_order / t_pay_order, cmf.tt_inst_order, router.t_channel* |
| 5. Trigger Settlement | Money moves from pending settlement account → business's actual receiving account | tradeii, pfs, payment | dpm account tables |
2.2 Key Concept Distinctions
Payment ≠ Settlement
- Payment: User's money enters the "pending settlement account"
- Settlement: Transfer from pending settlement account into the business's actual receiving account
- Settlement trigger modes: auto-settlement / periodic settlement / manual settlement
2.3 Channel Routing Diagram
Routing rule dimensions: verification method, card institution, order amount, merchant number, payer member number, priority.
3. UFS — Unified File Service
📖 References:
3.1 Positioning
UFS (Unified File Service) = unified wrapper for file storage/sharing.
- Underlying layer wraps Alibaba Cloud OSS / Azure Blob
- Design goal: shield differences between underlying cloud vendors, enabling easy future cloud migration
- Current implementation is Proxy mode: all upload/download traffic except download URLs flows through the UFS Server
- New applications uniformly integrate with ufs2 (legacy APIs are kept only for compatibility)
3.2 Architecture
3.3 Two Authorization Modes
| Mode | Use Case | Authorization Required | Path Prefix |
|---|---|---|---|
| Standalone Bucket | Dedicated storage, high data security requirements | UFS user authorization (Basic Auth) | /ufs2/standalone |
| Shared Bucket | Lower data security requirements, accessible by other internal systems | No UFS user authorization | /ufs2/share |
3.4 Standalone Bucket Application Process
Application key points:
- sim bucket names end with
test, prod bucket names end withprod - sim and uat share the same bucket
- UFS Manager: shangkai.shi (backups: yongxing.cao, cong.zhou)
3.5 Integration Methods
Four types of API are provided:
- Java Client (recommended):
ufs-Standalone bucket-java Client/ufs-Share bucket-java Client - HTTP API (cross-language):
ufs-Standalone bucket-http API/ufs-Share bucket-http API
Environment URLs (HTTP):
| Environment | URL |
|---|---|
| sim | https://sim-api-intra.test2pay.com/ufs2 |
| uat | https://uat.intra.test2pay.com/ufs2 |
| prod | https://intra.payby.com/ufs2 |
3.6 HTTP API - Standalone Bucket
📖 ufs-Standalone bucket-http API
Common request headers:
| Header | Required | Description |
|---|---|---|
Authorization | ✅ | Basic Auth credentials, allocated per application |
x-ufs-client-id | ✅ | Client ID, e.g. gp024_cgs |
x-ufs-bucket-alias | ❌ | Specify bucket alias; if omitted, the default bucket configured in db is used |
3.6.1 Upload File (PUT)
PUT {url}/standalone/file/{ossPath}
Optional request headers:
x-ufs-forbid-overwrite: Forbid overwriting same-name file (default allows overwrite)x-ufs-encrypt: Encrypt on UFS side (default not encrypted)x-ufs-meta-*: Custom metadata (e.g.x-ufs-meta-check-sum, only a-z and-)
curl -v --request PUT \
'https://sim-api-intra.test2pay.com/ufs2/standalone/file/demo/helloworld.txt' \
--header 'x-ufs-client-id: demo' \
--header 'Authorization: Basic dWZzX3VuaXR0ZXN0OnVmc191bml0dGVzdA==' \
--form 'file=@/Users/cong.zhou/temp/hello.txt'
# < HTTP/1.1 2003.6.2 Download File (GET)
GET {url}/standalone/file/{ossPath}
Response header x-ufs-meta-* returns the metadata set during upload.
curl -v --request GET \
'https://sim-api-intra.test2pay.com/ufs2/standalone/file/demo/helloworld.txt' \
--header 'x-ufs-client-id: demo' \
--header 'Authorization: Basic dWZzX3VuaXR0ZXN0OnVmc191bml0dGVzdA=='
# < HTTP/1.1 200
# < Content-Type: application/octet-stream;charset=UTF-8
# < Content-Disposition: attachment; filename="helloworld.txt"3.6.3 Get Temporary Authorized Download URL (STS)
GET {url}/standalone/fileUrl/{ossPath}
Optional request headers:
x-ufs-expire-seconds: Link validity period (seconds, default 5 minutes)x-ufs-public-access: true returns OSS signed external URL; false returns UFS STS intranet URL (default)
curl -v --request GET \
'https://sim-api-intra.test2pay.com/ufs2/standalone/fileUrl/demo/helloworld.txt' \
--header 'x-ufs-client-id: demo' \
--header 'Authorization: Basic dWZzX3VuaXR0ZXN0OnVmc191bml0dGVzdA=='
# Response:
# {"url":"https://.../ufs2/sts/file/b37e2707...","stsToken":"b37e2707..."}3.6.4 Copy File (POST)
POST {url}/standalone/copyFile
Request headers specify source and target: x-ufs-from-bucket-alias / x-ufs-from-oss-path / x-ufs-to-bucket-alias / x-ufs-to-oss-path
3.6.5 Copy Shared File to Own Bucket (POST)
POST {url}/standalone/copyShareFile/
Copies a file from the Share Bucket (identified by fileTag) into the standalone bucket.
curl -v --request POST \
'https://sim-api-intra.test2pay.com/ufs2/standalone/copyShareFile/' \
--header 'x-ufs-client-id: demo' \
--header 'Authorization: Basic dWZzX3VuaXR0ZXN0OnVmc191bml0dGVzdA==' \
--header 'x-ufs-from-file-tag: ce0a58c2...' \
--header 'x-ufs-to-oss-path: demo/ce0a58c2...' \
--header 'x-ufs-copy-suffix: true'
# Response: {"ossPath":"demo/ce0a58c2....txt"}3.7 HTTP API - Share Bucket
📖 ufs-Share bucket-http API
Share Bucket does not require Authorization, only x-ufs-client-id. The returned fileTag is the file's unique ID.
3.7.1 Upload File (PUT)
PUT {url}/share/file
Optional request headers:
x-ufs-expire-seconds: File expiration time; file is inaccessible after expiration (default no expiration)x-ufs-encrypt: Encrypt on UFS sidex-ufs-meta-*: Custom metadata
curl -v --request PUT \
'http://sim-api-intra.test2pay.com/ufs2/share/file' \
--header 'x-ufs-client-id: demo' \
--form 'file=@/Users/cong.zhou/temp/hello.txt'
# Response: {"fileTag":"0abe2b6a57c5463cb5837c523d8fa601"}3.7.2 Download File (GET)
GET {url}/share/file/{fileTag}
curl -v --request GET \
'http://sim-api-intra.test2pay.com/ufs2/share/file/0abe2b6a...' \
--header 'x-ufs-client-id: demo'3.7.3 Get File Metadata (GET)
GET {url}/share/fileMeta/{fileTag}
Returns the x-ufs-meta-* data from response headers.
3.7.4 Adopt File (PATCH)
PATCH {url}/share/adopt/{fileTag}
Convert a temporary file into a permanent file (prevents cleanup on expiration).
curl -v --request PATCH \
'http://sim-api-intra.test2pay.com/ufs2/share/adopt/83a151bb...' \
--header 'x-ufs-client-id: demo'3.7.5 Get Temporary Authorized Download URL (GET)
GET {url}/share/fileUrl/{fileTag}
Parameters same as Standalone mode. If x-ufs-public-access=true, must be called by the application that uploaded or adopted the file.
3.8 Return Codes
| HTTP | JAVA Return Code | Description |
|---|---|---|
| 200 | - | Operation succeeded |
| 400 | INVALID_PARAMETER | Parameter error |
| 401 | UNAUTHORIZED | Unauthorized |
| 404 | NOT_EXIST | Not exist |
| 409 | CONFLICT | Operation not allowed (e.g. file already exists when overwrite is forbidden) |
| 410 | EXPIRED | Expired |
| Other | SYSTEM_ERROR | System error |
4. UES — Unified Encryption/Decryption Service
📖 References:
- ues(Unified encryption and decryption service)
- Credit UES API Documentation (HTTP API reference)
4.1 Positioning
UES (Unified Encryption/Decryption Service) = unified handling of sensitive field encryption/decryption.
- Client dependency:
com.uaepay.basis.ues:ues-client, current version2.3.4 - Business database stores only tickets, not plaintext; use ticket to decrypt when needed
- Maintainer: Cao Yongxing
4.2 Core Concept: Ticket
4.3 Ticket Type Comparison
| Type | Prefix | Storage | TTL | Typical Use Case |
|---|---|---|---|---|
| Temporary Ticket | C | Memory (Redis) | Seconds to minutes | Sensitive data transfer within one session |
| Persistent Ticket | P | DB / MongoDB | Long-term | Sensitive fields persisted long-term by business |
| Persistent + Digest | P...-xxx | DB | Long-term | Fields requiring verification/statistics |
| Large Field Persistent | P | MongoDB | Long-term | ≤ 5,000,000 characters, GZIP compression supported |
4.4 Main Capabilities
- Temporary ticket / persistent ticket / persistent ticket with digest
- Large field persistent ticket (≤ 5,000,000 characters, stored in MongoDB; MySQL sharding)
- Temporary ticket → persistent ticket conversion (data_type can be changed)
- Look up ticket by plaintext (
queryTicket) - Batch encryption (
saveDatas)
4.5 Supported data_type (Partial)
| data_type | Regex | Description | ||
|---|---|---|---|---|
name | ^.{1,100}$ | Name | ||
password | ^.{2,100}$ | Password, secret key | ||
mobile_no | `^(+\ | \d\ | -){2,20}$` | Mobile number |
email | ^.{5,30}@.{2,30}$ | |||
card_no | ^.{2,50}$ | Card number | ||
cvv2 | ^.+$ | CVV2 | ||
iban | ^.{5,40}$ | IBAN | ||
address | ^.{1,500}$ | Address | ||
passport | ^.+$ | Passport | ||
id | ^.+$ | ID card |
4.6 Key Version Evolution
4.7 Java Integration Example
<!-- pom.xml -->
<dependency>
<groupId>com.uaepay.basis.ues</groupId>
<artifactId>ues-client</artifactId>
<version>2.3.4</version>
</dependency>@Autowired
UesClientV2 uesClient;
// Persistent ticket encryption
EncryptContextV2 context = new EncryptContextV2(plain, "card_no");
uesClient.saveData(context);
String ticket = context.getTicket(); // Business DB stores this ticket
// Decryption
context = new EncryptContextV2();
context.setTicket(ticket);
uesClient.getDataByTicket(context);
String plainData = context.getPlainData();4.8 HTTP API Access
📖 Credit UES API Documentation
UES primarily recommends Java Client integration, but internal HTTP endpoints are also provided (using Credit UES as an example; the inner API design is identical for other modules).
External HTTP APIs are generally exposed through CGS (Client Gateway Service):
- Internal call path:
/bapi/... - Public API path:
/api/... - Gateway can automatically handle UES tokens via
encrypt/responseEncryptextensions
Base Path: /credit-ues/inner
Content-Type: application/json
4.8.1 Single Encryption
POST /inner/encrypt
{
"plainData": "sensitive-data",
"dataType": "USER_INFO",
"summary": "User personal information"
}Response:
{
"success": true,
"data": "ticket-string",
"message": null
}curl -X POST http://localhost:8080/credit-ues/inner/encrypt \
-H "Content-Type: application/json" \
-d '{"plainData":"sensitive-data","dataType":"USER_INFO","summary":"User info"}'4.8.2 Batch Encryption
POST /inner/batchEncrypt
[
{"plainData":"d1","dataType":"USER_INFO","summary":"s1"},
{"plainData":"d2","dataType":"USER_INFO","summary":"s2"}
]Response: data array maps one-to-one with the request; failed entries are null.
{ "success": true, "data": ["ticket1", "ticket2", null], "message": null }4.8.3 Single Decryption
POST /inner/decrypt
{ "ticket": "ticket-string" }Response:
{ "success": true, "data": "decrypted-plain-text", "message": null }Error example:
{ "success": false, "data": null, "message": "ticket not exist in database." }4.8.4 Batch Decryption
POST /inner/batchDecrypt
{ "tickets": ["ticket1", "ticket2", "ticket3"] }Response: returns Map<ticket, plain>, including only valid tickets.
{
"success": true,
"data": {
"ticket1": "decrypted-data-1",
"ticket2": "decrypted-data-2"
}
}4.8.5 Encryption/Decryption with Redis Cache
| Endpoint | Description |
|---|---|
POST /inner/encryptWithCache | Encrypt and write plaintext to Redis cache at the same time |
POST /inner/batchEncryptWithCache | Batch encryption with cache |
POST /inner/decryptWithCache | On decryption, check Redis first; on miss, fall back to DB and backfill cache |
POST /inner/batchDecryptWithCache | Batch decryption with cache, significantly reduces latency for bulk data |
Usage recommendations:
- Frequently read, latency-sensitive data → use
*WithCache - One-off, strong consistency, write-heavy / read-light → use standard API
4.8.6 Security Model
Encryption: random AES Key encrypts data → RSA public key encrypts AES Key → both stored → ticket generated
Decryption: ticket queries DB → RSA private key restores AES Key → AES decrypts plaintext → GZIP decompress if needed
4.8.7 Common Errors
| Error Message | Cause | Handling |
|---|---|---|
ticket not exist in database | Invalid or expired ticket | Check ticket source |
Invalid certification certSerialNo | Certificate not found | Verify certificate configuration |
Exception: ... | System exception | Check logs |
4.8.8 Best Practices
- Prefer batch APIs to reduce network overhead
- Use
*WithCachefor frequently accessed data - Check for null in batch responses (partial failures appear as null)
- Use consistent
dataTypefor the same kind of field for easier data governance - Always check the
successfield before consumingdata
5. Redis — redis-starter & Cluster Solution
📖 Reference: redis-starter
5.1 Positioning
- Internally, Redis is uniformly accessed via
com.uaepay.starter:redis-starter - Encapsulates Spring Cache, RedisTemplate, Redisson distributed lock
- Maintainers: Cong Zhou / Yongxing Cao
5.2 Integration Architecture
5.3 Two Version Lines
1.2.x:
- 1.2.18 switched to Lettuce + Cluster support
- 1.2.19 topology auto-refresh
- 1.2.22 scan interval configurable
- 1.2.26-SNAPSHOT exposes Redisson configuration
1.3.x:
- 1.3.6-SNAPSHOT back-ports 1.2.22 + 1.2.26 enhancements
5.4 Deployment & Integration Methods
| Method | Configuration | Status |
|---|---|---|
| Cluster Redis | spring.redis.cluster.nodes | ✅ Recommended |
| Db Index | spring.redis.database | ❌ Deprecated |
When Cluster and Db Index are both configured, only Cluster takes effect.
5.5 Key Configuration
spring:
application:
name: redis-starter # Required, used as key prefix
redis:
password: ******
timeout: 15s
expireDefault: 10m
clusterScanInterval: 1m
cluster:
max-redirects: 6
nodes: redis-cluster.sim.test2pay.com:6379
lettuce:
pool:
max-idle: 5
min-idle: 5
max-active: 20
max-wait: 10s
redisson:
ping-connection-interval: 1m
check-lock-synced-slaves: true5.6 Usage
Annotation-based caching:
@Service
public class SampleUserService {
public static final String CACHE_NAME = "SAMPLE_USER_BY_ID";
@Cacheable(value = CACHE_NAME)
public User getUserById(long id) { /* ... */ }
@CacheEvict(value = CACHE_NAME)
public void flushUserById(long id) {}
}Key rule: keys are automatically prefixed with the application name:
redis-starter:SAMPLE_USER_BY_ID:2971133547753664512API calls:
@Resource
private RedisTemplate<String, Object> redisTemplate;
@Resource
private RedisService<String, Object> redisService;⚠️ Do not inject RedisTemplate<String, String> — it pulls in the default StringRedisTemplate and loses the application-name prefix.Distributed lock:
@Autowired
RedissonClient redissonClient;
public void demo() {
RLock lock = redissonClient.getSpinLock("lock-key");
if (!lock.tryLock()) return;
try {
// Default 120s auto-renewal
} finally {
lock.unlock();
}
}5.7 Usage in Payment Chain
- Cashier token ↔ order number binding cache
- Business-level caching (auth / product config / risk rules)
- Distributed locks (prevent duplicate payment / concurrent settlement)
- UES Temporary Ticket (in-memory sensitive data)
- Plaintext cache for UES
*WithCacheendpoints
5.8 Evolution Direction
- Migrate the legacy G42Cloud cluster to Azure (Redis Cluster supported)
- See Sunset Legacy Redis and Guide for upgrading to cluster Redis
6. Summary
| Module | Key Points |
|---|---|
| Payment Flow | 5 stages, payment ≠ settlement |
| UFS | Proxy mode; two bucket types; Java Client + HTTP API |
| UES | Ticket (C/P); Java Client + HTTP /inner/* |
| Redis | redis-starter; Cluster recommended |
7. Reference Documents
7.1 Microservices Overview
| Document | Link |
|---|---|
| Microservices main doc | https://algento.atlassian.net/wiki/spaces/PCW/pages/1423376385/Microservices |
| Core Systems Brief Introduction | https://algento.atlassian.net/wiki/spaces/tester/pages/124289174 |
7.2 Payment Flow Related
| Document | Link |
|---|---|
| APP Payment Main Flow | https://algento.atlassian.net/wiki/spaces/AQ/pages/1268547602/APP |
| 21-pfs-Pre-payment | https://algento.atlassian.net/wiki/spaces/PCW/pages/124554323/21-pfs- |
| 22-payment-Payment Engine | https://algento.atlassian.net/wiki/spaces/PCW/pages/124554288/22-payment- |
| Payment Core | https://algento.atlassian.net/wiki/spaces/PCW/pages/1439596574/Payment+Core |
7.3 UFS Related
| Document | Link |
|---|---|
| ufs (Unified File Service) | https://algento.atlassian.net/wiki/spaces/PMDPayment/pages/124556361/ufs |
| ufs-Unified File Service | https://algento.atlassian.net/wiki/spaces/PCW/pages/124556038/ufs-Unified+File+Service |
| ufs-2-Proxy Mode - Integration Guide | https://algento.atlassian.net/wiki/spaces/PCW/pages/124556040/ufs-2-Proxy+Mode+-+Integration+Guide |
| ufs-Standalone bucket-http API | https://algento.atlassian.net/wiki/spaces/PCW/pages/124556560/ufs-Standalone+bucket-http+API |
| ufs-Share bucket-http API | https://algento.atlassian.net/wiki/spaces/PCW/pages/124556480/ufs-Share+bucket-http+API |
7.4 UES Related
| Document | Link |
|---|---|
| ues (Unified encryption and decryption service) | https://algento.atlassian.net/wiki/spaces/PCW/pages/124555323/ues+Unified+encryption+and+decryption+service |
| Credit UES API Documentation (HTTP API reference) | https://algento.atlassian.net/wiki/spaces/QT/pages/1671233596/Credit+UES+API+Documentation |
7.5 Redis Related
| Document | Link |
|---|---|
| redis-starter | https://algento.atlassian.net/wiki/spaces/PCW/pages/124555370/redis-starter |
Document compiled from Pay Core Workspace Confluence documents
Generated: 2026-05-24