html vers, deploy
This commit is contained in:
@@ -1,165 +1,83 @@
|
||||
# Lean 101 Website
|
||||
|
||||
This repo runs as a server-rendered SvelteKit app with a custom Mongo-backed CMS at `/admin`.
|
||||
Plain static HTML site with a small Python (Flask) backend for the contact form.
|
||||
|
||||
## Stack
|
||||
## Layout
|
||||
|
||||
- `SvelteKit`
|
||||
- `@sveltejs/adapter-node`
|
||||
- `MongoDB` via the native `mongodb` driver
|
||||
- `docker compose` for local and server runtime
|
||||
|
||||
## What changed
|
||||
|
||||
- The public site now reads page content from MongoDB when `MONGODB_URI` and `MONGODB_DB` are set.
|
||||
- If MongoDB is not configured, the homepage falls back to the local seed file at `src/lib/content/homepage.json`.
|
||||
- `/admin` is a custom password-protected editor for:
|
||||
- pages
|
||||
- movable page sections
|
||||
- blog posts
|
||||
- The homepage seed is automatically migrated into the `site_pages` collection the first time the app connects to MongoDB.
|
||||
|
||||
## Project layout
|
||||
|
||||
```text
|
||||
.
|
||||
├── Dockerfile
|
||||
├── docker-compose.yml
|
||||
├── package.json
|
||||
├── scripts/
|
||||
│ └── deploy-do.sh
|
||||
├── src/
|
||||
│ ├── app.css
|
||||
│ ├── app.html
|
||||
│ ├── lib/
|
||||
│ │ ├── content/homepage.json
|
||||
│ │ ├── components/SitePage.svelte
|
||||
│ │ ├── server/auth.js
|
||||
│ │ ├── server/content.js
|
||||
│ │ └── site.js
|
||||
│ └── routes/
|
||||
│ ├── +layout.js
|
||||
│ ├── +page.server.js
|
||||
│ ├── +page.svelte
|
||||
│ ├── [slug]/+page.server.js
|
||||
│ ├── [slug]/+page.svelte
|
||||
│ ├── admin/+page.server.js
|
||||
│ ├── admin/+page.svelte
|
||||
│ ├── blog/+page.server.js
|
||||
│ ├── blog/+page.svelte
|
||||
│ ├── blog/[slug]/+page.server.js
|
||||
│ ├── blog/[slug]/+page.svelte
|
||||
│ ├── robots.txt/+server.js
|
||||
│ └── sitemap.xml/+server.js
|
||||
└── static/assets/
|
||||
├── lean101-isotipo.png
|
||||
└── lean101-logotipo.png
|
||||
```
|
||||
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
|
||||
```
|
||||
|
||||
## Environment variables
|
||||
|
||||
Required for the CMS:
|
||||
|
||||
- `MONGODB_URI`
|
||||
- `MONGODB_DB`
|
||||
- `ADMIN_PASSWORD`
|
||||
- `ADMIN_SESSION_SECRET`
|
||||
|
||||
Required for correct canonical/meta URLs:
|
||||
|
||||
- `PUBLIC_SITE_URL`
|
||||
|
||||
Example `.env`:
|
||||
|
||||
```env
|
||||
PUBLIC_SITE_URL=http://localhost:8080
|
||||
MONGODB_URI=mongodb://localhost:27017
|
||||
MONGODB_DB=lean101
|
||||
ADMIN_PASSWORD=replace-this
|
||||
ADMIN_SESSION_SECRET=replace-this-with-a-long-random-string
|
||||
```
|
||||
|
||||
## Run locally with Docker
|
||||
## Local development
|
||||
|
||||
```bash
|
||||
docker compose up --build
|
||||
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
|
||||
```
|
||||
|
||||
The site will be available at `http://localhost:8080`.
|
||||
Site at http://127.0.0.1:5000
|
||||
|
||||
The app server listens on port `3000` inside the container and is mapped to `8080` on the host.
|
||||
## Contact form
|
||||
|
||||
## Run locally without Docker
|
||||
- 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 <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:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run dev
|
||||
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
|
||||
```
|
||||
|
||||
The Vite dev server will run on its normal local port, usually `http://localhost:5173`.
|
||||
Rollback: `mv /etc/nginx/sites-enabled/lean-101.com.au.bak /etc/nginx/sites-enabled/lean-101.com.au && nginx -s reload`.
|
||||
|
||||
## Production build
|
||||
### Coexistence with the clients app
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
npm run preview
|
||||
```
|
||||
|
||||
`npm run preview` now runs the built Node server with `node build`.
|
||||
|
||||
## Custom CMS
|
||||
|
||||
Visit `/admin`.
|
||||
|
||||
The CMS is intentionally simple, but it now supports structured content:
|
||||
|
||||
- one password
|
||||
- multiple pages
|
||||
- reorderable sections within each page
|
||||
- blog drafts and published posts
|
||||
|
||||
Current collections:
|
||||
|
||||
- `site_pages`
|
||||
- `blog_posts`
|
||||
|
||||
Current section types:
|
||||
|
||||
- `hero`
|
||||
- `services`
|
||||
- `process`
|
||||
- `outcomes`
|
||||
- `why`
|
||||
- `richText`
|
||||
- `cta`
|
||||
|
||||
Published blog posts are available under `/blog`, and individual pages are available at `/<slug>`.
|
||||
|
||||
## DigitalOcean deployment script
|
||||
|
||||
After copying this project folder onto a droplet, you can run:
|
||||
|
||||
```bash
|
||||
sudo ./scripts/deploy-do.sh --domain yourdomain.com --email you@example.com --with-www
|
||||
```
|
||||
|
||||
The script:
|
||||
|
||||
- installs Docker, the compose plugin, nginx, and certbot
|
||||
- writes `.env` with `PUBLIC_SITE_URL=https://yourdomain.com`
|
||||
- starts the compose stack
|
||||
- configures system nginx to reverse proxy to the Docker app on `127.0.0.1:8080`
|
||||
- requests and installs a Let's Encrypt certificate if `--email` is provided
|
||||
|
||||
If you use the CMS in production, make sure the `.env` file on the server also includes:
|
||||
|
||||
- `MONGODB_URI`
|
||||
- `MONGODB_DB`
|
||||
- `ADMIN_PASSWORD`
|
||||
- `ADMIN_SESSION_SECRET`
|
||||
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 current contact CTA still uses `mailto:hello@lean-101.com`
|
||||
- The seed homepage remains in `src/lib/content/homepage.json`
|
||||
- Live page and blog content is stored in MongoDB once the database env vars are configured
|
||||
- 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.
|
||||
|
||||
Reference in New Issue
Block a user