Files
XQKqueue/server/README.md
brother7 78df07e074 实现叫号播报并调整现场业务规则
需求描述:发布屏在员工叫号后播放语音;同场次手机号被叫号后可重新取号;登录连续失败限制调整为10次。

实现思路:发布屏按新批次去重触发中文语音;重复手机号仅拦截WAITING号码;登录限流使用10次阈值,并补充前后端回归测试与接口说明。
2026-07-31 16:36:55 +08:00

3.8 KiB

Queue API

Go 1.26 modular-monolith API for the scenic queue system. It uses the standard library HTTP router, GORM, PostgreSQL, versioned embedded SQL migrations and database-backed sessions.

Local run

  1. Start PostgreSQL and create the database in DATABASE_URL.

  2. Copy .env.example to .env, replace both cryptographic keys, and export the variables. Keys must decode to exactly 32 random bytes.

  3. Run go run ./cmd/api. With MIGRATE_ON_START=true, embedded migrations run under a PostgreSQL advisory lock.

  4. Seed the local demo users, projects, queues, batches, devices and audit data with:

    ADMIN_PASSWORD='replace-me' go run ./cmd/seed
    

    The command is repeatable and prints the demo display and visitor paths. It resets only the DEMO, RAFT and CABLE projects. Default users are the protected xqkwljtadmin account and staff; override the staff credential and primary-project values with ADMIN_USERNAME, STAFF_USERNAME, ADMIN_PASSWORD, PROJECT_CODE and PROJECT_NAME.

For a production release, run go run ./cmd/migrate as a separate release Job with MIGRATE_ON_START=false, then rotate the protected administrator password with SUPER_ADMIN_PASSWORD='...' go run ./cmd/bootstrap-admin. Do not run the seed command against production.

POST /api/staff/projects/{id}/tickets and POST /api/staff/projects/{id}/call-next require an Idempotency-Key header. Ticket creation requires an immutable integer party_size inside the project's configured min_party_size / max_party_size range. A call-next request uses { "expected_revision": 12, "mode": "TICKET|PEOPLE", "count": 5 }. TICKET selects up to count consecutive FIFO tickets. PEOPLE selects the longest consecutive FIFO prefix whose total party size does not exceed count; it never splits or skips a ticket and rejects when the first ticket alone is larger than the requested target. Each mode has a separate project-level anti-mistouch maximum.

If a phone already has waiting tickets in the current queue session, ticket creation returns DUPLICATE_PHONE; repeat with the same request body except allow_duplicate: true and a new idempotency key after the employee confirms. Once the earlier ticket has been called, the same phone can take a new ticket without duplicate confirmation.

GET /api/public/projects returns projects currently open for visitor self-service, including each project's allowed party-size range. POST /api/public/projects/{id}/tickets uses the same ticket validation, queue locking and idempotency rules as the staff ticket flow, but returns only the public ticket projection and a private status token. Public ticket creation is rate-limited and audited as PUBLIC_TICKET_CREATED.

POST /api/public/status/search is a temporary non-production operational-test endpoint. It accepts { "phone": "..." } and returns all current active tickets associated with that phone. It is disabled when APP_ENV=production; replace it with OTP or an external identity interface before formal launch.

POST /api/internal/status/search exposes the same active-ticket lookup to trusted backend services in every environment. It accepts { "phone": "..." } and only allows direct peers on private or loopback networks. Do not publish this path through the public Ingress; callers must use the internal service address. Forwarded client-IP headers are intentionally ignored.

Tests

go test ./...
go vet ./...

From the repository root, make test-db creates a disposable PostgreSQL database and runs migration/maintenance integration tests.

Unit tests cover FIFO ticket/people selection, people-ahead ETA, phone normalization, authenticated encryption, token hashing and password hashing. PostgreSQL integration tests run through make test-db against a disposable database.