Commit Graph

46 Commits

Author SHA1 Message Date
Neo 2ae7352799 feat(release): adapt PrivacyLLC-Web's release.sh, and add the deploy half it deliberately omits
scripts/release.sh — publish. Bump, guards, build, verify the image's own
version label, push :vX.Y.Z and move :dev, commit last, tag.

Adapted, not copied. The arguments are PrivacyLLC's and were paid for there; the
mechanism is this project's, because almost none of it transferred. Three
differences, each a fact about this repository rather than a preference:

- It gates on verify.sh, not a test suite, because there is not one. The
  original refuses to release on a half-run 1,600-test run. This one says out
  loud that a build, a secret scan and a doc-header check are not tests and that
  nothing in the gate touched a route, a form or an API response.
- It moves :dev as well as publishing :vX.Y.Z, because Portainer stack 58
  follows :dev. That makes :dev a pointer and never evidence.
- It checks the public origin in three files, not one. The original passes its
  origin in as a build arg; here https://queuenorth.com is written out in
  src/lib/seo.js, src/components/SEO.jsx and scripts/prerender.js and is baked
  into every canonical URL, og:url, sitemap.xml and robots.txt. The guard asks
  whether the three still agree.

Why this was needed: publishing was `npm run docker:push` with the bump as a
separate thing to remember, and it was not remembered. package.json said 0.8.3
while four commits announced "batch 0.9.0" through "0.9.3", and NO image was
ever published for any of them — the registry's newest tag is v0.8.3.

No prune. The original has one; this project has published thirteen tags in its
life, deleting a published image is irreversible, and the one that matters is
whichever the container was created from — exactly what a newest-N rule gets
wrong.

scripts/deploy.sh — deploy, and do not build. The template's deploy.py builds,
pushes AND deploys; adopting it beside release.sh would mean two commands that
both build, a second image for the same code, and two answers to "what is
running". This does only the missing half: point stack 58 at an already
published tag, having taken a verified backup first.

Its most important guard is not the obvious one. Portainer treats a stack PUT as
the whole desired state, so sending it without the stack's Env array would strip
twelve variables — the reCAPTCHA secret and the Zoho form tokens among them —
and the container would come back HEALTHY while quietly capturing no leads. It
reads them, counts them, sends them back, and refuses outright if none.

Guards proven to refuse, not assumed: already-published tag, http origin,
trailing-slash origin, the three origin constants drifted, dirty tree, bad flag,
unpublished deploy tag, missing Portainer key, wrong stack id.

One real bug found and fixed while testing: the image-line rewrite used
`python3 -` with a heredoc while also piping the stack file to stdin, so python
tried to execute the YAML.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-18 02:49:03 -05:00
Ripley 5c04195cb1 chore: adopt template scripts and git hooks, retire phase-versioning
Ten scripts from ~/.openclaw/Projects/Template, taken one at a time and
configured against this deployment rather than copied wholesale.

Configured, not just copied:
- check-env.sh   SPEC written from what server/index.js actually reads — 24
                 variables, each with the consequence of getting it wrong
- secrets.sh     plus this project's own shapes: a bare 60+ hex run, which is
                 how the Zoho WebToLead tokens leaked into four commits, and a
                 reCAPTCHA key shape as NOTED rather than a failure, because the
                 site key and the secret key are indistinguishable by shape
- status.sh      nebula / qn-website-dev
- healthcheck.sh /api/health, asserting 200 AND "status":"ok" AND "db":"ok".
                 The template probed /healthz, which does not exist here
- preflight.sh   https://qn.isnull.dev, no --auth — there are no accounts
- verify.sh      GUARD_DIR=scripts/verify.d, since this project has no test
                 runner and no typecheck for it to detect
- backup.sh      ENGINE block replaced for SQLite: better-sqlite3's online
                 .backup() inside the container, verified with PRAGMA
                 integrity_check before anything is renamed into place
- restore-check.sh  rewritten rather than configured — the template's is
                 pg_restore/psql end to end with no seam. Replays the dump from
                 SQL into a scratch database and times it

Three guards in scripts/verify.d, because verify.sh would otherwise detect
nothing and exit 2: the build, the tracked-tree secret scan, and a check that
every document carries a valid Status, Governs and Review trigger.

Every guard was proven to fail before being trusted, per GUARDS.md rule 1:
healthcheck against a 200 that is not this app, secrets against the real
historical leak replayed out of 033bdf6, doc-headers against both a missing
Review trigger and the Status word "Historical", restore-check against a
truncated dump, an empty database and a raised row floor.

pre-commit is ADAPTED, not the template's. That one runs `npx tsc --noEmit` and
`npx vitest run`; this project has neither, so unchanged it would refuse every
commit. It runs the secret scan and `npm run build`. Hooks are not activated by
this commit — `git config core.hooksPath .githooks` is a separate, per-clone act.

package.json: adds `verify`, and corrects the version to 0.9.3. It said 0.8.3
while the last four commits said batch 0.9.0 through 0.9.3 — the second drift of
the phase-versioning rule, which is retired in the following commit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-18 01:18:20 -05:00
null ac6f5d1f78 feat(seo): publish privacy policy, remove street address, prerender all routes (batch 0.9.3)
Client directive (Levi Halford, 2026-08-01) ahead of Google/Meta lead forms.

Privacy policy:
- Publish approved policy verbatim at /privacy-policy (src/data/privacyPolicy.js
  is the single source of truth; 292/292 source lines verified present)
- Privacy Policy link in the footer of every page
- Effective/Last Updated 2026-07-31, privacy@queuenorth.com as mailto

Remove St. Petersburg street address from every surface named in the brief:
footer, contact page, schema markup, SEO metadata, Google Maps links. Collapse
ProfessionalService + Organization schema into a single Organization with
areaServed: United States; drop geo coordinates, priceRange, openingHours.
Add the approved US-coverage sentence to About. No replacement address.

Crawler visibility (the site previously served 0 bytes of body HTML without JS):
- Prerender all 19 routes at build time via src/entry-server.jsx + scripts/prerender.js
- Hoist title/meta/canonical/JSON-LD into <head>; renderToString does not do this
  and react-helmet-async's context is empty under React 19
- Serve prerendered HTML; return a real 404 for unknown paths instead of 200
- Hydrate instead of discarding the prerendered markup

SEO/perf:
- Titles <=60 and descriptions <=160 chars across all pages
- Add BreadcrumbList to interior pages, WebSite to home
- Generate sitemap.xml from the route list with git-derived lastmod
- 301 duplicate URL forms (trailing slash, //, /index.html), preserving query
- Immutable caching for content-hashed assets; no-cache for HTML
- Split the 522 KB bundle into app/react-vendor/router/icons
- loading/decoding/fetchpriority + per-route hero preload; drop unused asset

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 01:45:52 -05:00
null 76cb558e8b chore: bump version to v0.8.3 2026-05-28 01:10:38 -05:00
null 1dcfbfc7a7 chore: bump version to v0.8.2 2026-05-27 21:56:47 -05:00
null 225c4e5485 chore: bump version to v0.8.1 2026-05-27 14:33:13 -05:00
null 431d1157b3 chore: bump version to 0.8.0 2026-05-26 13:44:27 -05:00
null ca8972b54d chore: bump version to 0.7.6 2026-05-18 14:26:06 -05:00
null 3f8eafb76a chore: bump version to 0.7.5 2026-05-18 14:02:50 -05:00
null a293d0fa9a feat(seo): add canonical URLs, close SEO audit (#175) 2026-05-18 13:58:35 -05:00
null de61d5e625 fix(ui): UI fixes across header, contact, home, about, support, services, industries (#132 #133 #134 #154 #165 #172 #173) 2026-05-18 13:12:18 -05:00
null fdc6eaeab5 chore: bump version to 0.7.2 2026-05-18 12:33:06 -05:00
null aec33165b9 chore: bump version to 0.7.1, fix Home.jsx aria-label text fragment (batch 10.3) 2026-05-17 22:48:57 -05:00
null 2c002c2f82 fix: remove React Query, add HTTPS redirect, document CSP Zoho note (#128 #127 #129) (batch 10.0) 2026-05-17 22:33:11 -05:00
null 95917bc699 chore: bump version to 0.7.0 (batch 9.10) 2026-05-17 22:11:40 -05:00
null 5c17019931 fix: remove unused assets (24MB), Dialog component, CardDescription dup, zustand dep (#95 #113 #114 #115 #116) (batch 9.9) 2026-05-17 22:08:21 -05:00
null 1b0d5adc36 feat(seo): add react-helmet-async, per-page meta/OG tags, JSON-LD, sitemap, robots.txt, heading fixes (#71)
- Added react-helmet-async + HelmetProvider to main.jsx
- Per-page Helmet components on all 8 pages (title, description, OG tags)
- JSON-LD structured data (Organization, LocalBusiness, Service)
- Created public/sitemap.xml with all 17 routes
- Created public/robots.txt
- Fixed heading hierarchy (no h1->h3 skips)
- Improved image alt text throughout
- Fixed docs/zoho-setup.md env defaults clarification
2026-05-17 20:03:42 -05:00
null 2a9eef0e71 docs: update FUTURE.md + HISTORY.md, bump v0.6.6 (Phase 7 complete) 2026-05-17 19:27:57 -05:00
null 1437b2af07 fix: 10 bug fixes from code review (batch 0.6.5)
- #63: Fix industry.href undefined → use industry.id for navigation
- #50: Fix sanitized scope error in catch block (let before try)
- #58: Footer.jsx: convert all internal <a href> to <Link to>
- #61: Textarea.jsx: fix className interpolation (quotes → backticks)
- #59: About.jsx: convert CTA <a href> to <Link to>
- #60: Support.jsx: convert Contact button <a href> to <Link to>
- #62: Badge.jsx: text-foreground → text-text
- #64: Support.jsx: hover:bg-navy-darker → hover:bg-primary-navy-dark
- #65: Server: move timeoutMiddleware before catch-all routes
- #66: Contact.jsx: convert self-referencing <a href> to <Link to>
2026-05-17 18:03:55 -05:00
null b428348a4c docs: close issues #45 #46 #47 — already implemented in earlier batches (batch 0.6.2) 2026-05-17 16:17:54 -05:00
null 56bdf07216 fix: close issues #12 #15 #17 #18 — CSP nonce, API retry, input debounce, caching verified (batch 0.6.1) 2026-05-17 16:10:10 -05:00
null e11aefd184 fix: audit issues #10 #14 #16 #19 — CORS errors, JSON middleware, Zoho fields, noValidate (batch 0.6.8) 2026-05-17 15:46:59 -05:00
null 5807582df1 feat: hero left-alignment + about section content fixes (batches 0.6.3, 0.6.4)
- Hero text left-aligned on all screen sizes (Issue #33)
- Hero image always visible, grid breakpoint md instead of lg
- Spacing refactored from margin to gap utils
- About: veteran-founded framing, mission paragraph (Issue #34)
- About: vendor-neutral consulting in expertise (Issue #36)
- About: image sizing max-h-96 object-cover (Issue #37)
- Version bump 0.5.6 → 0.5.7
2026-05-17 15:33:30 -05:00
null eb76e1fadc feat(cisco): add Cisco partnership signals across site (batch 0.6.2) 2026-05-17 15:28:12 -05:00
null 25ab4c7986 fix(server): Zoho token endpoint hardening + version bump to 0.5.4 (batch 0.6.0) 2026-05-17 15:18:24 -05:00
null 71c8129046 feat(ui): footer + contact improvements, CTAs everywhere, gitignore update (batch 0.5.6)
- Footer: email, phone, Request Consultation CTA
- Home: CTA links added to Trust Signals, Services, Why Queue North
- Contact: hero CTA, prominent phone/email
- Support page updates
- Version bumped to 0.5.3
- FUTURE.md and HISTORY.md now tracked in git
- .gitignore updated to allow FUTURE.md and HISTORY.md
2026-05-17 15:07:28 -05:00
null a963dc4dcc feat(ui): why queue north section refinement (batch 0.5.5) 2026-05-17 14:56:10 -05:00
null 54dc893ec5 chore: bump version to 0.5.1 2026-05-17 14:33:54 -05:00
null 796d372e79 chore: add docker-push.sh, docker-test.sh, npm scripts, bump v0.5.0
- docker-push.sh: build + tag + push dev image to Forgejo registry
- docker-test.sh: rebuild and run container for local testing
- npm scripts: docker:push and docker:test
- Version bump to 0.5.0 (Phase 5)
2026-05-14 01:18:44 -05:00
null c4985e37bc feat: Phase 5 SPA fixes, mobile menu, assets, and redesign planning
- Fix BrowserRouter → RouterProvider (routes were disconnected)
- Strip TS generics from .jsx files (Card, Badge, Dialog, Input, Textarea)
- Fix useToast import from sonner (Contact, Support)
- Merge mobile Sheet into Header (DialogTrigger outside Dialog)
- Add SPA catch-all route for client-side navigation
- Add CSP style-src for Google Fonts
- Copy all image assets to public/ (were 404)
- Replace placeholder logo with real Queue North logo
- Fix SheetContent positional CSS + install tailwindcss-animate
- Add visually hidden SheetTitle for accessibility
- Update README and FUTURE.md with Phase 5 redesign batches
- Add review.md (redesign assessment, exempt from git)
2026-05-13 22:07:35 -05:00
null c2d5873f08 feat: error handling hardening, 404 catch-all, health check DB test, request timeout, global error handlers (v0.4.8) 2026-05-13 19:59:19 -05:00
null 7257633d94 feat: rate limiting, helmet security headers, CORS, trust proxy, Docker env vars (v0.4.7) 2026-05-13 18:37:32 -05:00
null 6bfd804313 feat: Zoho CRM forwarding layer with OAuth2 token management (v0.4.6) 2026-05-13 18:28:56 -05:00
null 4ac0fa250d feat: server-side validation + input sanitization (v0.4.5) 2026-05-13 18:18:07 -05:00
null 931c9a9095 feat: client-side form validation + Sonner feedback (v0.4.4) 2026-05-13 18:10:04 -05:00
null 71347d070b chore: bump version to 0.4.3 (SQLite persistence verified) 2026-05-13 04:14:07 -05:00
null f03229dd50 feat: Phase 3 Batch 4 — inner pages layout system with consistent hero/card/CTA pattern (v0.3.4) 2026-05-12 02:45:25 -05:00
null 35aaa639ec feat: Phase 3 Batch 3 — header/footer/mobilenav polish + fix Button.jsx TS generics (v0.3.3)
- Sticky dark navy header with clean nav and CTA
- Reorganized MobileNav with Primary/Services/Industries sections
- Dark navy footer with cyan accent headers
- Added navy-light color token
- Fixed Button.jsx: removed TypeScript generic syntax that broke esbuild
- Replaced asChild Button usage with styled anchor tags
2026-05-12 02:39:35 -05:00
null 76aa71691f feat: Phase 3 Batch 2 — home page redesign with hero, trust bar, services, CTA (v0.3.2) 2026-05-12 02:31:23 -05:00
null 287e2b79f6 feat: Phase 3 Batch 1 — theme tokens, spacing scale, container width (v0.3.1) 2026-05-12 02:26:18 -05:00
null 0b7da4d237 chore: bump to v0.3.0 — Phase 3 Visual Overhaul baseline 2026-05-12 02:15:36 -05:00
null ba0d039cdc fix: reduce Docker image from 331MB to 215MB — remove duplicate node_modules layer
v0.2.2: Removed COPY --from=builder node_modules from runner stage.
The full dev+prod modules (116MB) were being copied as a permanent
Docker layer, then npm ci --omit=dev installed a separate prod-only
set on top. Now only the prod install runs, cutting 116MB.
2026-05-12 02:04:52 -05:00
null 1f3e3864f9 feat: Docker batch 0.2.1 — production-ready containerization
- Multi-stage Dockerfile with non-root nodejs user
- Healthcheck using Node 20 built-in fetch (no wget)
- docker-entrypoint.sh: root permission fix, then exec to nodejs
- server/db.js: deferred SQLite init for Docker volume permissions
- docker-compose.yml with named volumes for persistence
- .dockerignore and .env.example added
- README updated with Docker usage section

Security reviewed by Private Hudson. All blockers resolved.
2026-05-12 01:57:55 -05:00
null c83dc08660 feat: complete phase 2 layout rebuild 2026-05-12 01:18:57 -05:00
null bd17e964b3 chore: bump phase 1 checkpoint to 0.1.1 2026-05-12 01:05:44 -05:00
null b7f7765a72 feat: complete phase 1 foundation 2026-05-12 01:04:17 -05:00