3.4 KiB
3.4 KiB
OpenSpec Change: enterprise-gaming-api-plugin-matchmaking
- Change ID: enterprise-gaming-api-plugin-matchmaking
- Package:
@suaveplan/api-plugin-matchmaking - Category: gaming/server
- Target path:
gaming/server/api-plugin-matchmaking - Status: PROPOSED
- Date: 2026-04-24
- Reference spec:
/mnt/s/web/suaveplan/enterprise/api-plugin-matchmaking.md
Summary
Deliver @suaveplan/api-plugin-matchmaking on the genesis branch from scratch at enterprise quality. The package wraps a MatchmakingQueue in a Hono HTTP plugin. The queue accepts skill-rated players, sorts by rating, and builds balanced teams using alternating-rank assignment with a configurable skill gap that widens over wait time. HTTP routes expose enqueue, dequeue, status, and queue stats. Genesis adds Zod player schemas, structured errors, OTel queue-depth gauge, injectable clock, and 100% coverage.
Current-state audit (genesis)
Package does not exist on genesis yet — fresh build.
Available workspace deps on genesis
| Package | Role |
|---|---|
@suaveplan/error (workspace:^) |
MatchmakingError; MM.* codes |
@suaveplan/types (workspace:^) |
Clock |
@suaveplan/events (workspace:^) |
mm:enqueued, mm:match_found, mm:dequeued events |
zod (catalog:forms) |
QueuedPlayer, MatchResult schemas |
@opentelemetry/api (catalog:observability) |
Queue depth gauge, match counter |
HTTP Routes
| Method | Path | Description |
|---|---|---|
POST |
/queue |
Enqueue player |
DELETE |
/queue/:playerId |
Dequeue player |
GET |
/queue/:playerId/status |
Queue position |
POST |
/queue/tick |
Advance matchmaking (server-side tick) |
GET |
/queue/stats |
Queue depth, avg wait time |
Core logic
interface QueuedPlayer {
playerId: string
displayName: string
skillRating: number
gameMode: string
enqueuedAt: number
}
interface MatchResult {
matchId: string
team1: QueuedPlayer[]
team2: QueuedPlayer[]
avgSkillGap: number
createdAt: number
}
function createMatchmakingQueue(options: MatchmakingOptions): MatchmakingQueue
interface MatchmakingOptions {
teamSize?: number // players per team, default 5
baseSkillGap?: number // initial acceptable gap, default 200
expandGapPerSecond?: number // gap expansion rate, default 10/sec
clock?: Clock
}
interface MatchmakingQueue {
enqueue(player: QueuedPlayer): void
dequeue(playerId: string): void
findMatches(now: number): MatchResult[]
getStatus(playerId: string): QueueStatus | undefined
getStats(): QueueStats
}
Error codes
type MatchmakingErrorCode =
| 'MM_PLAYER_NOT_FOUND'
| 'MM_ALREADY_QUEUED'
| 'MM_INVALID_GAME_MODE'
| 'MM_QUEUE_FULL'
File layout
gaming/server/api-plugin-matchmaking/
package.json
tsconfig.json
vitest.config.ts
src/
index.ts
error-codes.ts
types/common.ts
types/common.md
core/
matchmaking-queue/
matchmaking-queue.ts
matchmaking-queue.md
matchmaking-queue.types.ts
matchmaking-queue.test.ts
index.ts
routes/
queue.ts
queue.md
plugin.ts
plugin.md
tests/
integration.test.ts
Impact
Downstream: @suaveplan/api-plugin-game-server creates sessions for matched groups. Prerequisites: @suaveplan/error, @suaveplan/types, @suaveplan/events.