# Architecture Decisions ## 1. Registration Code Model **Decision:** Added a `RegistrationCode` model to the database schema. **Rationale:** The specification requires a registration-code mechanism. Rather than overloading an existing model or implementing a complex external system, a simple `RegistrationCode` table with venue scoping, expiration, and single-use semantics provides a clean implementation. ## 2. Payment Method Must Be Explicitly Selected **Decision:** The UI never defaults to `cash`. The user must explicitly select a payment method. **Rationale:** The specification explicitly forbids silent defaults. This prevents accidental charges and ensures compliance with the business requirement. ## 3. Cursor Implementation **Decision:** Opaque cursor encoded as base64url containing timestamp + UUID tiebreaker. **Rationale:** Provides a simple, privacy-preserving cursor that allows the server to determine which commands the device has already seen without exposing database internals. ## 4. Refresh Token Storage **Decision:** Refresh tokens are stored hashed (SHA-256) in a `RefreshToken` table, supporting revocation and rotation. **Rationale:** Provides security (tokens can be revoked) and aligns with OAuth2 best practices for refresh token management. ## 5. PostgreSQL Everywhere **Decision:** PostgreSQL is used in development, CI and production. **Rationale:** One database means one set of migrations; the schema uses JSON columns and serializable transactions that SQLite doesn't support the same way. ## 6. Invalidation-Only Live Updates **Decision:** The API pushes topic names (`tabs`, `commands`, ...) over Socket.IO; the dashboard refetches that data over the normal REST API. It falls back to polling while the socket is down. **Rationale:** Events never carry data, so a socket can't see anything its owner couldn't fetch, and the REST API stays the single source of truth. ## 7. In-Memory Rate Limiting **Decision:** Use NestJS ThrottlerModule with in-memory storage. **Rationale:** Suitable for single-instance deployments. The abstraction allows swapping to Redis without controller changes. ## 8. Venue Isolation via JWT Claims **Decision:** Venue ID is embedded in the JWT token. All service methods verify the requesting user/device's venue context rather than trusting URL parameters alone. **Rationale:** Prevents cross-venue access even if a user manually modifies URL parameters.