# Queue North Website

```
Status: Current
Owner: _null
Last reviewed: 2026-08-18
Governs: package.json, src/routes.jsx, Dockerfile, docker-compose.yml — the
         project-facing overview, whose stack, route list and Docker story
         all describe those files
Review trigger: Any change to the stack, the route list, the Docker or
                deployment story, the agent pipeline, or where a document lives
```

The business website for Queue North Technologies — an 8x8 Certified Partner
delivering UCaaS, contact centre, networking and managed support for SMB and
enterprise organisations. Live at
**[queuenorth.com](https://queuenorth.com)**, with
[qn.isnull.dev](https://qn.isnull.dev) reaching the same container through a
second ingress.

## Objective

Queue North Website is the modern rebuild of the Queue North Technologies business website.

The goal is to replace the current static early-2000s-style HTML/CSS/JS site with a polished 2026 business website that clearly presents Queue North as a trustworthy communications, contact center, networking, and managed support partner.

The site should feel:

- Bright and professional
- Modern but not flashy
- Business-first, not cyber/gaming/crypto
- Easy to navigate
- Clear about Queue North's 8x8 partnership and service expertise
- Optimized for consultation and support request conversion

## Target Stack

- **Vite** — build tool, not Next.js
- **React** — SPA frontend
- **React Router** — client-side routing
- **Tailwind CSS** — utility-first styling
- **shadcn/ui** — component primitives
- **Sonner** — toast notifications
- **TanStack Query** — server state management
- **Express** — backend API
- **better-sqlite3** — SQLite database

## Layout Direction

The design direction is a light-first B2B technology layout with strategic dark navy sections.

Primary structure:

1. **Hero**
   - Dark navy section
   - Clear headline and value proposition
   - Primary CTA: `Request Consultation`
   - Secondary CTA: `Explore Services`
   - Trust chips: 8x8 Certified Partner, Veteran Owned, 25+ Years Experience, SMB to Enterprise

2. **Trust / Certification Bar**
   - Light section
   - Reinforces 8x8 partner credibility

3. **Services Preview**
   - White cards on a bright background
   - Concise service explanations
   - Links to service detail pages

4. **Why Queue North**
   - Three-pillar section:
     - Architecture
     - Deployment
     - Lifecycle Support

5. **Industries**
   - Healthcare
   - Retail
   - Manufacturing
   - Education & Finance

6. **Final CTA**
   - Dark navy conversion band
   - Consultation-focused message

## Routes

```txt
/                              Home
/about                         About
/services                      Services index
/services/:slug                7 service detail pages
/industries                    Industries index
/industries/:slug              4 industry detail pages
/contact                       Contact form  → POST /api/leads
/support                       Support form  → POST /api/support
/privacy-policy                Privacy policy
*                              404
```

Defined in `src/routes.jsx`. **Every one of them is prerendered to static HTML at
build time** by `scripts/prerender.js` — the SPA hydrates on top. `/privacy-policy`
additionally has a server-rendered fallback because Meta's crawler does not run
JavaScript.

The standalone `/8x8` route was removed at `0.6.6`; that content now lives inside
the UCaaS and contact-centre service pages.

## Where the work is

**Open work lives in the issue tracker, not in this file.** Milestones are
batches, issues are deliverables. There used to be a phase checklist here and in
four other documents; by the time it was removed it said *"Phase 5 — In
Progress"* while the last four commits said *batch 0.9.3*. That is the second
record this convention exists to remove.

- **What is left, and what is next:** the milestones at
  [dream.scheller.ltd/null/Queue-North-Website](https://dream.scheller.ltd/null/Queue-North-Website/milestones)
- **What is broken:** issues labelled `P0`, `P1`, `P2`
- **What the batches were, before the tracker held them:**
  [docs/history/BATCH_LEDGER.md](docs/history/BATCH_LEDGER.md)

The rebuild itself is done: phases 1 through 10 completed between May and August
2026, from the original static HTML site to the current Vite + React SPA with a
prerendered build. `docs/history/DEVELOPMENT_LOG.md` has it version by version.

### Where the tracker is

**[dream.scheller.ltd](https://dream.scheller.ltd)** — a Forgejo instance, and
naming it matters. The convention is portable; the *reporting* is not. Every
figure on this project's card at [privacyllc.dev](https://privacyllc.dev) is read
from this Forgejo repository.

Credentials are in `~/.openclaw/docker-registry.env`:

```bash
set -a; . ~/.openclaw/docker-registry.env; set +a
python3 scripts/forgejo-issue.py list
```

Despite its name that token is not registry-scoped — it works across the whole
API, with push and pull. Never print it into a log or a chat.

Two traps that cost an hour each otherwise. **Cloudflare fronts the instance and
1010-blocks clients that do not look like a browser or curl** — Python's `urllib`
among them — so every request needs `User-Agent: curl/8.5.0`;
`scripts/forgejo-issue.py` already sends it and anything new must too. And
**`/issues` returns pull requests too** unless `type=issues` is passed.

**Labels are exactly `P0`, `P1`, `P2`, `release-blocker`.** They are queried by
name. A fifth label, `P3`, exists on 21 closed issues from before adoption and is
frozen — nothing new gets it, because nothing counts it.

## Backend Goals

Initial API endpoints:

```txt
GET  /api/health
POST /api/leads
POST /api/support
```

Initial SQLite tables:

- `leads`
- `support_requests`

Contact and support forms should submit through Express, save to SQLite, and show user feedback with Sonner.

## Agent Plan

The overhaul is handled through the agent pipeline below:

1. **Scarlett** — design system, Tailwind/shadcn layout direction, responsive polish, accessibility review
2. **Neo** — Vite/React implementation, Express API, SQLite/database work, build-system changes
3. **Private Hudson** — security review for API routes, form handling, validation, data exposure, dependency risks, and backend hardening
4. **Scarlett** — UI polish pass after implementation changes
5. **Bishop** — build/runtime verification, route checks, documentation verification, version consistency
6. **Ripley** — final local checks, commit, tag, and push to `dev`

Agents do not touch git. Ripley owns all commits, tags, and pushes.

This pipeline says **who does which part**. `docs/WORK_CYCLE.md` says **what must
be true before a piece of work counts as finished** — closing the issue with its
evidence, closing the milestone if the batch landed, updating the documents the
change triggered in the same commit, and recording the next action. They are
different questions and both apply.

`.learnings/` holds each agent's accumulated notes and error logs. It is
gitignored and local to this machine.

## Batch Pipeline Rule

Work is dispatched as task batches. A batch runs through the required agents,
then Ripley pushes that completed batch once.

Example Docker batch:

```txt
Neo → Private Hudson → Bishop → Ripley
```

The whole batch is one push, not one push per agent.

**A batch is a milestone in the tracker.** Closing the last issue under it does
not close the milestone, and a complete-but-open milestone reads as a batch still
in progress — closing it is what marks the batch *shipped*, and it moves a figure
on the project card the same day.

> **Version numbers no longer encode the phase.** Until 2026-08-18 the rule was
> that the minor version *was* the phase number — Phase 5 releases are `0.5.x` —
> with Bishop responsible for keeping `package.json` in agreement with two
> root-level documents — PROJECT.md and HISTORY.md, named here without backticks
> because both were retired on 2026-08-18 and a backticked path is a claim that
> a file exists. It drifted twice; the second time `package.json` said `0.8.3`
> for two and a half months while commits said *batch 0.9.3*. The tracker holds
> the batch now, and
> [docs/history/HISTORY.md](docs/history/HISTORY.md) has the full reasoning.

## Design Direction

Based on the redesign review (see [docs/design/REDESIGN_REVIEW.md](docs/design/REDESIGN_REVIEW.md)), the site should feel:

- **Modern, clean, stable** — not experimental, not hacker aesthetic
- **Business-first** — B2B UCaaS/IT partner, not a dev portfolio
- **Trust-forward** — 8x8 partnership, certifications, uptime SLAs front and center
- **Human but competent** — less corporate fluff, more concrete outcomes

Color palette evolution (not rip-and-replace):
- Keep navy dark base, add teal/cyan accents for depth and hierarchy
- Improve contrast and spacing
- Mobile-first — SMB decision-makers browse on phones

Reference brands: RingCentral, Cloudflare, Dialpad — modern but enterprise-trustworthy.

See [docs/design/REDESIGN_REVIEW.md](docs/design/REDESIGN_REVIEW.md) for the full redesign assessment.

## Docker Deployment

The application can be containerized using Docker for consistent deployment across environments.

### Prerequisites

- Docker (v20+)
- Docker Compose (v2+)

### Quick Start

#### Using Docker Compose (Recommended)

```bash
# Build and start the container
npm run docker:compose:up

# View logs
npm run docker:compose:logs

# Stop the container
npm run docker:compose:down
```

#### Manual Docker Build

```bash
# Build the image
npm run docker:build

# Run the container
npm run docker:run
```

### Environment Variables

Set the following in the `.env` file (not included in image by default):

```env
NODE_ENV=production
SERVER_PORT=3001
```

### Data Persistence

SQLite database is persisted in the `./db` directory. Data will survive container restarts.

**Note on data persistence:**

The application uses Docker named volumes (`queuenorth-db` and `queuenorth-logs`) to persist data. Docker manages the ownership and permissions of these volumes automatically, so no manual setup is required.

If you prefer to use host bind mounts instead, ensure your host `./db` and `./logs` directories are owned by UID 1001:

```bash
mkdir -p ./db ./logs
sudo chown -R 1001:1001 ./db ./logs
```

If you encounter "unable to open database file" errors, verify the host directory is writable by the container's UID (1001) or use named volumes as shown above.

### Health Check

The container includes a health check at `/api/health`. A healthy container returns:

```json
{"status":"ok","timestamp":"2026-05-12T..."}
```

### Ports

- Backend API: `3001` (host) → `3001` (container)

### Build Optimization

The `.dockerignore` excludes:
- `node_modules` (reinstalled in container)
- `dist` (built in container)
- `db/` (mounted as volume)
- `.git`, logs, private docs

This ensures minimal image size and reproducible builds.

## Run Locally

```bash
npm install
git config core.hooksPath .githooks     # per clone — see below
npm run dev                             # Vite on 5173, Express on 3001
```

`npm run build` is the real gate: client bundle, SSR bundle, then prerender.
`docs/TOOLS.md` has every script and which ones can stop you.

### The git hooks

Four hooks live in `.githooks/` because `.git/hooks` is not versioned. **The
`core.hooksPath` line above is per clone**, so every checkout runs it once; an
uninstalled hook fails silently.

| Hook | What it does here |
| --- | --- |
| `pre-commit` | scans the staged diff for credentials, then runs `npm run build` if source is staged |
| `commit-msg` | refuses a message with no conventional type (`feat`, `fix`, `ui`, `docs`, `test`, `refactor`, `security`, `perf`, `chore`) |
| `post-commit` | **pushes to `origin`** |
| `pre-push` | refuses a push that leaves uncommitted or staged edits behind |

**`post-commit` pushes.** That is deliberate — work that exists on one laptop is
one disk away from gone — but it has a consequence: whatever documentation was
not in that commit is now behind the code by one push. That is the mechanical
reason documentation edits ride in the same commit as the change that caused
them. `SKIP_GUARDS=1` and `SKIP_PUSH=1` are the escape hatches, both loud.

## Project Docs

`README.md` is the landing page. Detailed procedures belong in `docs/`, and open
work belongs in the tracker.

**[docs/DOC_TRUST_MAP.md](docs/DOC_TRUST_MAP.md) is the entry point** — read it
before trusting anything else in `docs/`.

| Doc | Purpose |
| --- | --- |
| [docs/DOC_TRUST_MAP.md](docs/DOC_TRUST_MAP.md) | Which document owns which answer, and which source wins when records disagree |
| [docs/WORK_CYCLE.md](docs/WORK_CYCLE.md) | What happens at the end of a piece of work, and what privacyllc.dev will and will not update on its own |
| [docs/TOOLS.md](docs/TOOLS.md) | Where the scripts are, which ones can stop you, and this project's npm commands |
| [docs/OPERATIONS.md](docs/OPERATIONS.md) | What is deployed and where, what watches it, and what to run when it is down |
| [docs/planning/PROJECT_PLAN.md](docs/planning/PROJECT_PLAN.md) | Scope, audience, and what this project deliberately is not |
| [docs/planning/REQUIREMENTS.md](docs/planning/REQUIREMENTS.md) | Engineering standards. Not changeable without `_null`'s approval |
| [docs/architecture/README.md](docs/architecture/README.md) | Module boundaries, the database schema, every API response shape |
| [docs/architecture/GUARDS.md](docs/architecture/GUARDS.md) | How to write a check that can actually fail |
| [docs/architecture/zoho-setup.md](docs/architecture/zoho-setup.md) | The CRM integration, end to end |
| [docs/design/OVERHAUL_PLAN.md](docs/design/OVERHAUL_PLAN.md) | The visual system: tokens, type scale, spacing, layout blueprints |
| [docs/design/REDESIGN_REVIEW.md](docs/design/REDESIGN_REVIEW.md) | Brand positioning and the messaging standard |
| [docs/security/SECURITY.md](docs/security/SECURITY.md) | Threat model, secrets, third parties, what is out of scope |
| [docs/security/SECURITY_CHECKLIST.md](docs/security/SECURITY_CHECKLIST.md) | The list to work through before a release |
| [docs/qa/ClaudeQAPlan.md](docs/qa/ClaudeQAPlan.md) | What a QA round consists of |
| [docs/qa/ClaudeReport.md](docs/qa/ClaudeReport.md) | The QA verdict — quoted verbatim on the project card |
| [docs/qa/ClaudeQACoverage.md](docs/qa/ClaudeQACoverage.md) | What each pass actually reached, and the standing gaps |
| [docs/history/DEVELOPMENT_LOG.md](docs/history/DEVELOPMENT_LOG.md) | Dated, append-only: what happened and when |
| [docs/history/HISTORY.md](docs/history/HISTORY.md) | The narrative: decisions, and what was tried and dropped |
| [docs/history/BATCH_LEDGER.md](docs/history/BATCH_LEDGER.md) | Archived. What the batches were before the tracker held them |

## Agent Notes

- Product truth comes from the code and the tracker before prose.
- **Do not keep a work list in this README**, or in any markdown file. That is
  what the tracker is for, and this project has already paid for the lesson.
- Finish with [docs/WORK_CYCLE.md](docs/WORK_CYCLE.md), every time: close the
  issues you finished with the evidence that proves it, close the milestone if
  the batch landed, update the documents the change triggered **in the same
  commit**, then record the next action and any blockers before you stop.
- Nothing on privacyllc.dev writes itself except the tracker counts and the
  pushed docs. The summary and next action change only when they are sent; the
  milestone and blocker tables there change only when a human edits them.
- Do not claim a feature is built unless you can cite the route, file, or
  screenshot that proves it. **There is no test suite to cite.**
