05/06 Phase 2: fixed issues 3rd

This commit is contained in:
2026-05-07 11:44:05 -04:00
parent 50347e95c6
commit 33010fd71b
19 changed files with 81 additions and 49 deletions
+37 -1
View File
@@ -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. |