Files
landing/README.md
mifi 27808cfd0e
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
Tweaks, fixes, etc
2026-02-13 18:12:52 -03:00

163 lines
7.6 KiB
Markdown
Raw Permalink 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.
# mifi.holdings — Landing Page
Static landing site for **mifi.holdings** (and www). Plain HTML/CSS/JS source; a **build step** produces minified assets and inlines critical CSS. Served by **nginx** in Docker behind **Traefik**, with CI/CD via **Woodpecker** and deployment via **Portainer**.
---
## Quick reference
| What | Where |
| ----------------------- | -------------------------------------------- |
| **Site** | `mifi.holdings`, `www.mifi.holdings` (HTTPS) |
| **Runtime** | nginx (Alpine) in Docker |
| **Reverse proxy / TLS** | Traefik (Let's Encrypt) |
| **CI/CD** | Woodpecker (ci → build → deploy) |
| **Registry** | `git.mifi.dev/mifi-holdings/landing` |
| **Package manager** | pnpm |
| **Build output** | `dist/` (gitignored) |
---
## Architecture
```
┌─────────────────┐
│ Traefik │ (routing, TLS, websecure)
└────────┬────────┘
┌────────▼────────┐
│ Docker container │ mifi-holdings-landing
│ nginx:alpine │ port 80
│ /usr/share/ │
│ nginx/html ← │ built output from dist/
└─────────────────┘
```
- **Build**: `pnpm build` copies `src/``dist/`, minifies JS/CSS, inlines critical CSS (Critters). Docker image = `nginx:alpine` + `nginx/conf.d/` + **`dist/`** into `/usr/share/nginx/html`.
- **Run**: Single service on external network `marina-net`; Traefik routes `mifi.holdings` and `www.mifi.holdings` to this container (HTTPS, `security-prison@file` middleware).
---
## Repo structure
```
.
├── src/ # Source (HTML, CSS, JS)
│ ├── index.html
│ └── assets/
│ ├── css/style.css
│ ├── js/ga-init.js
│ └── images/ # favicon, etc.
├── scripts/
│ └── build.js # Build: copy, minify, inline critical CSS
├── dist/ # Build output (gitignored)
├── nginx/
│ └── conf.d/
│ └── default.conf # nginx server config (cache rules, SPA fallback)
├── .woodpecker/
│ ├── ci.yml # Lint, format, build check (PR + push to main)
│ ├── build.yml # Site build → Docker image → push (main)
│ └── deploy.yml # Trigger Portainer redeploy (main)
├── docker-compose.yml # Service + Traefik labels for production
├── Dockerfile # nginx + config + dist (not src)
├── package.json # pnpm scripts: build, format, lint, docker
└── README.md
```
---
## Build (pnpm build)
- **Output**: `dist/` (gitignored). Do not edit `dist/`; it is generated.
- **Steps** (see `scripts/build.js`):
1. Clean and copy `src/``dist/`.
2. Minify all `.js` (terser) and `.css` (clean-css).
3. Inline critical CSS with **Critters** (lazy-loads the rest; no browser required, so it works in CI).
- **When**: Run before `docker build`. CI and the build pipeline both run `pnpm build` before packaging.
---
## Tech stack
- **Frontend**: Static HTML + CSS + JS in `src/`; production build minifies and inlines critical CSS.
- **Server**: nginx (Alpine) in Docker.
- **Tooling**: **pnpm**; Prettier (format); ESLint (JS), Stylelint (CSS), yamllint (YAML); **terser**, **clean-css**, **beasties** (build).
- **Deployment**: Docker image (from `dist/`) → Gitea registry → Portainer stack redeploy.
---
## Local development
- **Dependencies**: `pnpm install`.
- **Format**: `pnpm format` / `pnpm format:check`.
- **Lint**: `pnpm lint` (ESLint for `src/**/*.js`, Stylelint for `src/**/*.css`, yamllint for Woodpecker + docker-compose). Use `pnpm lint:fix` to auto-fix where supported.
- **Build**: `pnpm build` → produces `dist/`. Required before building the Docker image.
- **Run locally (Docker)**:
- Build site: `pnpm build`.
- Image: `pnpm docker:build` (or `docker build --platform linux/amd64 -t git.mifi.dev/mifi-holdings/landing:latest .`).
- Run: use `docker-compose up` **only** on a host that has `marina-net` and Traefik; otherwise run the image with a port map and open `http://localhost:<port>`.
No dev server; edit `src/` and run `pnpm build` (and optionally `docker run` or a local static server on `dist/`) to test.
---
## Docker
- **Dockerfile**: Copies `nginx/conf.d/` and **`dist/`** (not `src/`) into an `nginx:alpine` image. Run `pnpm build` first so `dist/` exists.
- **Image**: Tagged as `git.mifi.dev/mifi-holdings/landing:latest` (and `:<commit-sha>` in CI).
- **Local build/push**: `pnpm build``pnpm docker:build``pnpm docker:push` (requires login to `git.mifi.dev`).
---
## CI/CD (Woodpecker)
Three pipelines:
1. **ci** (`.woodpecker/ci.yml`)
- **When**: Every PR and every push to `main`.
- **Steps**: Install deps → Prettier format check → lint (ESLint, Stylelint, yamllint) → **Build** (`pnpm build`). Mattermost notifications on success/failure.
2. **build** (`.woodpecker/build.yml`)
- **When**: Push/tag/manual on `main` (and deployment to production); **depends_on: ci**.
- **Steps**: **Site build** (`pnpm install`, `pnpm build`) → Docker image build (linux/amd64, up to 3 retries) → push `:latest` and `:<CI_COMMIT_SHA>` to `git.mifi.dev/mifi-holdings/landing`. Mattermost notifications.
3. **deploy** (`.woodpecker/deploy.yml`)
- **When**: Same as build (main / production deploy); **depends_on: ci**.
- **Steps**: Call Portainer webhook to redeploy the stack. Mattermost notifications.
Secrets used: `gitea_registry_username`, `gitea_package_token`, `portainer_webhook_url`, `mattermost_*` (bot token, channel IDs, API URL).
---
## Deployment (production)
- **Orchestration**: Stack defined in `docker-compose.yml`, deployed via **Portainer** (webhook triggered by Woodpecker deploy pipeline).
- **Network**: Container joins external network `marina-net` (shared with Traefik).
- **Traefik**:
- Hosts: `mifi.holdings`, `www.mifi.holdings`.
- Entrypoint: `websecure` (HTTPS).
- TLS: Let's Encrypt (`tls.certresolver=letsencrypt`).
- Middleware: `security-prison@file`.
- Backend: this service, port 80.
- **Healthcheck**: `wget --spider -q http://localhost/` every 20s (timeout 3s, 3 retries).
To deploy manually: pull the latest image and redeploy the stack in Portainer, or trigger the Portainer webhook (e.g. same URL as in `portainer_webhook_url`).
---
## nginx behavior
- **Root**: `/usr/share/nginx/html` (contents of **`dist/`** after build).
- **HTML**: `Cache-Control: public, no-cache` so updates are visible quickly.
- **JS/CSS**: Long cache, `immutable` for hashed/versioned assets.
- **Images/fonts**: Cached (30d / 1y).
- **SPA-style fallback**: `/` tries `$uri`, `$uri/`, then `index.html`, then 404.
---
## Summary
- **What it is**: Static landing for mifi.holdings; source in `src/`, built output in `dist/`.
- **How it runs**: nginx in Docker serving `dist/`, fronted by Traefik on `marina-net`.
- **How its updated**: Push to `main` → Woodpecker runs ci (lint, format, **build**), then build pipeline (**site build** → Docker image → push), then deploy (Portainer webhook); Mattermost reports status.