Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ data/
/logs/
.direnv/
.fake-backend-config.json
.vercel/
docs/_vendor/
*.local

# Python caches
Expand Down
3 changes: 2 additions & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ hugo server

The site will be available at `http://localhost:1313/docs/`.

To build the static site (outputting to `web-interface/public/docs` for the web portal):
To build the static site (outputting to `docs/public`, which Vite bundles into `web-interface/dist/docs`):

```bash
cd docs
Expand All @@ -35,6 +35,7 @@ Documentation source files are located in `content/`:
| [Testing](content/testing.md) | Automated tests and evidence runs |
| [Design system](content/design-system.md) | Portal design principles and components |
| [Frontend architecture](content/frontend-architecture.md) | UI layout and backend offloading plan |
| [Web & docs deployment](content/web-deployment.md) | Vercel build and multi-provider deployment guide |
| [Execution record](content/department-rollout-execution.md) | Department rollout status and validation |
| [Cleanup record](content/repository-cleanup.md) | Repository maintenance history |
| [Historical archive](content/archive/_index.md) | Archived previous-generation guides and plans |
28 changes: 28 additions & 0 deletions docs/agents/web-deployment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Web Interface and Documentation Deployment (Agent Reference)

This document outlines the deployment configuration for Mist's unified web presence (React SPA + Hugo static documentation).

## Core Architecture

- **Web interface**: Located in `web-interface/`. Built with Vite, React 19, Tailwind CSS 4, and TanStack Router.
- **Documentation site**: Located in `docs/`. Built with Hugo (Hextra theme) and Hugo Modules.
- **Combined target**: Both compile into `web-interface/dist/`. The web app resides at the root `/`, and documentation resides under `/docs/`.

## Vercel Target Setup

- **Root config**: `vercel.json` in repository root handles deployments where Vercel root is `.`.
- **Subpath config**: `web-interface/vercel.json` handles deployments where Vercel Root Directory is `web-interface`.
- **Prerequisites**: Hugo and Node.js/npm installed on the build environment with outgoing internet access.
- **Build command**: `npm run typecheck && npm run build` (or `npm --prefix web-interface ...`).
- **Rewrite rule**: `/((?!api(?:/|$)|auth(?:/|$)|docs(?:/|$)).*)` -> `/index.html`.
- **Redirect rule**: `/docs` -> `/docs/` (301 permanent).

## Switching Providers Requirements

When migrating to another static host or container platform:
1. Ensure Node.js >= 22 is available during build.
2. Publish `web-interface/dist`.
3. Route `/docs/*` directly to static files; DO NOT apply SPA fallback (`/index.html`) to `/docs/*`.
4. Redirect `/docs` to `/docs/`.
5. Point unmatched paths (excluding `/api`, `/auth`, `/docs`) to `/index.html` (HTTP 200).
6. Provide `VITE_API_URL` if Mist API is not served under the same origin.
1 change: 1 addition & 0 deletions docs/content/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ host-specific settings when provisioning another environment.
| Run automated checks and read recorded live evidence | [Testing](testing.md) |
| Maintain UI components and interactions | [Design system](design-system.md) |
| Understand frontend architecture and backend offloading | [Frontend architecture](frontend-architecture.md) |
| Deploy web portal and documentation (Vercel and other hosts) | [Web & docs deployment](web-deployment.md) |
| Read completed scope, exclusions and release verification | [Execution record](department-rollout-execution.md) |
| See what repository cleanup removed and verified | [Cleanup record](repository-cleanup.md) |

Expand Down
277 changes: 277 additions & 0 deletions docs/content/web-deployment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
---
title: "Web & Docs Deployment"
weight: 95
---

# Web interface and documentation deployment

Mist serves a unified static web footprint:
1. **Web portal**: A React 19 single-page application (SPA) built with Vite and TanStack Router, located in [`web-interface`](../../web-interface).
2. **Documentation site**: A static site built with Hugo and the Hextra theme, located in [`docs`](../../docs).

In production, both artifacts are compiled into a single output directory (`web-interface/dist`), where the web portal is served at `/` and the documentation site is served at `/docs/`.

---

## Unified build pipeline

The build pipeline combines the Vite application and Hugo documentation into one publishable distribution.

```mermaid
flowchart LR
A["web-interface (Vite / React 19)"] -->|"npm run build"| C["Unified Output: web-interface/dist/"]
B["docs/ (Hugo / Hextra)"] -->|"hugo -s ../docs"| D["docs/public/"]
D -->|"Vite closeBundle cp"| C
C --> E["Vercel Edge Network / Static Host"]
```

### Build prerequisites

- **Node.js & npm**: Node.js version 22.16.0 or newer with npm installed.
- **Hugo**: A standard Hugo (Extended) installation accessible in `PATH`.
- **Internet access**: Enabled during build for downloading npm dependencies and Hugo modules (such as Hextra).

### Local build execution

From the repository root:

```bash
npm --prefix web-interface ci
npm --prefix web-interface run typecheck
npm --prefix web-interface run build
```

Or from inside `web-interface`:

```bash
cd web-interface
npm ci
npm run typecheck
npm run build
```

The output is generated in `web-interface/dist`:
- `dist/index.html`: Web portal entrypoint and SPA assets in `dist/assets/`.
- `dist/docs/`: Hugo documentation static site with `dist/docs/index.html` and subpages.

---

## Deploying on Vercel

The repository includes preconfigured Vercel configuration files supporting either deployment mode.

### Option 1: Root directory set to `web-interface` (Recommended)

When connecting the GitHub repository to Vercel, set the **Root Directory** project setting to `web-interface`.

Vercel reads `web-interface/vercel.json`:

```json
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"framework": "vite",
"installCommand": "npm ci",
"buildCommand": "npm run typecheck && npm run build",
"outputDirectory": "dist",
"redirects": [
{
"source": "/docs",
"destination": "/docs/",
"permanent": true
}
],
"rewrites": [
{
"source": "/((?!api(?:/|$)|auth(?:/|$)|docs(?:/|$)).*)",
"destination": "/index.html"
}
]
}
```

### Option 2: Root directory set to repository root (`.`)

When leaving **Root Directory** as default (`.`), Vercel reads the root `vercel.json`:

```json
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"framework": "vite",
"installCommand": "npm --prefix web-interface ci",
"buildCommand": "npm --prefix web-interface run typecheck && npm --prefix web-interface run build",
"outputDirectory": "web-interface/dist",
"redirects": [
{
"source": "/docs",
"destination": "/docs/",
"permanent": true
}
],
"rewrites": [
{
"source": "/((?!api(?:/|$)|auth(?:/|$)|docs(?:/|$)).*)",
"destination": "/index.html"
}
]
}
```

### Routing and redirect behavior

1. **SPA Fallback Exclusion**: The rewrite regex `((?!api(?:/|$)|auth(?:/|$)|docs(?:/|$)).*)` routes client-side application paths (like `/jobs`, `/dashboard`, `/teams`) to `/index.html`. It explicitly excludes `/api`, `/auth`, and `/docs/`.
2. **Docs trailing slash redirect**: Hugo generates directory-based HTML structures (`docs/k3s-setup/index.html`). Requesting `/docs` is permanently redirected (HTTP 301) to `/docs/` to maintain relative asset resolution.
3. **Static docs serving**: Requests starting with `/docs/` resolve directly to files in `dist/docs/`.

---

## Backend connectivity

The frontend connects to the backend API (`/api`) and authentication endpoints (`/auth`).

### Environment variable `VITE_API_URL`

If the backend API is hosted on an external domain (e.g. `https://api.mist.example.com`), configure `VITE_API_URL` in the hosting provider's build environment:

```bash
VITE_API_URL="https://api.mist.example.com"
```

Vite inlines this variable into the compiled bundle during `npm run build`.

### Fallback connection screen

If the backend service is offline, unreachable, or in cold-start, the frontend displays an interactive connection error screen (`BackendConnectionError.tsx`) with a retry button and links directly to `/docs/` for operational troubleshooting.

---

## Switching to another hosting provider

To migrate from Vercel to another static hosting provider or container environment, adhere to the four platform requirements below.

### Platform requirements checklist

1. **Build environment**: The host must have Node.js (>= 22.16.0), npm, and Hugo installed, with network access to fetch npm dependencies and Hugo modules.
2. **Publish directory**: Point the publish directory to `web-interface/dist` (or `dist` if build root is `web-interface`).
3. **Docs path passthrough**: Requests to `/docs/*` must serve static files directly and must **not** be rewritten to `/index.html`.
4. **SPA routing fallback**: Unmatched routes (excluding `/api`, `/auth`, and `/docs`) must fall back to `/index.html` with HTTP status 200.
5. **Trailing slash on docs**: `/docs` must redirect to `/docs/`.

---

### Cloudflare Pages

1. **Project settings**:
- Framework preset: `None`
- Build command: `npm run build`
- Build output directory: `dist`
- Root directory: `web-interface`

2. **Redirects and routing (`web-interface/public/_redirects`)**:
Create `_redirects` inside `web-interface/public/` (copied to `dist/` on build):

```text
/docs /docs/ 301
/docs/* /docs/:splat 200
/* /index.html 200
```

---

### Netlify

Create `netlify.toml` in the repository root or `web-interface/`:

```toml
[build]
base = "web-interface"
publish = "dist"
command = "npm run typecheck && npm run build"

[[redirects]]
from = "/docs"
to = "/docs/"
status = 301
force = true

[[redirects]]
from = "/docs/*"
to = "/docs/:splat"
status = 200

[[redirects]]
from = "/*"
to = "/index.html"
status = 200
```

---

### Self-hosted Nginx or Docker

A production Dockerfile builds both artifacts and serves them via Nginx:

```dockerfile
# Build stage
FROM node:22-alpine AS builder
RUN apk add --no-cache hugo git
WORKDIR /app
COPY . .
RUN cd web-interface && npm ci && npm run typecheck && npm run build

# Runtime stage
FROM nginx:alpine
COPY --from=builder /app/web-interface/dist /usr/share/nginx/html
COPY deploy/nginx-portal.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
```

Corresponding Nginx configuration (`nginx-portal.conf`):

```nginx
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;

# Canonical docs trailing slash
location = /docs {
return 301 /docs/;
}

# Static Hugo documentation
location /docs/ {
try_files $uri $uri/ =404;
}

# Backend API proxy
location /api/ {
proxy_pass http://mist-api:3000/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}

# Backend Auth proxy
location /auth/ {
proxy_pass http://mist-api:3000/auth/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}

# SPA history fallback
location / {
try_files $uri $uri/ /index.html;
}
}
```

---

### AWS S3 + CloudFront

1. **S3 Bucket**: Upload the contents of `web-interface/dist` to an S3 bucket configured for static website hosting or Origin Access Control (OAC).
2. **CloudFront Behaviors**:
- **Default (`*`)**: Points to S3 origin. Custom error response: HTTP 404/403 maps to `/index.html` with HTTP 200.
- **Path Pattern `/docs/*`**: Points to S3 origin. Do not rewrite 404 to `/index.html`; allow standard S3 404 or Hugo 404.
- **CloudFront Function / Lambda@Edge for `/docs`**: Redirects `/docs` to `/docs/` and appends `index.html` to directory subpaths.
20 changes: 20 additions & 0 deletions vercel.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"framework": "vite",
"installCommand": "npm --prefix web-interface ci",
"buildCommand": "npm --prefix web-interface run typecheck && npm --prefix web-interface run build",
"outputDirectory": "web-interface/dist",
"redirects": [
{
"source": "/docs",
"destination": "/docs/",
"permanent": true
}
],
"rewrites": [
{
"source": "/((?!api(?:/|$)|auth(?:/|$)|docs(?:/|$)).*)",
"destination": "/index.html"
}
]
}
11 changes: 10 additions & 1 deletion web-interface/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,20 @@ not live utilization. Inputs are read-only; save results in `/outputs`.
The old fake account helpers/chart and unused `use-immer` dependency are retired.
Current behavior and components follow [the design system](../docs/content/design-system.md).

## Deployment

Production and preview environments can be deployed to **Vercel** or any static hosting provider. The build compiles both the React SPA (served at `/`) and the Hugo documentation (served at `/docs/`) into `web-interface/dist`.

- **Vercel build**: Configured via `vercel.json` (at repo root and `web-interface/vercel.json`).
- **Dependencies**: Requires Node.js/npm and Hugo installed on the host with internet access for npm packages and Hugo modules.
- **API Target**: Set `VITE_API_URL` to point to the remote Mist API if not on the same origin.
- See the [Web & Docs deployment guide](../docs/content/web-deployment.md) for full Vercel settings and instructions for switching to Cloudflare Pages, Netlify, Nginx/Docker, or AWS S3.

## Verify

```bash
npm test
npx tsc --noEmit
npm run typecheck
npm run lint
npm run build
```
Expand Down
Loading
Loading