2026-05-17 22:45:45 +12:00
2026-05-06 22:38:06 +12:00
2026-05-17 22:45:45 +12:00
2026-05-17 22:45:45 +12:00
2026-05-17 22:45:45 +12:00
2026-05-17 22:45:45 +12:00
2026-05-17 22:45:45 +12:00
2026-05-17 22:45:45 +12:00
2026-05-17 22:45:45 +12:00
2026-05-17 22:45:45 +12:00
2026-05-17 22:45:45 +12:00
2026-05-17 22:45:45 +12:00
2026-05-17 22:45:45 +12:00
2026-05-17 22:45:45 +12:00
2026-05-17 22:45:45 +12:00

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

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. 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:

copy .env.production.example .env.production    # then edit and set RESEND_API_KEY
./Deploy.ps1 -RemoteHost <droplet-ip>

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:

ssh root@<droplet>
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.
S
Description
No description provided
Readme
370 KiB
Languages
HTML 97.2%
PowerShell 2.4%
Python 0.4%