Files
mail-landing/README.md
mifi 6bef0f8254
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/build Pipeline was successful
ci/woodpecker/push/deploy Pipeline was successful
Updates to readme
2026-02-13 18:19:29 -03:00

130 lines
8.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# mail-landing
Static landing site for **mail.mifi.holdings** (HTML/CSS/JS). Source lives in `src/`, is built to `dist/`, and is served in production by **nginx** inside a Docker container, with **Traefik** as the reverse proxy.
---
## Tech stack & frameworks
| Layer | Technology |
| --------------------- | -------------------------------------------------------------------------------------- |
| **Runtime** | Node 22 (dev/build only); production is static files only |
| **Package manager** | pnpm 10.x |
| **Source** | Plain HTML, CSS, JS — no framework (Vite/React/etc.) |
| **Build** | Custom script (`scripts/build.js`): copy, minify, inline critical CSS |
| **Minification** | **Terser** (JS), **clean-css** (CSS) |
| **Critical CSS** | **Beasties** — inlines above-the-fold CSS into HTML (no browser/headless; works in CI) |
| **Lint / format** | ESLint, Stylelint, Prettier, yamllint (for Woodpecker & compose) |
| **Production server** | nginx (Alpine) in Docker |
| **Reverse proxy** | Traefik (via `docker-compose` labels; TLS, gzip, security middlewares) |
| **CI/CD** | Woodpecker CI (Gitea); images pushed to `git.mifi.dev` registry |
---
## Project structure
```
mail-landing/
├── src/ # Source (edited by hand)
│ ├── index.html
│ ├── help/index.html
│ └── assets/
│ ├── css/site.css
│ ├── js/ga-init.js
│ └── images/favicon.svg
├── dist/ # Build output (gitignored in practice; produced by pnpm build)
├── scripts/
│ └── build.js # Build: copy → minify JS/CSS → Beasties inline critical CSS
├── nginx/conf.d/ # nginx config for the container
├── docker-compose.yml # Service definition + Traefik labels for mail.mifi.holdings
├── Dockerfile # nginx:alpine + config + dist/
├── .woodpecker/
│ ├── ci.yml # Lint, format check, build (PR + push to main)
│ ├── build.yml # Build site → Docker image → push to registry
│ └── deploy.yml # Trigger Portainer webhook + Mattermost notifications
├── .devcontainer/ # Dev Container (Node 22 + pnpm) for Cursor/VS Code
└── package.json
```
---
## Architecture (high level)
1. **Develop** in `src/` (HTML/CSS/JS). No bundler; structure mirrors output.
2. **Build** (`pnpm build`): `src/``dist/` (copy, minify JS/CSS, inline critical CSS via Beasties).
3. **Docker image**: `Dockerfile` copies `nginx/conf.d/` and `dist/` into `nginx:alpine`; no Node in the image.
4. **Run**: Container serves `/usr/share/nginx/html` on port 80. Traefik (external) terminates TLS for `mail.mifi.holdings`, applies gzip and security middlewares, and routes to this service on `marina-net`.
5. **Deploy**: Woodpecker runs **ci****build** (site + image + push) → **deploy** (Portainer webhook redeploy + Mattermost).
---
## Local development (Dev Container)
1. **Open in Dev Container**
In Cursor/VS Code: **Command Palette****Dev Containers: Reopen in Container** (or **Clone Repository in Container Volume** when opening the repo).
First time: builds the container (Node 22 + pnpm), runs `pnpm install`.
2. **Preview the site**
In the container terminal:
- **Quick preview** (serves `src/` as-is, no build):
`pnpm preview`
- **Production-like** (build then serve `dist/`):
`pnpm preview:prod`
Port **3000** is forwarded; open **http://localhost:3000** (or use the “Preview” port notification).
3. **Other commands**
- `pnpm build` — build `src/``dist/` (minify JS/CSS, inline critical CSS)
- `pnpm lint` / `pnpm format` — lint and format
- `pnpm docker:build` — build production image (for local testing; image: `git.mifi.dev/mifi-holdings/mail-landing:latest`)
---
## Build pipeline (what `pnpm build` does)
1. **Clean & copy**`dist/` is removed; `src/` is copied recursively to `dist/`.
2. **Minify JS** — All `.js` files in `dist/` are minified with Terser (no comments).
3. **Minify CSS** — All `.css` files are minified with clean-css (level 2).
4. **Inline critical CSS** — Beasties runs on every `.html` file in `dist/` (default preload behavior; no headless browser).
Output: `dist/` ready to be served or copied into the Docker image.
---
## Deployment (Woodpecker CI/CD)
Pipelines live under `.woodpecker/`. Execution order:
| Pipeline | When | What |
| ------------------------- | ------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **ci** (`ci.yml`) | Every PR and every push to `main` | Install → Prettier check → Lint (JS, CSS, YAML) → Build. Mattermost notifications on failure/success. |
| **build** (`build.yml`) | Push/tag/manual on `main`, or deployment event for production | Depends on **ci**. Site build → Docker image build (linux/amd64, tagged with commit SHA + `latest`) → Push to `git.mifi.dev/mifi-holdings/mail-landing`. Mattermost on success/failure. |
| **deploy** (`deploy.yml`) | Same as build (runs after build) | `skip_clone: true`; triggers Portainer webhook to redeploy the stack. Mattermost deploy success/failure. |
**Secrets** (in Woodpecker): `portainer_webhook_url`, `mattermost_*`, `gitea_registry_username`, `gitea_package_token`.
**Production**: Stack is defined in Portainer (using this repos `docker-compose.yml`). Redeploy pulls `git.mifi.dev/mifi-holdings/mail-landing:latest` and restarts the service. Traefik (on `marina-net`) routes `mail.mifi.holdings` to this container with TLS (e.g. Lets Encrypt) and middlewares (gzip, security).
---
## Production runtime (Docker + Traefik)
- **Image**: `git.mifi.dev/mifi-holdings/mail-landing:latest` (nginx:alpine + `nginx/conf.d/` + `dist/`).
- **Compose**: `docker-compose.yml` defines one service, `marina-net`, Traefik labels for `Host(\`mail.mifi.holdings\`)`, TLS, gzip, and security middlewares; healthcheck via `wget`on`/`.
- **nginx**: Serves `/usr/share/nginx/html`; HTML no-cache, JS/CSS long-lived cache; static assets and directory/index handling as in `nginx/conf.d/default.conf`.
---
## Quick reference (pnpm scripts)
| Command | Description |
| ------------------- | ---------------------------------------------- |
| `pnpm build` | Build `src/``dist/` (minify + critical CSS) |
| `pnpm preview` | Serve `src/` on port 3000 (no build) |
| `pnpm preview:prod` | Build then serve `dist/` on 3000 |
| `pnpm lint` | Lint JS, CSS, and Woodpecker/compose YAML |
| `pnpm lint:fix` | Auto-fix lint where supported |
| `pnpm format` | Prettier write |
| `pnpm format:check` | Prettier check only |
| `pnpm docker:build` | Build Docker image (linux/amd64) |
| `pnpm docker:push` | Push image to registry (manual) |