393 lines
15 KiB
Markdown
393 lines
15 KiB
Markdown
# 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
|
|
[qn.isnull.dev](https://qn.isnull.dev).
|
|
|
|
## 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.**
|