Skip to content

feat(tickets): add ticket lookup, QR image and rotating QR tokens - #460

Merged
EmmanuelOchaje merged 1 commit into
StellarTickets:mainfrom
c4182657-ship-it:feat/131-129-125-121-ticket-qr-verify
Oct 18, 2026
Merged

EmmanuelOchaje merged 1 commit into
StellarTickets:mainfrom
c4182657-ship-it:feat/131-129-125-121-ticket-qr-verify

Conversation

@c4182657-ship-it

Copy link
Copy Markdown
Contributor

Summary

Adds the ticket lookup, QR image and rotating QR token endpoints from #121, #125 and #129, and a route-level test for the verify rate limit from #131.

Changes

#121 — GET /tickets/:ticketId

  • Returns the ticket (with event, organization and ticketType) to its owner or to members of the event's organization; anyone else gets 403, an unknown id 404.
  • Staff do not receive the ticket's qrSecret; the owner does.
  • Declared after the static routes (mine, resale, offline-public-keys, by-chain/:id), which a test confirms it does not shadow.

#125 — GET /tickets/:ticketId/qr

  • Returns a 512px PNG (Content-Type: image/png, Cache-Control: no-store) encoding the ticket's qrSecret. Owner only: a non-owner, including organization staff, gets 403.
  • Adds the qrcode dependency (@types/qrcode as a dev dependency); the lockfile change is limited to it and its transitive packages.
  • The route writes the response directly with @Res(), because the global BigIntSerializerInterceptor would flatten a returned Buffer into a plain object.

#129 — rotating QR tokens

  • New QrTokenService. GET /tickets/:ticketId/qr-token (owner only, no-store) issues v1.<ticketId>.<exp>.<signature>, an HMAC-SHA256 token whose key is derived from the existing JWT signing secret for this purpose only. It is deliberately not a JWT, so it can never be used as a bearer credential. No new secret is required.
  • GET /tickets/verify/:value now accepts either a static qrSecret or one of these tokens. An expired token is rejected with 400; a forged or malformed one is 404, like an unknown secret.
  • QR_TOKEN_TTL_SECONDS (default 30) and QR_TOKEN_CLOCK_SKEW_SECONDS (default 5, the configurable tolerance) are added to .env.example, the env-docs generator and docs/CONFIGURATION.md.
  • This is additive: existing static QR codes and scanners keep working, so a screenshot of the static QR stays valid until a client switches to rendering the rotating token. Retiring the static secret would be a breaking change and is left to the maintainers.

#131 — verify rate limiting

  • GET /tickets/verify/:qrSecret is already bound to ScanRateLimitGuard (per-IP and per-secret, 429 past the limit, configurable via SCAN_RATE_LIMIT_*), with guard unit tests and a metadata test for the binding. No production code changes here.
  • Adds tickets.verify-rate-limit.spec.ts, which sends real HTTP requests through the real guard and an in-memory store and asserts 429 past the limit without the handler being reached.

Docs and generated files

  • docs/API.md, the README endpoint table and CHANGELOG.md cover the new routes and settings.
  • Three Bruno requests for the new routes were added. npm run docs:api also wants stellar/Get Transaction Status.bru and tickets/Build Issue Batch.bru, which were already missing on main and are unrelated, so they are not included.

Tests

  • New: qr-token.service.spec.ts (issue/verify, expiry and skew boundaries, tampering, wrong secret, malformed tokens, invalid config) and tickets.verify-rate-limit.spec.ts.
  • Extended: tickets.service.spec.ts (findOne, getQrImage, issueQrToken, token path of verify) and tickets.controller.spec.ts (routes, status codes, headers, PNG body, unauthenticated 401s).

Issues

Resolves #131
Resolves #129
Resolves #125
Resolves #121

Verification

Manual code review of the full diff only. cargo build and cargo test were not run (this is not a Rust project), and the new tests and the app itself were not built or executed locally, so CI is their first real run. npm run docs:env -- --check passes; formatting of the added code was checked with the repo's pinned prettier version. No snapshots were committed.

@drips-wave

drips-wave Bot commented Oct 17, 2026

Copy link
Copy Markdown

@c4182657-ship-it Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@netlify

netlify Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for stellarticketsbackend ready!

Name Link
🔨 Latest commit 963965f
🔍 Latest deploy log https://app.netlify.com/projects/stellarticketsbackend/deploys/6ad3aec15e4cbda1fa368735
😎 Deploy Preview https://deploy-preview-460--stellarticketsbackend.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@EmmanuelOchaje
EmmanuelOchaje merged commit 0f72d47 into StellarTickets:main Oct 18, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants