Device capability flags: restrict POS devices to sales and/or topup - #187
Open
daedeloth wants to merge 15 commits into
Open
Device capability flags: restrict POS devices to sales and/or topup#187daedeloth wants to merge 15 commits into
daedeloth wants to merge 15 commits into
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RQjdQhQM3q7MZCWCv3AdmD
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RQjdQhQM3q7MZCWCv3AdmD
docker compose run --rm phpunit mirrors the CI MySQL service (catlab_drinks_test, test/test) so feature tests run locally without host PHP extensions or a manually provisioned database. Both services sit behind the 'test' profile so docker compose up doesn't start them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The repo gained a feature-test suite and dockerized runner since CLAUDE.md was written; backend tasks now carry real failing-test steps instead of tinker smoke checks. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RQjdQhQM3q7MZCWCv3AdmD
Implement Task 1: Add database columns and model support for device capability flags (allow_sales and allow_topup). Both flags default to true. Updated Device model to include fillable fields, boolean casts, and reassignment logic when allow_sales is disabled. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RQjdQhQM3q7MZCWCv3AdmD
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RQjdQhQM3q7MZCWCv3AdmD
- Management API: allow_sales/allow_topup fields writeable (admin can change) - Device API: same fields visible but read-only (POS cannot change own capabilities) - TransactionResourceDefinition: expose unauthorized field for both APIs Implements Task 3: TDD approach with three tests ensuring proper security boundary. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RQjdQhQM3q7MZCWCv3AdmD
TransactionMerger now accepts the uploading Device and records uploaded_by_device_id on each merged transaction. Topup/reset/refund transactions uploaded by a device with allow_topup=false are flagged unauthorized=true, giving admins an audit trail for offline NFC card writes that can't be blocked server-side. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RQjdQhQM3q7MZCWCv3AdmD
- Add 'allow_sales' check to findBestDevice() query alongside allow_remote_orders - Update reevaluateAssignments() to reassign when either flag is disabled - Add testAssignOrderExcludesSalesDisabledDevices and testReevaluateReassignsWhenSalesDisabled tests Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RQjdQhQM3q7MZCWCv3AdmD
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RQjdQhQM3q7MZCWCv3AdmD
Adds a pure deviceCapabilities.js module (TDD, vitest-covered) that maps allow_sales/allow_topup to route redirects, a Disabled.vue dead-end screen, and app.js wiring (window.DEVICE_ALLOW_SALES/TOPUP boot flags, a router.beforeEach guard, and the /disabled route). Missing flags on stale cached device responses are treated as enabled so existing devices keep working. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RQjdQhQM3q7MZCWCv3AdmD
Gate the Events and Cards navbar items in App.vue, and the order toggles in Settings.vue based on window.DEVICE_ALLOW_SALES and window.DEVICE_ALLOW_TOPUP capability flags set in Task 7. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RQjdQhQM3q7MZCWCv3AdmD
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RQjdQhQM3q7MZCWCv3AdmD
…ads, document risks - Card.vue: gate the topup/reset/rebuild/alias/discount UI behind an allowTopup flag (window.DEVICE_ALLOW_TOPUP !== false) so a sales-only POS device can no longer mutate cards via the CheckIn route, which mounts Card.vue without any capability check. - TransactionMerger: also flag a transaction as unauthorized when a non-topup device uploads any positive-value, non-reversal transaction (not just topup/reset/refund), closing the gap where a mistyped transaction_type could bypass the type-list check. - Design spec: document known residual risks (offline balance inflation without a typed upload, unflagged positive reversals, detection vs. prevention) in a new Known limitations section. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RQjdQhQM3q7MZCWCv3AdmD
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RQjdQhQM3q7MZCWCv3AdmD
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements the feature request to assign POS devices a limited function — sales-only, topup-only, or both — so bar volunteers cannot top up or reset NFC cards, while dedicated topup stations can be locked out of sales.
Device:allow_sales/allow_topup(defaulttrue, existing fleets unaffected). Editable only via the Management API (Manage → Devices → Edit, with capability badges in the list); the Device API exposes them read-only, so a device cannot re-enable its own capabilities.uploaded_by_device_idon every device upload and marksunauthorized = truefor topup/reset/refund uploads — and any positive-value non-reversal upload — from non-topup devices. Flagged rows get a red badge in the transactions overview. Residual risks are documented in the spec's Known limitations section.allow_remote_orders), and pending orders are reassigned when an admin disables sales.docker compose run --rm phpunit,testprofile) mirroring CI.Design spec:
docs/superpowers/specs/2026-07-08-device-capability-flags-design.mdTest plan
npm run productionbuilds clean; i18n keys verified identical across all 5 locales🤖 Generated with Claude Code
https://claude.ai/code/session_01RQjdQhQM3q7MZCWCv3AdmD