diff --git a/docs/superpowers/plans/2026-05-13-nfc-clock-kiosk-plan.md b/docs/superpowers/plans/2026-05-13-nfc-clock-kiosk-plan.md index 4becc9e4..116e4676 100644 --- a/docs/superpowers/plans/2026-05-13-nfc-clock-kiosk-plan.md +++ b/docs/superpowers/plans/2026-05-13-nfc-clock-kiosk-plan.md @@ -11,11 +11,11 @@ **Reference spec:** [docs/superpowers/specs/2026-05-13-nfc-clock-kiosk-design.md](../specs/2026-05-13-nfc-clock-kiosk-design.md) **Dev environment:** -- Odoo container: `odoo-dev-app` -- Database: `fusion-dev` +- Odoo container: `odoo-modsdev-app` +- Database: `modsdev` - Local URL: http://localhost:8069 -- Module reload: `docker exec odoo-dev-app odoo -d fusion-dev -u fusion_clock --stop-after-init` -- Run tests: `docker exec odoo-dev-app odoo -d fusion-dev --test-tags fusion_clock --stop-after-init -i fusion_clock` +- Module reload: `docker exec odoo-modsdev-app odoo -d modsdev -u fusion_clock --stop-after-init` +- Run tests: `docker exec odoo-modsdev-app odoo -d modsdev --test-tags fusion_clock --stop-after-init -i fusion_clock` --- @@ -112,7 +112,7 @@ class TestNfcModels(TransactionCase): - [ ] **Step 3: Run the test to confirm it fails** ```bash -docker exec odoo-dev-app odoo -d fusion-dev --test-tags fusion_clock --stop-after-init -i fusion_clock 2>&1 | tail -40 +docker exec odoo-modsdev-app odoo -d modsdev --test-tags fusion_clock --stop-after-init -i fusion_clock 2>&1 | tail -40 ``` Expected: errors about `x_fclk_nfc_card_uid` not being a valid field on `hr.employee`. @@ -147,7 +147,7 @@ In `fusion_clock/models/hr_employee.py`, insert after the existing `x_fclk_kiosk - [ ] **Step 5: Run the test to confirm it passes** ```bash -docker exec odoo-dev-app odoo -d fusion-dev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -40 +docker exec odoo-modsdev-app odoo -d modsdev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -40 ``` Expected: `0 failed, 0 error(s)` for the three test methods. @@ -231,7 +231,7 @@ Tests are in the same file, no additional import needed. - [ ] **Step 3: Run the tests to confirm they fail** ```bash -docker exec odoo-dev-app odoo -d fusion-dev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -30 +docker exec odoo-modsdev-app odoo -d modsdev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -30 ``` Expected: `nfc_kiosk` not a valid Selection value; `x_fclk_check_in_photo` not a valid field. @@ -332,7 +332,7 @@ The two updated fields should look like: - [ ] **Step 6: Run the tests to confirm they pass** ```bash -docker exec odoo-dev-app odoo -d fusion-dev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -30 +docker exec odoo-modsdev-app odoo -d modsdev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -30 ``` Expected: 6 tests pass (3 from Task 1 + 3 new). @@ -380,7 +380,7 @@ class TestNfcKioskCompanyField(TransactionCase): - [ ] **Step 2: Run the test to confirm it fails** ```bash -docker exec odoo-dev-app odoo -d fusion-dev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -30 +docker exec odoo-modsdev-app odoo -d modsdev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -30 ``` Expected: `x_fclk_nfc_kiosk_location_id` not a valid field on `res.company`. @@ -423,7 +423,7 @@ from . import res_company - [ ] **Step 5: Run the tests to confirm they pass** ```bash -docker exec odoo-dev-app odoo -d fusion-dev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -30 +docker exec odoo-modsdev-app odoo -d modsdev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -30 ``` Expected: 8 tests pass (6 from previous tasks + 2 new). @@ -469,7 +469,7 @@ Open `fusion_clock/data/ir_config_parameter_data.xml`. Find the closing ` - [ ] **Step 2: Reload the module and confirm parameters are present** ```bash -docker exec odoo-dev-app odoo -d fusion-dev -u fusion_clock --stop-after-init 2>&1 | tail -10 +docker exec odoo-modsdev-app odoo -d modsdev -u fusion_clock --stop-after-init 2>&1 | tail -10 ``` Expected: clean reload, no errors. @@ -477,7 +477,7 @@ Expected: clean reload, no errors. Then verify in odoo-shell: ```bash -docker exec -it odoo-dev-app odoo shell -d fusion-dev --no-http << 'EOF' +docker exec -it odoo-modsdev-app odoo shell -d modsdev --no-http << 'EOF' ICP = env['ir.config_parameter'].sudo() for k in ['fusion_clock.enable_nfc_kiosk', 'fusion_clock.nfc_photo_required', 'fusion_clock.nfc_enroll_password', 'fusion_clock.nfc_kiosk_debug']: print(k, '=', repr(ICP.get_param(k))) @@ -585,7 +585,7 @@ Open `fusion_clock/views/res_config_settings_views.xml`. Find the last ` - [ ] **Step 3: Reload and verify in browser** ```bash -docker exec odoo-dev-app odoo -d fusion-dev -u fusion_clock --stop-after-init 2>&1 | tail -5 +docker exec odoo-modsdev-app odoo -d modsdev -u fusion_clock --stop-after-init 2>&1 | tail -5 ``` Then in browser, navigate to http://localhost:8069/odoo/settings → Fusion Clock app → scroll to "NFC Clock Kiosk" block. Confirm: @@ -670,7 +670,7 @@ from . import test_clock_nfc_kiosk - [ ] **Step 3: Run the test to confirm it fails** ```bash -docker exec odoo-dev-app odoo -d fusion-dev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -30 +docker exec odoo-modsdev-app odoo -d modsdev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -30 ``` Expected: 404 errors on `/fusion_clock/kiosk/nfc` (route not yet defined). @@ -771,7 +771,7 @@ Edit `fusion_clock/__manifest__.py`. In the `'data'` list, add `'views/kiosk_nfc - [ ] **Step 8: Run the tests to confirm they pass** ```bash -docker exec odoo-dev-app odoo -d fusion-dev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -30 +docker exec odoo-modsdev-app odoo -d modsdev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -30 ``` Expected: both new tests pass. @@ -842,7 +842,7 @@ class TestUidNormalization(TransactionCase): - [ ] **Step 2: Run the test to confirm it fails** ```bash -docker exec odoo-dev-app odoo -d fusion-dev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -30 +docker exec odoo-modsdev-app odoo -d modsdev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -30 ``` Expected: `AttributeError: type object 'FusionClockNfcKiosk' has no attribute '_normalize_uid'`. @@ -882,7 +882,7 @@ class FusionClockNfcKiosk(http.Controller): - [ ] **Step 4: Run the tests to confirm they pass** ```bash -docker exec odoo-dev-app odoo -d fusion-dev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -30 +docker exec odoo-modsdev-app odoo -d modsdev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -30 ``` Expected: 7 normalization tests pass. @@ -982,7 +982,7 @@ class TestEnrollEndpoint(HttpCase): - [ ] **Step 2: Run the tests to confirm they fail** ```bash -docker exec odoo-dev-app odoo -d fusion-dev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -40 +docker exec odoo-modsdev-app odoo -d modsdev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -40 ``` Expected: 404 on `/fusion_clock/kiosk/nfc/enroll`. @@ -1049,7 +1049,7 @@ Append to `fusion_clock/controllers/clock_nfc_kiosk.py` (inside the `FusionClock - [ ] **Step 4: Run the tests to confirm they pass** ```bash -docker exec odoo-dev-app odoo -d fusion-dev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -40 +docker exec odoo-modsdev-app odoo -d modsdev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -40 ``` Expected: 4 enroll tests pass. @@ -1150,7 +1150,7 @@ class TestTapEndpointHappyPath(HttpCase): - [ ] **Step 2: Run the test to confirm it fails** ```bash -docker exec odoo-dev-app odoo -d fusion-dev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -40 +docker exec odoo-modsdev-app odoo -d modsdev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -40 ``` Expected: 404 on `/fusion_clock/kiosk/nfc/tap`. @@ -1267,7 +1267,7 @@ Append to `fusion_clock/controllers/clock_nfc_kiosk.py` (inside the `FusionClock - [ ] **Step 4: Run the tests to confirm they pass** ```bash -docker exec odoo-dev-app odoo -d fusion-dev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -40 +docker exec odoo-modsdev-app odoo -d modsdev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -40 ``` Expected: both tap tests pass. @@ -1370,7 +1370,7 @@ class TestTapEndpointErrors(HttpCase): - [ ] **Step 2: Run the tests to confirm they fail** ```bash -docker exec odoo-dev-app odoo -d fusion-dev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -40 +docker exec odoo-modsdev-app odoo -d modsdev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -40 ``` Expected: most error tests pass already (the controller already returns `card_unknown`, `clock_disabled`, etc.) but `test_debounce_silent_second_tap` fails because debounce isn't implemented yet. @@ -1413,7 +1413,7 @@ Then in the `nfc_tap` method, immediately AFTER the `normalized = self._normaliz - [ ] **Step 4: Run the tests to confirm they pass** ```bash -docker exec odoo-dev-app odoo -d fusion-dev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -40 +docker exec odoo-modsdev-app odoo -d modsdev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -40 ``` Expected: all 6 error tests pass. @@ -1506,7 +1506,7 @@ class TestTapPhotoHandling(HttpCase): - [ ] **Step 2: Run the tests to confirm they fail** ```bash -docker exec odoo-dev-app odoo -d fusion-dev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -40 +docker exec odoo-modsdev-app odoo -d modsdev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -40 ``` Expected: photo_required rejection test fails because the endpoint doesn't enforce it; photo-saved test fails because photo isn't decoded/saved. @@ -1559,7 +1559,7 @@ And in the clock-out branch: - [ ] **Step 4: Run the tests to confirm they pass** ```bash -docker exec odoo-dev-app odoo -d fusion-dev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -40 +docker exec odoo-modsdev-app odoo -d modsdev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -40 ``` Expected: all 3 photo tests pass. @@ -1619,7 +1619,7 @@ class TestEmployeeSearch(HttpCase): - [ ] **Step 2: Run the test to confirm it fails** ```bash -docker exec odoo-dev-app odoo -d fusion-dev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -30 +docker exec odoo-modsdev-app odoo -d modsdev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -30 ``` Expected: 404 on `/fusion_clock/kiosk/nfc/employee_search`. @@ -1639,7 +1639,7 @@ Append to `fusion_clock/controllers/clock_nfc_kiosk.py` (inside the class): - [ ] **Step 4: Run the test to confirm it passes** ```bash -docker exec odoo-dev-app odoo -d fusion-dev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -30 +docker exec odoo-modsdev-app odoo -d modsdev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -30 ``` Expected: search test passes. @@ -1929,7 +1929,7 @@ Edit `fusion_clock/__manifest__.py`. In the `'web.assets_frontend'` list, add th - [ ] **Step 3: Reload module and verify SCSS compiles** ```bash -docker exec odoo-dev-app odoo -d fusion-dev -u fusion_clock --stop-after-init 2>&1 | grep -i -E "(error|warning|nfc_kiosk)" | head -20 +docker exec odoo-modsdev-app odoo -d modsdev -u fusion_clock --stop-after-init 2>&1 | grep -i -E "(error|warning|nfc_kiosk)" | head -20 ``` Expected: no SCSS compilation errors. If you see "could not be parsed", check for missing semicolons or typos. @@ -2003,7 +2003,7 @@ Open `fusion_clock/views/kiosk_nfc_templates.xml` and REPLACE the entire file co - [ ] **Step 2: Reload module** ```bash -docker exec odoo-dev-app odoo -d fusion-dev -u fusion_clock --stop-after-init 2>&1 | tail -5 +docker exec odoo-modsdev-app odoo -d modsdev -u fusion_clock --stop-after-init 2>&1 | tail -5 ``` - [ ] **Step 3: Smoke test in browser** @@ -2011,7 +2011,7 @@ docker exec odoo-dev-app odoo -d fusion-dev -u fusion_clock --stop-after-init 2> In Chrome, open http://localhost:8069 and log in as an admin/manager. Then enable the kiosk via odoo-shell: ```bash -docker exec -it odoo-dev-app odoo shell -d fusion-dev --no-http << 'EOF' +docker exec -it odoo-modsdev-app odoo shell -d modsdev --no-http << 'EOF' env['ir.config_parameter'].sudo().set_param('fusion_clock.enable_nfc_kiosk', 'True') env.cr.commit() EOF @@ -2191,7 +2191,7 @@ Edit `fusion_clock/__manifest__.py`. The `web.assets_frontend` list should now i - [ ] **Step 3: Reload + smoke test in browser** ```bash -docker exec odoo-dev-app odoo -d fusion-dev -u fusion_clock --stop-after-init 2>&1 | tail -5 +docker exec odoo-modsdev-app odoo -d modsdev -u fusion_clock --stop-after-init 2>&1 | tail -5 ``` Hard-refresh http://localhost:8069/fusion_clock/kiosk/nfc (Ctrl+Shift+R). Expected: @@ -2318,7 +2318,7 @@ In `fusion_clock/static/src/js/fusion_clock_nfc_kiosk.js`, REPLACE the setup wiz - [ ] **Step 2: Reload + verify in Chrome on Android** ```bash -docker exec odoo-dev-app odoo -d fusion-dev -u fusion_clock --stop-after-init 2>&1 | tail -5 +docker exec odoo-modsdev-app odoo -d modsdev -u fusion_clock --stop-after-init 2>&1 | tail -5 ``` Open the kiosk URL in Chrome on an Android phone (HTTPS required — see note below). Click "Tap to enable NFC reader". Browser will prompt for NFC permission → grant it. Tap any contactless card. @@ -2424,7 +2424,7 @@ Then UPDATE the setup button click handler to also start the camera: - [ ] **Step 2: Reload + smoke test on a real device** ```bash -docker exec odoo-dev-app odoo -d fusion-dev -u fusion_clock --stop-after-init 2>&1 | tail -5 +docker exec odoo-modsdev-app odoo -d modsdev -u fusion_clock --stop-after-init 2>&1 | tail -5 ``` On the Android phone with NFC, hard-refresh the kiosk page. Click activation button. Browser prompts for NFC, then for Camera. Grant both. Tap a contactless card. @@ -2634,13 +2634,13 @@ Then UPDATE the `window.__nfcKiosk` exposure at the bottom to include the enroll - [ ] **Step 2: Reload + smoke test on real device** ```bash -docker exec odoo-dev-app odoo -d fusion-dev -u fusion_clock --stop-after-init 2>&1 | tail -5 +docker exec odoo-modsdev-app odoo -d modsdev -u fusion_clock --stop-after-init 2>&1 | tail -5 ``` Set the enroll password: ```bash -docker exec -it odoo-dev-app odoo shell -d fusion-dev --no-http << 'EOF' +docker exec -it odoo-modsdev-app odoo shell -d modsdev --no-http << 'EOF' env['ir.config_parameter'].sudo().set_param('fusion_clock.nfc_enroll_password', '1234') env.cr.commit() EOF @@ -2692,7 +2692,7 @@ In `fusion_clock/static/src/js/fusion_clock_nfc_kiosk.js`, immediately BEFORE th - [ ] **Step 2: Enable debug mode and verify** ```bash -docker exec -it odoo-dev-app odoo shell -d fusion-dev --no-http << 'EOF' +docker exec -it odoo-modsdev-app odoo shell -d modsdev --no-http << 'EOF' env['ir.config_parameter'].sudo().set_param('fusion_clock.nfc_kiosk_debug', 'True') env.cr.commit() EOF @@ -2705,7 +2705,7 @@ Hard-refresh the kiosk page. Click activation. Once at IDLE, press Ctrl+Shift+T. - [ ] **Step 3: Disable debug mode again** ```bash -docker exec -it odoo-dev-app odoo shell -d fusion-dev --no-http << 'EOF' +docker exec -it odoo-modsdev-app odoo shell -d modsdev --no-http << 'EOF' env['ir.config_parameter'].sudo().set_param('fusion_clock.nfc_kiosk_debug', 'False') env.cr.commit() EOF @@ -2746,14 +2746,14 @@ to: - [ ] **Step 2: Reload one final time** ```bash -docker exec odoo-dev-app odoo -d fusion-dev -u fusion_clock --stop-after-init 2>&1 | tail -10 +docker exec odoo-modsdev-app odoo -d modsdev -u fusion_clock --stop-after-init 2>&1 | tail -10 ``` If the asset cache appears stale (CSS not updating, old JS), follow the CLAUDE.md escalation: ```bash -docker exec -it odoo-dev-app psql -U odoo -d fusion-dev -c "DELETE FROM ir_attachment WHERE url LIKE '/web/assets/%';" -docker exec odoo-dev-app odoo -d fusion-dev -u fusion_clock --stop-after-init +docker exec -it odoo-modsdev-app psql -U odoo -d modsdev -c "DELETE FROM ir_attachment WHERE url LIKE '/web/assets/%';" +docker exec odoo-modsdev-app odoo -d modsdev -u fusion_clock --stop-after-init ``` Then in the browser, DevTools → right-click refresh → "Empty Cache and Hard Reload". @@ -2761,7 +2761,7 @@ Then in the browser, DevTools → right-click refresh → "Empty Cache and Hard - [ ] **Step 3: Run the full test suite one last time** ```bash -docker exec odoo-dev-app odoo -d fusion-dev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -50 +docker exec odoo-modsdev-app odoo -d modsdev --test-tags fusion_clock --stop-after-init -u fusion_clock 2>&1 | tail -50 ``` Expected: 0 failures, 0 errors across all NFC tests.