diff --git a/docs/superpowers/plans/2026-05-26-fusion-login-audit.md b/docs/superpowers/plans/2026-05-26-fusion-login-audit.md index 6ab3eda5..920c3576 100644 --- a/docs/superpowers/plans/2026-05-26-fusion-login-audit.md +++ b/docs/superpowers/plans/2026-05-26-fusion-login-audit.md @@ -20,17 +20,26 @@ These apply to every task. Read once, internalize, then execute. ```bash docker exec odoo-modsdev-app cat /usr/lib/python3/dist-packages/odoo/addons/base/models/res_users.py | head -200 ``` -- **Module location:** `K:\Github\Odoo-Modules\fusion_login_audit\` (Windows paths) which is bind-mounted into the `odoo-modsdev-app` container at `/mnt/extra-addons/fusion_login_audit/` (or whatever path the compose file specifies — verify with `docker inspect odoo-modsdev-app --format '{{json .Mounts}}' | python -m json.tool`). +- **Module location:** `K:\Github\Odoo-Modules\fusion_login_audit\` (Windows paths) is bind-mounted into the `odoo-modsdev-app` container at `/mnt/odoo-modules/fusion_login_audit/`. (Verify with `docker inspect odoo-modsdev-app --format '{{json .Mounts}}' | python -m json.tool` if in doubt.) - **Field naming:** new fields on `res.users` and `res.config.settings` use the `x_fc_*` prefix. Fields on the new `fusion.login.audit` model use plain names. - **Settings field types:** booleans/integers/floats/char/selection/many2one/datetime only on `res.config.settings`. No Date fields. (`x_fc_login_audit_retention_days` is an Integer — not a Date.) - **`res.groups`:** never use `users=` or `category_id=`. - **HTTP routes:** if any are added, use `type="jsonrpc"` not `type="json"`. - **Canadian English** for all user-facing strings ("Authorise", "Centre", "behaviour", etc.). -- **Test command shape:** - ```bash - docker exec odoo-modsdev-app odoo -d fusion-dev --test-enable --test-tags /fusion_login_audit -i fusion_login_audit --stop-after-init 2>&1 | tail -60 +- **SQL constraints & indexes — Odoo 19 declarative form (project CLAUDE.md rule #9):** + Do **not** write `_sql_constraints = [(name, def, msg), ...]` or override `init(self)` with raw SQL. Odoo 19 silently drops both with only a warning. Use the declarative class attributes: + ```python + _result_failure_reason_consistent = models.Constraint( + "CHECK (...)", "Failure rows must carry a failure_reason." + ) + _user_time_idx = models.Index('(user_id, event_time DESC)') ``` - First run uses `-i fusion_login_audit` (install). Subsequent runs after code changes use `-u fusion_login_audit` (update). Expected to take 15-40 seconds per run. + The attribute name (sans the leading underscore) becomes the SQL object's suffix: `{table}_{suffix}`. `models.Index` supports `DESC`, `WHERE`, and `USING ...`. Tasks that mention `_sql_constraints` or `init()` in this plan were written against the legacy pattern — translate to the declarative form when implementing. +- **Test command shape (use ephemeral ports — the dev container holds 8069):** + ```bash + docker exec odoo-modsdev-app odoo -d fusion-dev --test-enable --test-tags /fusion_login_audit -u fusion_login_audit --stop-after-init --http-port=0 --gevent-port=0 2>&1 | tail -60 + ``` + Without `--http-port=0 --gevent-port=0` the second odoo process tries to bind 8069 and dies with `Address already in use`. Use `-i fusion_login_audit` only on the very first install; everything after T1 uses `-u` (update). Expected runtime: 15-40 seconds per run. - **Commit cadence:** every task ends with a commit. Branch is already `feat/fusion-login-audit` (cut from `main` at sha cc26b9ad). Never push without an explicit user request. - **Commit message footer:** ```