Files
XQKqueue/server
brother7 3f4a9bf398 统一单项目大屏与管理端全屏布局
需求:/display/{项目编码} 参照管理端项目大屏布局展示。

实现:抽取共享大屏组件,补充公开累计取号与最新号码字段,并完善桌面及窄屏适配。

验证:前端61项测试、TypeScript、Vite构建以及Go测试、vet、build均通过。
2026-07-31 18:43:10 +08:00
..
2026-07-12 15:53:24 +08:00
2026-07-12 15:53:24 +08:00
2026-07-14 19:15:13 +08:00
2026-07-12 15:53:24 +08:00
2026-07-12 15:53:24 +08:00

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.