TP-Manager is built on a microservices architecture designed for horizontal scalability and independent deployment. Each domain concern — matching, reputation, transactions, notifications, analytics — runs as an isolated service with its own data store where appropriate.
Services communicate through a combination of synchronous REST calls for reads requiring immediate consistency and asynchronous event streaming via Redis pub/sub for eventual consistency workflows. WebSocket connections provide real-time updates to connected clients, ensuring counterparties see transaction state changes instantly.
Service Boundaries
- Matching Service — Maintains an in-memory index of active entries, executes the matching algorithm against incoming requests.
- Transaction Service — Manages the transaction lifecycle: creation, state transitions, escrow coordination, completion, and dispute initiation.
- Reputation Service — Consumes transaction completion and dispute events to recalculate participant scores asynchronously.
- Notification Service — Subscribes to transaction and matching events, dispatching real-time WebSocket updates.
- Analytics Service — Aggregates event streams into time-series data for the operator dashboard.
Matching Algorithm
The matching engine evaluates compatibility using a weighted multi-factor scoring model. Factors include geographic proximity, historical reliability, response time patterns, and transaction parameter alignment.
Two-phase approach: candidate selection applies hard filters to reduce the search space, then ranking scores remaining candidates using a weighted composite score with tunable weights per deployment.
Reputation Engine
Decay-weighted scoring model where recent transactions carry more weight than older ones. Incorporates completion rate, dispute frequency, counterparty feedback, and response time consistency. Sybil detection heuristics flag rapid reputation accumulation from a small set of counterparties.
// Multi-factor matching — candidate scoring
function scoreCandidate(
candidate: MatchCandidate,
request: MatchRequest,
weights: MatchWeights
): number {
const paramScore = computeParameterAlignment(
candidate.parameters,
request.parameters
);
const proxScore = 1 - normalize(
haversineDistance(candidate.location, request.location),
0,
request.maxDistance
);
const repScore = normalize(candidate.reputationScore, 0, 100);
const respScore = 1 - normalize(
candidate.avgResponseTime,
0,
3600
);
return (
paramScore * weights.parameterAlignment +
proxScore * weights.proximity +
repScore * weights.reputation +
respScore * weights.responsiveness
);
}