Skip to content

resq-software/landing

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

402 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

ResQ Landing

Marketing and product site for the ResQ autonomous drone disaster-response platform.

CI Deploy License Next.js Tailwind Bun Live


Overview

Public-facing marketing, blog, and documentation site for the ResQ platform. Built with Next.js 16 (App Router), deployed to Cloudflare Workers via OpenNext, and optimized for Core Web Vitals and edge performance.

Content is authored in Sanity (with MDX fallbacks for content/posts and content/changelog). The site also runs a double opt-in newsletter (Resend), Turnstile-guarded forms, edge rate limiting (Upstash), and first-party analytics (PostHog + GA4).

Locales: English, Spanish, Chinese, Hindi, Arabic (RTL)


Architecture

Request Flow

flowchart LR
    Browser -->|HTTPS| CF["Cloudflare CDN"]
    CF -->|Static assets| Assets["Static HTML/CSS/JS"]
    CF -->|Dynamic routes| Worker["Cloudflare Worker"]
    Worker -->|Locale routing| MW["next-intl Middleware"]
    MW --> SSR["Server Components"]
    SSR --> UI["React 19 UI"]
    Worker -->|/api/*| Hono["Hono utility surface"]
    Hono --> Health["/api/health"]
    Hono --> Revalidate["/api/revalidate/research"]
    Hono --> Newsletter["/api/newsletter/confirm · unsubscribe"]
    Hono --> Webhook["/api/webhooks/resend"]
    Worker -->|/api/v1/*| Elysia["Elysia v1 API"]
    Elysia --> Status["/api/v1/status · /views"]
    Elysia --> NL["/api/v1/newsletter"]
    Worker -->|/api/og · /api/md| Edge["OG images · markdown-for-agents"]
Loading

Deployment Pipeline

flowchart TD
    Push["git push main"] --> CI
    subgraph CI["CI (parallel)"]
        Build["Build"]
        Test["bun test"]
        Lint["biome lint"]
    end
    CI -->|all pass| Deploy
    subgraph Deploy["Deploy"]
        ON["opennextjs-cloudflare build"] --> Wrangler["wrangler deploy"]
    end
    Wrangler --> Live["resq.software"]
Loading

Project Structure

graph TD
    subgraph App["src/app/"]
        Pages["[locale]/(marketing)/*"]
        API["api/[[...route]]"]
    end
    subgraph Features["src/features/"]
        Sections["marketing/sections/"]
        Components["marketing/components/"]
    end
    subgraph Core["Core"]
        Hooks["src/hooks/"]
        Lib["src/lib/"]
        Utils["src/utils/"]
        Config["src/config/"]
        Actions["src/actions/"]
        I18n["src/i18n/"]
    end
    subgraph Content["content/"]
        Posts["posts/*.mdx"]
        Changelog["changelog/*.mdx"]
    end
    Pages --> Sections
    Pages --> Components
    Sections --> Hooks
    Components --> Lib
    API --> APISurf["Hono /api/* + Elysia /api/v1/*"]
    Pages --> Content
Loading

Pages & Routes

Route Description
/[locale] Homepage — hero, metrics, problem statement, platform pillars, use cases
/[locale]/platform Platform overview
/[locale]/protocol Protocol details
/[locale]/pricing Pricing — civilian tiers published; defense/allied route to "Request a briefing"
/[locale]/research Research teaser; consumes index.json from research.resq.software
/[locale]/developers · /[locale]/developers/[slug] Developer landing and doc pages
/[locale]/contact Contact form (name, email, org, message) — Turnstile-guarded
/[locale]/blog · /[locale]/blog/[slug] Blog listing and individual posts (Sanity + MDX)
/[locale]/blog/featured · /[locale]/blog/category/[category] · /[locale]/blog/authors/[id] Blog facets
/[locale]/blog/archive · /[locale]/blog/archive/[year] · /[locale]/blog/archive/[year]/[month] Blog date archives
/[locale]/changelog · /[locale]/changelog/[slug] Product changelog and entries
/[locale]/changelog/archive/* Changelog date archives
/[locale]/legal/* Privacy, terms, cookies, data processing, acceptable use, security
/studio Embedded Sanity Studio (content editing)
/api/health Health check (Hono): health, health/detailed, health/ready, health/live
/api/revalidate/research Bearer-auth publish hook called by research.resq.software after deploy
/api/newsletter/confirm · /api/newsletter/unsubscribe Double opt-in confirm and RFC 8058 one-click unsubscribe
/api/webhooks/resend Svix-signed Resend webhook → suppression on bounce/complaint
/api/og Dynamic OG image generation (@vercel/og)
/api/md/* Markdown-for-Agents fallback (serves text/markdown of pages)
/api/v1/* Elysia business surface — status, views, newsletter — see src/app/api/v1/[[...route]]/

Quick Start

git clone https://github.com/resq-software/landing.git
cd landing
bun install
bun dev          # http://localhost:3000

Commands

Command Description
bun dev Dev server (Turbopack)
bun build Production build
bun build:cf Build the Cloudflare Worker bundle (opennextjs-cloudflare)
bun preview Build + run the worker locally via wrangler dev
bun test Unit tests (bun:test)
bun test:coverage Unit tests with coverage
bun cy:open Cypress E2E (interactive)
bun cy:run Cypress E2E (headless)
bun test:e2e:critical Critical-path E2E specs (pre-push gate)
bun lint Biome lint check
bun format Biome auto-format
bun check Biome lint + format
bun knip Find unused files, deps, and exports
bun lhci Lighthouse CI
bun size Bundle size budget check (size-limit)
bun audit Dependency vulnerability audit

Testing

Unit Tests (bun:test)

10 test files, 91 tests covering utilities, hooks, email tokens, and API handlers.

bun test              # run all
bun test:coverage     # with coverage report
Test file Coverage
src/lib/utils.test.ts cn() class merging
src/lib/helpers.test.ts URL, scroll, hash, stringify utilities
src/lib/logger.test.ts Logger class with log levels
src/lib/seo/meta.test.ts Metadata constructors
src/lib/seo/speculation-schema.test.ts Schema.org graph builders
src/lib/email/confirm-token.test.ts HMAC confirm/unsubscribe token signing
src/lib/repo-hygiene.test.ts Repo hygiene / license-header checks
src/hooks/use-in-view.test.ts IntersectionObserver hook
src/app/api/v1/**/health/handlers.test.ts Health check handlers
src/app/api/v1/**/status/handlers.test.ts Better Stack status with fetch mocking

E2E Tests (Cypress)

36 spec files covering homepage and navigation, blog (listing, search, authors, editorial, archives, post features), changelog, contact and newsletter forms, API health/v1/status, locale switching, legal and content pages, SEO/OG/sitemap, security headers, accessibility, and mobile nav. The homepage, navigation, contact-form, sitemap-robots, newsletter-inline, and security-headers specs run as the pre-push critical-path gate (bun test:e2e:critical).

bun cy:open           # interactive mode
bun cy:run            # headless CI mode

Deployment

Infrastructure

graph LR
    subgraph Cloudflare
        Worker["Worker<br/>(Next.js SSR)"]
        Assets["Static Assets<br/>(HTML, CSS, JS, fonts)"]
        DNS["DNS<br/>resq.software"]
    end
    subgraph External
        Sentry["Sentry<br/>(error tracking)"]
        BetterStack["Better Stack<br/>(uptime monitoring)"]
    end
    DNS --> Worker
    Worker --> Assets
    Worker --> Sentry
    Worker --> BetterStack
Loading

How it works

  1. Push to main triggers CI (build + test + lint)
  2. CI passes triggers the deploy workflow
  3. OpenNext builds the Next.js app into a Cloudflare Worker bundle
  4. Wrangler deploys the worker + static assets to Cloudflare
  5. Static pages (blog, legal, homepage) are prerendered at build time and served from the assets cache
  6. Dynamic routes (API) are server-rendered by the Worker

OpenNext Configuration

The site uses @opennextjs/cloudflare with static-assets caching — no KV, R2, or D1 bindings required.

Setting Value Why
incrementalCache static-assets Serves prerendered pages from static assets
queue direct No ISR revalidation needed
enableCacheInterception false Reduces cold start overhead

Environment Variables

All variables are validated in src/env.ts via @t3-oss/env-nextjs + Zod. Every key is optional in development; several are required in production (noted below) and the features that depend on them degrade gracefully (log-only / disabled) when unset. Secrets live in Cloudflare Workers secrets, not wrangler.jsonc.

Core / observability

Variable Prod Description
NEXT_PUBLIC_APP_URL Required Canonical site URL
NEXT_PUBLIC_SENTRY_DSN No Sentry DSN for client-side error tracking
SENTRY_AUTH_TOKEN / SENTRY_ORG / SENTRY_PROJECT / SENTRY_URL No Sentry source-map upload + project config
BETTERSTACK_API_KEY No Better Stack API key for uptime status

Analytics

Variable Prod Description
NEXT_PUBLIC_POSTHOG_KEY No PostHog project key (analytics disabled when unset)
NEXT_PUBLIC_POSTHOG_HOST No First-party reverse-proxy path (defaults to /ingest)
NEXT_PUBLIC_GA4_ID No GA4 Measurement ID (G-XXXXXXX)

Forms / bot mitigation / rate limiting

Variable Prod Description
NEXT_PUBLIC_TURNSTILE_SITE_KEY / TURNSTILE_SECRET_KEY Recommended Cloudflare Turnstile sitekey + secret (widget omitted when unset)
UPSTASH_REDIS_REST_URL / UPSTASH_REDIS_REST_TOKEN Recommended Upstash Redis for cross-isolate rate limiting (falls back to per-isolate memory)
RATE_LIMIT_KEY_PEPPER Required* SHA-256 pepper for rate-limit keys (*required when Upstash is configured)
CSRF_SECRET No CSRF token secret for state-changing forms

Newsletter (Resend, double opt-in)

Variable Prod Description
RESEND_API_KEY Required Resend API key (Sending + Contacts); newsletter is log-only when unset
RESEND_AUDIENCE_ID Required Resend Audience/Segment id used as the subscriber list
RESEND_FROM Required Verified sender identity (e.g. ResQ <updates@send.resq.software>)
RESEND_WEBHOOK_SECRET Required Svix signing secret for /api/webhooks/resend
NEWSLETTER_CONFIRM_SECRET Required HMAC pepper for confirm/unsubscribe tokens (openssl rand -hex 32)
NEWSLETTER_POSTAL No Physical postal address for the commercial-broadcast email footer (CAN-SPAM)

Content (Sanity) & research feed

Variable Prod Description
NEXT_PUBLIC_SANITY_PROJECT_ID / NEXT_PUBLIC_SANITY_DATASET Required Sanity project + dataset for blog/changelog content
SANITY_API_TOKEN No Sanity read/write token (Studio, server fetches)
SANITY_WEBHOOK_SECRET No Verifies Sanity publish webhook → /api/v1/revalidate
RESEARCH_FEED_URL Required Absolute URL to the research subdomain feed (.../index.json)
RESEARCH_REVALIDATE_TOKEN Required 32-byte bearer token shared with the research publish hook
ADMIN_API_TOKEN No Bearer token for admin-only API operations

CI/CD Secrets (GitHub)

Secret Description
CLOUDFLARE_API_TOKEN Cloudflare API token with Workers Scripts Edit permission
CLOUDFLARE_ACCOUNT_ID Cloudflare account ID

Content

Blog and changelog content is authored in Sanity (an embedded Studio is served at /studio, and src/lib/sanity/ holds the client, queries, and adapters). Publishing fires a webhook to /api/v1/revalidate. MDX files under content/ remain as a fallback / seed source.

Blog Posts (MDX fallback)

MDX files in content/posts/ with frontmatter:

---
title: "Post Title"
date: "2026-01-15"
excerpt: "Short description"
tag: "Engineering"
tags: ["mesh", "protocols"]
author: "mike"
readTime: "8 min read"
---

Changelog

MDX files in content/changelog/ with dated entries.


Tech Stack

Layer Technology
Framework Next.js 16 (App Router, React 19)
Styling Tailwind CSS v4
Language TypeScript 6 (strict)
Runtime Bun (tooling/tests); workerd with nodejs_compat (production)
API Hono (/api/* utility surface) + Elysia (/api/v1/* business surface)
i18n next-intl (5 locales, RTL support)
CMS Sanity (blog + changelog), MDX fallback
Forms TanStack Form + next-safe-action + Zod
Bot mitigation Cloudflare Turnstile
Rate limiting Upstash Redis (per-isolate memory fallback)
Email / Newsletter Resend (double opt-in, Svix webhooks)
UI Components Radix UI + class-variance-authority
Linting Biome
Unit Testing bun:test
E2E Testing Cypress
Hosting Cloudflare Workers (via @opennextjs/cloudflare)
Error Tracking Sentry
Analytics PostHog + GA4
Uptime Better Stack

Contributing

  1. Fork and create a branch (feat/, fix/, docs/)
  2. Run bun check before committing
  3. Follow Conventional Commits
  4. Submit a PR against main — CI must pass

License

Apache License 2.0

About

Marketing and product site for the ResQ autonomous drone disaster-response platform, built with Next.js 15, Tailwind CSS, and Bun.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Contributors