## Summary
- Closes#18
- Logout POST was failing CSRF Origin checks on HTTPS because `CSRF_TRUSTED_ORIGINS` was unset (Django 5)
- Derive trusted origins from `DJANGO_ALLOWED_HOSTS` (override via `DJANGO_CSRF_TRUSTED_ORIGINS`)
- Trust reverse-proxy TLS headers in prod/beta (`SECURE_PROXY_SSL_HEADER`, secure cookies)
## Test plan
- [x] `python manage.py test public.tests.CsrfTrustedOriginsTests public.tests.LogoutCsrfTests`
- [ ] Deploy, log in on aimloperations.com, click Log Out → redirect home, no 403
- [ ] Confirm login still works after deploy
Reviewed-on: #19
## Summary
- Closes#16
- Confirms `/preview_email/<pk>/` requires an authenticated user (`@login_required` already on the view)
- Adds unit tests for unauthenticated redirect and authenticated preview access
## Test plan
- [x] `python manage.py test public.tests.PreviewEmailAuthTests`
- [ ] Manually hit `/preview_email/1/` logged out → redirect to `/accounts/login/`
- [ ] Log in and hit same URL → email preview renders
Reviewed-on: #17
## Summary
- Containerize the Django app with Docker and docker-compose (dev + production)
- Refactor settings into `dev` / `beta` / `prod` environments driven by environment variables
- Connect to PostgreSQL via `DATABASE_URL` or `DB_*` vars
- Migrate package management from pip to uv (`pyproject.toml`, `uv.lock`)
- Split Gitea workflows: PRs run unit tests only; pushes to `master` run tests, Docker validation, and deploy
- Update deploy script to rsync code, preserve server `.env`, validate config, and run Docker compose
Closes#4
## Test plan
- [x] `uv run python manage.py test` passes locally (10/10)
- [x] `DJANGO_ENV=beta` and `DJANGO_ENV=prod` load with correct logging levels
- [x] `scripts/validate-env.sh` rejects missing production variables
- [ ] `docker compose up --build` starts app + Postgres locally
- [ ] Containerized unit tests pass in CI Docker job
- [ ] Server `.env` created from `.env.prod.example` before first production deploy
- [ ] CI workflow runs on this PR (tests only, no deploy)
Reviewed-on: #6
## Summary
- Adds `UserProfile` model with mutually exclusive **Employee** / **Client** types
- Replaces auto-Employee signal with auto-Client profile on user creation
- Data migration: users with time log entries → Employee; others → Client (orphan Employee rows removed)
- Admin UI at `/financial/manage_users` to set any user's type; profile page shows current type
- **Employees** can log time; **Clients** get read-only access to reports and time logs
- Time logs, reports, and dashboard filter to employees only
- 14 new tests covering signals, type switching, access control, and filtering
## Design decisions (from issue Q&A)
1. Client login = read-only financial access (reports + time logs, no edit/log time)
2. Employee and Client are strictly mutually exclusive
3. Admins (superusers) can change type via Manage Users
4. Bulk migration applied for existing users
## Test plan
- [x] `python manage.py test financial.tests` (14 tests pass)
- [x] `python manage.py test public.tests` (21 tests pass)
- [ ] Run migration on staging: `python manage.py migrate`
- [ ] Verify admin can set user types at `/financial/manage_users`
- [ ] Verify employee can log time at `/financial/timekeeping`
- [ ] Verify client sees reports/time logs read-only, cannot log time
- [ ] Verify employee filter dropdown excludes clients
Closes#14
Reviewed-on: #15
## Summary
Follow-up to PR #12 / Lighthouse agentic-browsing audit on `/contact` (score 0.88).
- Add `toolparamdescription` to all contact form fields for WebMCP schema validity
- Move reCAPTCHA outside the annotated `<form>` so `g-recaptcha-response` is excluded from the declarative tool schema
- Always render `toolname` / `tooldescription` on the contact form (not gated by `WEBMCP_ENABLED`)
- Override `django_recaptcha/widget_v3.html` to associate captcha with `form="contact-form"`
- Update docs with HTTPS Lighthouse commands
## Test plan
- [x] `python manage.py test public.tests` — 21 tests pass
- [ ] Deploy and re-run Lighthouse agentic-browsing on `https://aimloperations.com/contact`
- [ ] Confirm `webmcp-schema-validity` passes (expected overall score 1.0)
Reviewed-on: #13
## Summary
- Add `WEBMCP_ENABLED` setting and guarded `webmcp-tools.js` loader on public pages
- Register navigation tools (`list_services`, `get_page_content`, `navigate_to_service`, `open_contact_with_subject`) and contact tool (`submit_contact_inquiry`)
- Annotate contact form with declarative WebMCP attributes for Lighthouse form coverage
- Extend `PUBLIC_PAGE_ENTRIES` with summaries shared by SEO and WebMCP tools
- Add `docs/webmcp.md`, update `docs/agentic-browsing.md`, and regression tests
Closes#9
## Test plan
- [x] `python manage.py test public.tests` — 20 tests pass
- [ ] Set `WEBMCP_ENABLED=True`, enable Chrome experimental web platform features flag
- [ ] Verify homepage HTML includes `webmcp-config` and `webmcp-tools.js`
- [ ] Verify `/contact` form has `toolname="submit_contact_inquiry"`
- [ ] Run Lighthouse agentic-browsing on `/` and `/contact` with experimental flag
- [ ] Call `list_services` from WebMCP-capable Chrome on homepage
- [ ] Call `submit_contact_inquiry` on `/contact` with `DEBUG=True` (reCAPTCHA bypass)
Reviewed-on: #12
Load analytics on page load so visitors who never interact still produce data, while an informational banner lets users acknowledge the practice. Migrate legacy declined and accepted consent values so prior opt-outs are cleared and tracking resumes.
Closes#7
Reviewed-on: #10
## Summary
- Add `robots.txt`, `sitemap.xml`, and `llms.txt` endpoints so crawlers and AI agents can discover public pages
- Fix accessibility tree issues: contact form labels, semantic nav/profile dropdown buttons, cookie consent dialog ARIA, and dead `href="#"` links
- Reduce layout shift on homepage/contact via hero min-heights, trusted-by marquee sizing, and fixed cookie banner
- Add regression tests and `docs/agentic-browsing.md` for Lighthouse agentic-browsing audits
Closes#5. Also addresses overlap with #3 (sitemap + robots.txt).
## Test plan
- [x] `python manage.py test public.tests` (14 tests pass)
- [ ] Verify `GET /robots.txt`, `/sitemap.xml`, `/llms.txt` return 200 in staging/prod
- [ ] Confirm contact form labels visible and submittable on `/contact`
- [ ] Run Lighthouse `--only-categories=agentic-browsing` on homepage and contact page
- [ ] Smoke test mobile nav dropdown and cookie consent banner
Reviewed-on: #8