From 33010fd71be9115222a02e5ce86d9402967d11c4 Mon Sep 17 00:00:00 2001 From: NguyenND Date: Thu, 7 May 2026 11:44:05 -0400 Subject: [PATCH] 05/06 Phase 2: fixed issues 3rd --- CLAUDE.md | 38 ++++++++++++++++++- app/templates/tenant/auth/account_locked.html | 2 +- app/templates/tenant/auth/cancelled.html | 2 +- app/templates/tenant/auth/login.html | 6 +-- .../tenant/auth/password_reset_confirm.html | 2 +- .../tenant/auth/password_reset_request.html | 2 +- app/templates/tenant/auth/suspended.html | 2 +- app/templates/tenant/dashboard/index.html | 2 +- app/templates/tenant/feature_unavailable.html | 2 +- app/templates/tenant/layouts/base.html | 26 ++++++------- app/templates/tenant/staff_auth/login.html | 2 +- .../tenant/staff_auth/staff_login.html | 2 +- templates/tenant/auth/account_locked.html | 2 +- templates/tenant/auth/login.html | 6 +-- .../tenant/auth/password_reset_confirm.html | 2 +- .../tenant/auth/password_reset_request.html | 2 +- templates/tenant/feature_unavailable.html | 2 +- templates/tenant/layouts/base.html | 26 ++++++------- templates/tenant/staff_auth/staff_login.html | 2 +- 19 files changed, 81 insertions(+), 49 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index aff583f..fe6cd27 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -886,6 +886,42 @@ MySQL backup credentials stored in `/etc/mysql/backup.cnf` (mode 600, owned by ` --- +## Development Rules + +The following rules are mandatory for all development on this codebase. Violations have caused production 500 errors. + +**Rule 1 — Never assume, always read first.** +Before fixing any error or touching any file, read the actual file content on disk. Do not assume the file matches what was previously written — the server may have a different version. Use `cat`, `grep`, or `sed -n` to read the exact content before making any changes. + +**Rule 2 — No temporary fixes.** +All fixes must address the root cause. Workarounds that mask a problem without solving it are not permitted. If the root cause is unclear, investigate further before writing any code. + +**Rule 3 — Never remove or change existing functionality unless explicitly instructed.** +All changes must be additive or corrective. Existing routes, function names, variable names, and model fields must be preserved unless a change is explicitly requested. + +**Rule 4 — Always audit the full extends chain in every template you create or modify.** +Every `{% extends "..." %}` path must resolve relative to the Flask app's `template_folder` root. Before delivering any template, verify the parent template exists at that exact path. Correct convention for this project: `admin/layouts/base.html` for admin templates, `tenant/layouts/base.html` for tenant templates. + +**Rule 5 — Never leave `url_for()` calls pointing at unregistered or stub-only endpoints.** +If a blueprint is registered as a stub (no routes yet), all `url_for()` references to its endpoints in templates must be replaced with `'#'` or guarded with `{% if %}` until the route is implemented. A `BuildError` from an unregistered endpoint is a 500 error in production. + +**Rule 6 — Always add logging for create, edit, and delete actions.** +Every route that creates, edits, deletes, or changes the status of a record must call `logger.info()` or `logger.warning()` with the action, relevant IDs, and actor context. + +**Rule 7 — All audit log values must be JSON-serialisable.** +When passing data to `AuditLog.log()` or any JSON column, always convert `datetime`/`date` to ISO-8601 strings via `.isoformat()` and `Decimal` to `float`. Use `model_to_dict()` from `app/admin/utils.py` — never pass raw ORM objects. + +**Rule 8 — Use absolute paths for `template_folder` and `static_folder` in app factories.** +Never use relative paths (`"../templates"`) in Flask app factories. Flask resolves relative paths against the package directory, not the project root, which differs depending on where Gunicorn is started. Always use `os.path.dirname(os.path.abspath(__file__))` as the anchor. + +**Rule 9 — Test all fixes before delivering them.** +Every fix must be validated by a programmatic test (import test, render test, or unit test) before being packaged for delivery. Do not ship code that has not been executed in the container. + +**Rule 10 — Pack files when more than 5 files are changed.** +When a fix touches more than 5 files, compress them into a ZIP for delivery. Always include only the changed files — not the entire project. + +--- + ## Phase 1 — Implementation Notes The following decisions and resolutions were made during Phase 1 scaffold implementation. @@ -952,4 +988,4 @@ All Phase 2+ blueprints are registered as stubs (blueprint object only, no route | 24 | Admin login URL | Admin auth blueprint uses `url_prefix=""`. Login page is at `posadmin.ngodanguyen.tech/login`. Root `/` redirects to `/login` (unauthenticated) or `/dashboard` (authenticated). | | 25 | JWT blocklist table location | `jwt_blocklist` defined in `platform.py` (not `salon.py`) — it is a platform-level concern shared across all tenants. DB-persisted (not in-memory) to survive Gunicorn worker restarts. | | 26 | Template path convention | `template_folder` points to project-root `templates/`. All `render_template()` calls and `{% extends %}` use full paths: `"admin/auth/login.html"`, `"admin/layouts/base.html"`, `"tenant/auth/login.html"`, etc. | -| 27 | Production domains | Admin portal: `posadmin.ngodanguyen.tech`. Tenant portal: `pos.ngodanguyen.tech`. Updated in `.env`, `nginx.conf`, and all documentation. | +| 27 | Production domains | Admin portal: `posadmin.ngodanguyen.tech`. Tenant portal: `pos.ngodanguyen.tech`. Updated in `.env`, `nginx.conf`, and all documentation. | \ No newline at end of file diff --git a/app/templates/tenant/auth/account_locked.html b/app/templates/tenant/auth/account_locked.html index 3250c4c..562ed1f 100644 --- a/app/templates/tenant/auth/account_locked.html +++ b/app/templates/tenant/auth/account_locked.html @@ -1,4 +1,4 @@ -{% extends "layouts/base.html" %} +{% extends "tenant/layouts/base.html" %} {% block title %}Account Suspended{% endblock %} {% block content %} diff --git a/app/templates/tenant/auth/cancelled.html b/app/templates/tenant/auth/cancelled.html index 5a19122..603d855 100644 --- a/app/templates/tenant/auth/cancelled.html +++ b/app/templates/tenant/auth/cancelled.html @@ -1,4 +1,4 @@ -{% extends "tenant/base.html" %} +{% extends "tenant/layouts/base.html" %} {% block title %}Account Cancelled{% endblock %} {% block content %}
diff --git a/app/templates/tenant/auth/login.html b/app/templates/tenant/auth/login.html index 260a9e5..5bb56f5 100644 --- a/app/templates/tenant/auth/login.html +++ b/app/templates/tenant/auth/login.html @@ -1,4 +1,4 @@ -{% extends "layouts/base.html" %} +{% extends "tenant/layouts/base.html" %} {% block title %}Sign In{% endblock %} {% block content %} @@ -44,9 +44,7 @@ Forgot password? - - View demo account - +
diff --git a/app/templates/tenant/auth/password_reset_confirm.html b/app/templates/tenant/auth/password_reset_confirm.html index 4c938c6..1c30f62 100644 --- a/app/templates/tenant/auth/password_reset_confirm.html +++ b/app/templates/tenant/auth/password_reset_confirm.html @@ -1,4 +1,4 @@ -{% extends "layouts/base.html" %} +{% extends "tenant/layouts/base.html" %} {% block title %}Set New Password{% endblock %} {% block content %} diff --git a/app/templates/tenant/auth/password_reset_request.html b/app/templates/tenant/auth/password_reset_request.html index 96dd2fd..5e5c090 100644 --- a/app/templates/tenant/auth/password_reset_request.html +++ b/app/templates/tenant/auth/password_reset_request.html @@ -1,4 +1,4 @@ -{% extends "layouts/base.html" %} +{% extends "tenant/layouts/base.html" %} {% block title %}Reset Password{% endblock %} {% block content %} diff --git a/app/templates/tenant/auth/suspended.html b/app/templates/tenant/auth/suspended.html index 0a6c4d8..1252325 100644 --- a/app/templates/tenant/auth/suspended.html +++ b/app/templates/tenant/auth/suspended.html @@ -1,4 +1,4 @@ -{% extends "tenant/base.html" %} +{% extends "tenant/layouts/base.html" %} {% block title %}Account Suspended{% endblock %} {% block content %}
diff --git a/app/templates/tenant/dashboard/index.html b/app/templates/tenant/dashboard/index.html index 7727702..ddc17d2 100644 --- a/app/templates/tenant/dashboard/index.html +++ b/app/templates/tenant/dashboard/index.html @@ -1,4 +1,4 @@ -{% extends "tenant/base.html" %} +{% extends "tenant/layouts/base.html" %} {% block title %}Dashboard{% endblock %} {% block content %}

Dashboard diff --git a/app/templates/tenant/feature_unavailable.html b/app/templates/tenant/feature_unavailable.html index e2caebf..0d1deeb 100644 --- a/app/templates/tenant/feature_unavailable.html +++ b/app/templates/tenant/feature_unavailable.html @@ -1,4 +1,4 @@ -{% extends "layouts/base.html" %} +{% extends "tenant/layouts/base.html" %} {% block title %}Feature Unavailable{% endblock %} {% block content %} diff --git a/app/templates/tenant/layouts/base.html b/app/templates/tenant/layouts/base.html index 34564f3..ed22b7f 100644 --- a/app/templates/tenant/layouts/base.html +++ b/app/templates/tenant/layouts/base.html @@ -37,7 +37,7 @@ {% for loc in locations %}
  • + href="{{ '#' }}"> {{ loc.name }} {% if loc.is_primary %}Primary{% endif %} @@ -86,74 +86,74 @@
  • {% if current_user.role == 'tenant_admin' %} diff --git a/app/templates/tenant/staff_auth/login.html b/app/templates/tenant/staff_auth/login.html index f555f5d..61792df 100644 --- a/app/templates/tenant/staff_auth/login.html +++ b/app/templates/tenant/staff_auth/login.html @@ -1,4 +1,4 @@ -{% extends "tenant/base.html" %} +{% extends "tenant/layouts/base.html" %} {% block title %}Staff Login{% endblock %} {% block content %}
    diff --git a/app/templates/tenant/staff_auth/staff_login.html b/app/templates/tenant/staff_auth/staff_login.html index a3fca4f..fb952e7 100644 --- a/app/templates/tenant/staff_auth/staff_login.html +++ b/app/templates/tenant/staff_auth/staff_login.html @@ -1,4 +1,4 @@ -{% extends "layouts/base.html" %} +{% extends "tenant/layouts/base.html" %} {% block title %}Staff Login{% endblock %} {% block content %} diff --git a/templates/tenant/auth/account_locked.html b/templates/tenant/auth/account_locked.html index 3250c4c..562ed1f 100644 --- a/templates/tenant/auth/account_locked.html +++ b/templates/tenant/auth/account_locked.html @@ -1,4 +1,4 @@ -{% extends "layouts/base.html" %} +{% extends "tenant/layouts/base.html" %} {% block title %}Account Suspended{% endblock %} {% block content %} diff --git a/templates/tenant/auth/login.html b/templates/tenant/auth/login.html index 260a9e5..5bb56f5 100644 --- a/templates/tenant/auth/login.html +++ b/templates/tenant/auth/login.html @@ -1,4 +1,4 @@ -{% extends "layouts/base.html" %} +{% extends "tenant/layouts/base.html" %} {% block title %}Sign In{% endblock %} {% block content %} @@ -44,9 +44,7 @@ Forgot password? - - View demo account - +

    diff --git a/templates/tenant/auth/password_reset_confirm.html b/templates/tenant/auth/password_reset_confirm.html index 4c938c6..1c30f62 100644 --- a/templates/tenant/auth/password_reset_confirm.html +++ b/templates/tenant/auth/password_reset_confirm.html @@ -1,4 +1,4 @@ -{% extends "layouts/base.html" %} +{% extends "tenant/layouts/base.html" %} {% block title %}Set New Password{% endblock %} {% block content %} diff --git a/templates/tenant/auth/password_reset_request.html b/templates/tenant/auth/password_reset_request.html index 96dd2fd..5e5c090 100644 --- a/templates/tenant/auth/password_reset_request.html +++ b/templates/tenant/auth/password_reset_request.html @@ -1,4 +1,4 @@ -{% extends "layouts/base.html" %} +{% extends "tenant/layouts/base.html" %} {% block title %}Reset Password{% endblock %} {% block content %} diff --git a/templates/tenant/feature_unavailable.html b/templates/tenant/feature_unavailable.html index e2caebf..0d1deeb 100644 --- a/templates/tenant/feature_unavailable.html +++ b/templates/tenant/feature_unavailable.html @@ -1,4 +1,4 @@ -{% extends "layouts/base.html" %} +{% extends "tenant/layouts/base.html" %} {% block title %}Feature Unavailable{% endblock %} {% block content %} diff --git a/templates/tenant/layouts/base.html b/templates/tenant/layouts/base.html index 34564f3..ed22b7f 100644 --- a/templates/tenant/layouts/base.html +++ b/templates/tenant/layouts/base.html @@ -37,7 +37,7 @@ {% for loc in locations %}
  • + href="{{ '#' }}"> {{ loc.name }} {% if loc.is_primary %}Primary{% endif %} @@ -86,74 +86,74 @@
  • {% if current_user.role == 'tenant_admin' %} diff --git a/templates/tenant/staff_auth/staff_login.html b/templates/tenant/staff_auth/staff_login.html index a3fca4f..fb952e7 100644 --- a/templates/tenant/staff_auth/staff_login.html +++ b/templates/tenant/staff_auth/staff_login.html @@ -1,4 +1,4 @@ -{% extends "layouts/base.html" %} +{% extends "tenant/layouts/base.html" %} {% block title %}Staff Login{% endblock %} {% block content %}