# Lean 101 Website Plain static HTML site with a small Python (Flask) backend for the contact form. ## Layout ``` index.html # Home (includes contact form at #contact) services/ # coaching, consulting, digital-solutions pages resources/ # resources index assets/ # logos app.py # Flask app: serves the site + /api/contact (Resend) requirements.txt .env.example # copy to .env and fill in (local dev) Dockerfile # python:3.12-slim + gunicorn docker-compose.yml # single service: lean101, attaches to shared nginx network deploy.env.template # synced to server .env by deploy.sh (live values win) deploy.sh # remote deploy: git clone + compose up + nginx + maintenance ``` ## Local development ```bash python -m venv .venv .venv\Scripts\activate # Windows # source .venv/bin/activate # macOS/Linux pip install -r requirements.txt copy .env.example .env # then edit .env with your Resend key python app.py ``` Site at http://127.0.0.1:5000 ## Contact form - Form is on the home page in the `#contact` section. - Submits to `POST /api/contact` (JSON response). - Server sends the email via [Resend](https://resend.com). Configure: - `RESEND_API_KEY` — your Resend API key. - `CONTACT_TO` — where enquiries are sent. - `CONTACT_FROM` — must be on a domain you've verified in Resend. - Honeypot field (`website`) silently drops bots. The "Let's Talk" buttons on service pages link back to the home `#contact` section, where the real form lives. ## Deployment `Deploy.ps1` runs from your laptop. It tars the repo, scps it to the droplet, and runs `docker compose up --build` over SSH. Host nginx on the droplet terminates TLS for `www.lean-101.com.au` and proxies to `127.0.0.1:WEBSITE_APP_PORT` (default 8083) where this container binds. First deploy: ```powershell copy .env.production.example .env.production # then edit and set RESEND_API_KEY ./Deploy.ps1 -RemoteHost ``` Subsequent deploys: same command. Add `-Logs` to tail logs after, `-SkipBuild` if only the env changed. ### Cutover (first deploy only) The script deploys to `/srv/lean-101-website-flask` with container `lean101-website-flask` on port 8083, deliberately leaving the old SvelteKit container (`/srv/lean101-website`, port 8091) running. After verifying the new container is healthy, swap the nginx vhost on the droplet: ```bash ssh root@ sed -i.bak 's|proxy_pass http://127.0.0.1:8091;|proxy_pass http://127.0.0.1:8083;|' \ /etc/nginx/sites-enabled/lean-101.com.au nginx -t && systemctl reload nginx curl -I https://www.lean-101.com.au/ # should hit the new Flask container # Once happy, retire the old stack: cd /srv/lean101-website && docker compose down ``` Rollback: `mv /etc/nginx/sites-enabled/lean-101.com.au.bak /etc/nginx/sites-enabled/lean-101.com.au && nginx -s reload`. ### Coexistence with the clients app The droplet runs host nginx → localhost ports → docker containers. The clients app at `clients.lean-101.com.au` proxies to `127.0.0.1:8082`, this site to `127.0.0.1:8083`. Each app has its own compose project and bridge network; they don't share anything. ## Notes - The SvelteKit + Mongo stack was removed in favour of plain HTML so edits land directly. If you need anything from the prior stack, recover it from git history before this commit. - During the restructure the v3.11 service pages were lost (they were never committed) and restored from the older `html-v3` versions in HEAD. The v3.11 service-page tweaks (e.g. CTA copy rebranded to "Let's Talk") will need to be re-applied.