05/06 Updated markdown files

This commit is contained in:
2026-05-06 17:24:02 -04:00
parent 04aae8bf5d
commit d924e41d9e
2 changed files with 119 additions and 33 deletions
+33 -10
View File
@@ -6,8 +6,8 @@ A multi-tenant SaaS POS web application for nail salons, served across two dedic
| Domain | Audience | Purpose |
|---|---|---|
| `admin.mydomain.com` | System Admins | Platform management |
| `mydomain.com` | Tenant users | Salon management |
| `posadmin.ngodanguyen.tech` | System Admins | Platform management |
| `pos.ngodanguyen.tech` | Tenant users | Salon management |
---
@@ -93,6 +93,8 @@ flask --app wsgi_tenant:app db upgrade
### 7. Seed initial data (plans + superadmin)
> **Important:** There is no default seeded admin user. You must create one manually using the shell commands below. Choose a strong password — minimum 10 characters, at least one uppercase letter, one lowercase letter, and one digit.
```bash
flask --app wsgi_admin:app shell
```
@@ -160,9 +162,6 @@ sudo chown salonpos:salonpos /var/log/salon_pos_admin /var/log/salon_pos_tenant
sudo cp deploy/salon_pos_admin.service /etc/systemd/system/
sudo cp deploy/salon_pos_tenant.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo mkdir -p /run/salon_pos
sudo chown salonpos:salonpos /run/salon_pos
sudo chmod 775 /run/salon_pos
sudo systemctl enable salon_pos_admin salon_pos_tenant
sudo systemctl start salon_pos_admin salon_pos_tenant
sudo systemctl status salon_pos_admin salon_pos_tenant
@@ -263,14 +262,38 @@ pip install -r requirements.txt
cp .env.example .env
# Set FLASK_ENV=development in .env
flask --app wsgi_tenant:app db upgrade
flask --app wsgi_tenant:app run --port 5001
flask --app wsgi_admin:app run --port 5002
flask --app wsgi_tenant:app run --port 5001 # Tenant portal → http://localhost:5001/login
flask --app wsgi_admin:app run --port 5002 # Admin portal → http://localhost:5002/login
```
---
## Project Structure
## Phase 1 Resolutions
The following issues were encountered and resolved during Phase 1 — documented here to inform future contributors.
### Circular Foreign Keys (MySQL InnoDB)
`appointments.rebooked_from_transaction_id` and `transactions.appointment_id` form a circular FK dependency. MySQL InnoDB enforces FK constraints at `CREATE TABLE` time so neither table could be created first. **Fix:** both columns use `use_alter=True, name="fk_..."` so SQLAlchemy defers them as `ALTER TABLE` statements after all tables are created.
If you re-generate migrations from scratch, always verify with:
```bash
flask --app wsgi_tenant:app db upgrade
```
Any `(1824, "Failed to open the referenced table ...")` error means a circular FK is missing `use_alter=True`.
### Static File Double-Prefix
Flask apps with `static_folder="../static"` and `static_url_path="/static/admin"` produce URLs like `/static/admin/css/admin.css`. If templates then call `url_for('static', filename='admin/css/admin.css')` the URL becomes `/static/admin/admin/css/admin.css` (doubled prefix). **Fix:** each app points `static_folder` directly at its subdirectory (`static/admin/` or `static/tenant/`) with `static_url_path="/static"`. Templates use `url_for('static', filename='css/admin.css')` with no portal prefix in the filename.
### Content Security Policy and Bootstrap CDN
The CSP must explicitly allow `https://cdn.jsdelivr.net` in `script-src`, `style-src`, and `font-src`. Both `app/security.py` (Flask after-request hook) and `deploy/nginx.conf` must be consistent — Nginx headers override Flask headers in production.
### Admin Login URL
The admin portal login page is at `posadmin.ngodanguyen.tech/login` (not `/admin/login`). The admin auth blueprint uses `url_prefix=""`. Visiting `/` redirects to `/login`.
---
```
salon_pos/
├── app/
@@ -283,8 +306,8 @@ salon_pos/
│ ├── models/
│ │ ├── platform.py # SystemUser, Tenant, Plan, AuditLog, ...
│ │ └── salon.py # All tenant-scoped models
│ ├── admin/ # admin.mydomain.com blueprints
│ └── tenant/ # mydomain.com blueprints
│ ├── admin/ # posadmin.ngodanguyen.tech blueprints
│ └── tenant/ # pos.ngodanguyen.tech blueprints
├── config.py # Dev / Prod / Test config classes
├── wsgi_admin.py # Gunicorn entrypoint — admin
├── wsgi_tenant.py # Gunicorn entrypoint — tenant
@@ -292,4 +315,4 @@ salon_pos/
├── .env.example
├── deploy/ # systemd units, Nginx config, backup scripts
└── tests/ # pytest test suites
```
```