TheDBA
2026 • Astro 5, TypeScript, Tailwind CSS 4, Cloudflare Workers, Cloudflare D1, Resend
TheDBA
2026 · Astro 5, TypeScript, Tailwind CSS 4, Cloudflare Workers, Cloudflare D1
About This Project
TheDBA (The Dog Business Association) is a new, independent, not-for-profit trade body in formation for UK dog service professionals: boarders, kennels, walkers, day care providers, trainers, groomers, and pet sitters. It is being set up by a founding team in the wake of the Association of Dog Boarders winding down, which left a lot of established, insured, licensed businesses without a professional body to belong to. The first thing the new association needed was somewhere to gather those people and gauge the appetite for what comes next.
So the current site is deliberately small: a single, focused landing page that explains who the DBA is, who it is for, and what it intends to do, with a form to register interest in twelve months of free founding membership. It is honest about its own status. The DBA is not yet incorporated, is not taking payment, and is not issuing membership. This is the "tell us you're interested and we'll keep you posted" stage, and the site says so plainly.
That sounds like a small brief, and in terms of page count it is. But a register-interest page is still collecting real details from real businesses, and it is the association's first impression. It needed to be fast, trustworthy, resilient, and impossible to lose a submission through. That is where most of the actual engineering went.
The Stack, and Why
The site is built with Astro 5 in fully static mode. Every page compiles to plain HTML at build time, so there is no server rendering to wait on and almost no JavaScript shipped to the browser. For a content page that just needs to load quickly on any connection, that is exactly right.
The more interesting decision is how it is hosted. It runs on a single Cloudflare Worker, not on Cloudflare Pages. The Worker sits in front of everything: it inspects each incoming request, handles the one dynamic thing the site does (the form submission at /api/submit), and hands everything else straight to Cloudflare's static asset serving:
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
const url = new URL(request.url);
if (url.pathname === "/api/submit" && request.method === "POST") {
return handleSubmit(request, env, ctx);
}
// Anything else: serve from the static Astro build
return env.ASSETS.fetch(request);
},
};
The result is one deployment that behaves like a static site for speed but has a genuine backend endpoint when it needs one, all on Cloudflare's edge network. Registrations are stored in Cloudflare D1, their edge SQL database, so there is no separate server or database to run, patch, or pay for while nobody is filling in the form. For a pre-launch site with unknown traffic, that combination is hard to beat: it is quick, it costs almost nothing to keep online, and there is very little that can break.
A Closer Look: The Registration Pipeline
On the surface it is just a contact form. Underneath, it is the part of the site I was most careful with, because losing a founding member's details at the "register your interest" stage would be the worst possible first impression.
The whole flow is built to work whether or not JavaScript runs. That is not a given on a modern site, and it is the detail I am most pleased with.
The server side is a single Worker handler, and the first thing it decides is how to answer, based on what the client asked for. A JavaScript submission sends an Accept: application/json header and gets a small JSON response back. A plain form submission with no JavaScript gets a proper 303 redirect instead, back to the page with the result carried in the URL:
const respond = (status: "ok" | "invalid" | "error") => {
if (wantsJson) {
const httpStatus = status === "ok" ? 200 : status === "invalid" ? 400 : 500;
return new Response(JSON.stringify({ status }), {
status: httpStatus,
headers: { "content-type": "application/json" },
});
}
// No-JS path: redirect back to the page with the result in the query string
const u = new URL("/", origin);
u.searchParams.set("submit", status);
u.hash = "register";
return Response.redirect(u.toString(), 303);
};
On the page, a small script catches both cases and shows the same message either way. If JavaScript is on, it intercepts the submit, posts in the background, and swaps the form for a success panel in place so the page never jumps. If JavaScript is off, the native form posts, the browser follows the redirect, and the script simply reads the result out of the URL on the way back in and shows the identical banner, then tidies the URL so a refresh does not repeat it:
// Fallback path: a no-JS native POST landed back here with ?submit=…
var params = new URLSearchParams(window.location.search);
var urlStatus = params.get("submit");
if (urlStatus && statusEl) {
if (urlStatus === "ok") {
showBanner("Thank you. Your interest has been registered. We will be in touch shortly.", "ok");
} else if (urlStatus === "invalid") {
showBanner("Some details look incorrect. Please check the form and try again.", "error");
} else {
showBanner("Sorry, something went wrong submitting the form. Please try again, or email info@thedba.org.uk.", "error");
}
// Clean the URL so a refresh doesn't re-show the banner
var clean = window.location.pathname + window.location.hash;
window.history.replaceState({}, "", clean);
}
Two completely different technical paths, one identical experience for the person filling in the form. Nobody hits a broken page, and nobody loses their submission because a script failed to load.
The rest of the handler is the unglamorous work a real submission endpoint needs. There is a hidden honeypot field that a person never sees but a spam bot fills in: if it arrives with content, the Worker quietly returns a success response and saves nothing, so the bot moves on none the wiser. Every field is validated and length-capped on the server, the email is pattern-checked, and the business type has to match a fixed list rather than being trusted from the form. Only then does the registration go into D1 as a prepared statement.
The last touch is how the team hears about it. As soon as a valid registration is saved, the Worker fires off two notifications at once, an email through Resend and a real-time message to a Discord channel, so the founding team sees new interest the moment it lands:
// Fire-and-forget: notify the team, but never make the user wait on it
if (env.RESEND_API_KEY && env.RESEND_FROM && env.NOTIFY_TO) {
ctx.waitUntil(sendNotification(env, data).catch((e) => console.error(e)));
}
if (env.theDbaDiscordWebhook) {
ctx.waitUntil(sendDiscordNotification(env.theDbaDiscordWebhook, data).catch((e) => console.error(e)));
}
The important word there is waitUntil. The notifications are sent after the user already has their confirmation, not before, so a slow email service can never hold up the response or make the form feel sluggish. If either service is not configured, or it fails, it is skipped and swallowed silently. The person registering always gets a fast, clean confirmation regardless of what is happening behind the scenes.
It is, in the end, a contact form. But it saves reliably, resists spam, works with JavaScript switched off, and tells the team instantly, all from one small Worker with no server to maintain. Sometimes the most ordinary-looking feature on a site is the one worth getting completely right.
Built To Be Found
Even at the pre-launch stage, the site is set up to be understood by search engines and AI tools rather than treated as an afterthought. Each page ships a canonical URL, full Open Graph and Twitter card metadata, correct en-GB language tags, and an Organization schema in JSON-LD, so Google and AI assistants have a clean, machine-readable description of what the DBA is and who it serves. It is the same structured-data thinking I apply on the larger dog-industry sites, put in place from day one here so the association starts building its footprint before it has even incorporated.
The Road to Launch
The landing page is stage one. The commitment on the site is to launch the full member offering shortly after, and that is a considerably bigger build: a member portal with sign-in and profiles, a verified application process that checks insurance evidence and, for regulated businesses, Animal Activities Licence details, a public directory that lets dog owners search for trustworthy professionals by location and service, and a Trust Mark that only verified members may display.
None of that architecture is locked in yet, and that is deliberate. The current site is intentionally lean so that the bigger decisions, around authentication, payments, file uploads, and directory search, can be made properly when that work begins, rather than being boxed in early by choices made for a landing page. What exists now is a fast, sturdy foundation and a clear direction, which is exactly what a trade body in formation should be putting in front of its first members.
Meta
- Year: 2026
- Skills: Astro 5, TypeScript, Tailwind CSS 4, Cloudflare Workers, Cloudflare D1, Resend
- Visit site: https://thedba.org.uk
Related Projects
- DogBusiness.co.uk
- Dog Business School