chore: baseline of the live help4bis.com docroot as of 2026-10-23 (cockpit #168)
Excludes analytics/data, vendor, support, .env, ACME tokens. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,540 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- Version: 1.2.0 | Created: 2026-05-05 | Updated: 2026-08-16 -->
|
||||
<html lang="en-AU">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Crohamhurst Case Study | HELP4BIS</title>
|
||||
<meta name="description" content="How I built Crohamhurst.app: a Gann and astronomical cycle analysis toolkit for financial market researchers, built as a metered SaaS with five specialist computation modules.">
|
||||
<meta name="author" content="HELP4BIS">
|
||||
<meta name="publisher" content="Dutch Digital Dynamics Pty Ltd">
|
||||
<meta name="language" content="en-AU">
|
||||
<meta name="geo.region" content="AU-QLD">
|
||||
<link rel="canonical" href="https://help4bis.com/work/crohamhurst-app.html">
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content="https://help4bis.com/work/crohamhurst-app.html">
|
||||
<meta property="og:site_name" content="HELP4BIS">
|
||||
<meta property="og:title" content="Crohamhurst Case Study | HELP4BIS">
|
||||
<meta property="og:description" content="A Gann and cycle analysis SaaS toolkit for financial researchers: five computation modules, metered compute pricing, and a nod to Queensland's Crohamhurst Observatory.">
|
||||
<meta property="og:image" content="https://help4bis.com/assets/images/port-crohamhurst.png">
|
||||
<meta property="og:locale" content="en_AU">
|
||||
<link rel="icon" type="image/jpeg" href="../assets/images/logo-favicon.jpg"> <link rel="stylesheet" href="../assets/css/style.css">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"@id": "https://help4bis.com/work/crohamhurst-app.html#webpage",
|
||||
"url": "https://help4bis.com/work/crohamhurst-app.html",
|
||||
"name": "Crohamhurst Case Study | HELP4BIS",
|
||||
"description": "Gann and astronomical cycle analysis SaaS toolkit with metered compute pricing and five specialist modules.",
|
||||
"isPartOf": {"@id": "https://help4bis.com/#website"},
|
||||
"breadcrumb": {
|
||||
"@type": "BreadcrumbList",
|
||||
"itemListElement": [
|
||||
{"@type": "ListItem", "position": 1, "name": "Home", "item": "https://help4bis.com/"},
|
||||
{"@type": "ListItem", "position": 2, "name": "Our Work", "item": "https://help4bis.com/#portfolio"},
|
||||
{"@type": "ListItem", "position": 3, "name": "Crohamhurst", "item": "https://help4bis.com/work/crohamhurst-app.html"}
|
||||
]
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.cs-hero {
|
||||
background: linear-gradient(160deg, var(--ink) 0%, var(--ink-mid) 60%, #1a1200 100%);
|
||||
padding: var(--sp-16) 0 var(--sp-12);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.cs-hero::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -30%;
|
||||
right: -15%;
|
||||
width: 60%;
|
||||
height: 200%;
|
||||
background: radial-gradient(circle, rgba(217,119,6,.07) 0%, transparent 65%);
|
||||
pointer-events: none;
|
||||
}
|
||||
.cs-breadcrumb {
|
||||
font-size: 13px;
|
||||
color: rgba(255,255,255,.45);
|
||||
margin-bottom: var(--sp-5);
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
}
|
||||
.cs-breadcrumb a { color: rgba(255,255,255,.45); }
|
||||
.cs-breadcrumb a:hover { color: var(--white); }
|
||||
.cs-breadcrumb span { color: rgba(255,255,255,.25); }
|
||||
.cs-hero h1 { color: var(--white); max-width: 820px; margin-bottom: var(--sp-4); }
|
||||
.cs-hero-sub {
|
||||
font-size: clamp(16px, 2vw, 20px);
|
||||
color: rgba(255,255,255,.65);
|
||||
max-width: 680px; line-height: 1.65; margin-bottom: var(--sp-6);
|
||||
}
|
||||
.cs-hero-actions { display: flex; gap: 12px; flex-wrap: wrap; }
|
||||
.btn-gold {
|
||||
background: linear-gradient(135deg, #D97706, #B45309);
|
||||
color: var(--white); border-color: transparent;
|
||||
box-shadow: 0 4px 14px rgba(217,119,6,.30);
|
||||
}
|
||||
.btn-gold:hover {
|
||||
background: linear-gradient(135deg, #B45309, #92400E);
|
||||
color: var(--white); transform: translateY(-2px);
|
||||
}
|
||||
.cs-kpis {
|
||||
display: grid; grid-template-columns: repeat(2, 1fr);
|
||||
gap: 16px; margin-top: var(--sp-8); padding-top: var(--sp-8);
|
||||
border-top: 1px solid rgba(255,255,255,.08);
|
||||
}
|
||||
@media (min-width: 640px) { .cs-kpis { grid-template-columns: repeat(4, 1fr); } }
|
||||
.cs-kpi { text-align: center; }
|
||||
.cs-kpi-value {
|
||||
font-family: var(--font-head); font-size: clamp(32px, 4vw, 52px);
|
||||
font-weight: 900; color: #D97706; line-height: 1; letter-spacing: -0.04em;
|
||||
}
|
||||
.cs-kpi-label {
|
||||
font-size: 12px; font-weight: 600; text-transform: uppercase;
|
||||
letter-spacing: .12em; color: rgba(255,255,255,.45); margin-top: 6px;
|
||||
}
|
||||
.cs-feature-grid {
|
||||
display: grid; grid-template-columns: 1fr; gap: 24px; margin-top: var(--sp-6);
|
||||
}
|
||||
@media (min-width: 640px) { .cs-feature-grid { grid-template-columns: repeat(2, 1fr); } }
|
||||
@media (min-width: 900px) { .cs-feature-grid { grid-template-columns: repeat(3, 1fr); } }
|
||||
.cs-feature-card {
|
||||
background: var(--white); border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-lg); padding: 24px; box-shadow: var(--shadow-card);
|
||||
}
|
||||
.cs-feature-card h4 { font-size: 15px; margin-bottom: 8px; color: var(--ink); }
|
||||
.cs-feature-card p { font-size: 14px; color: var(--grey-600); line-height: 1.6; margin: 0; }
|
||||
.cs-feature-icon {
|
||||
width: 36px; height: 36px; background: var(--grey-50); border-radius: var(--r-md);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
margin-bottom: 14px; font-size: 18px;
|
||||
}
|
||||
.cs-module-list {
|
||||
margin: 0; padding: 0; list-style: none;
|
||||
display: grid; grid-template-columns: 1fr; gap: 12px; margin-top: var(--sp-5);
|
||||
}
|
||||
@media (min-width: 640px) { .cs-module-list { grid-template-columns: repeat(2, 1fr); } }
|
||||
.cs-module-item {
|
||||
background: var(--white); border: 1px solid var(--grey-100);
|
||||
border-left: 3px solid #D97706;
|
||||
border-radius: var(--r-md); padding: 16px 20px; box-shadow: var(--shadow-sm);
|
||||
}
|
||||
.cs-module-item strong { display: block; font-size: 14px; font-weight: 600; color: var(--ink); margin-bottom: 4px; }
|
||||
.cs-module-item span { font-size: 13px; color: var(--grey-600); line-height: 1.5; }
|
||||
.cs-pricing-grid {
|
||||
display: grid; grid-template-columns: 1fr; gap: 16px; margin-top: var(--sp-6);
|
||||
}
|
||||
@media (min-width: 640px) { .cs-pricing-grid { grid-template-columns: repeat(2, 1fr); } }
|
||||
@media (min-width: 900px) { .cs-pricing-grid { grid-template-columns: repeat(4, 1fr); } }
|
||||
.cs-pricing-card {
|
||||
background: var(--white); border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-lg); padding: 20px; box-shadow: var(--shadow-card);
|
||||
text-align: center;
|
||||
}
|
||||
.cs-pricing-card.featured {
|
||||
border-color: #D97706;
|
||||
box-shadow: 0 0 0 2px rgba(217,119,6,.15), var(--shadow-card);
|
||||
}
|
||||
.cs-pricing-card .tier-name { font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .1em; color: var(--grey-400); margin-bottom: 8px; }
|
||||
.cs-pricing-card .tier-price { font-family: var(--font-head); font-size: 28px; font-weight: 900; color: var(--ink); letter-spacing: -.03em; line-height: 1; }
|
||||
.cs-pricing-card .tier-price span { font-size: 14px; font-weight: 500; color: var(--grey-500); }
|
||||
.cs-pricing-card .tier-units { font-size: 13px; color: var(--grey-600); margin-top: 10px; font-weight: 500; }
|
||||
.cs-pricing-card .tier-desc { font-size: 12px; color: var(--grey-500); margin-top: 6px; line-height: 1.5; }
|
||||
.cs-stack { display: flex; flex-wrap: wrap; gap: 8px; margin-top: var(--sp-4); }
|
||||
.cs-stack-tag {
|
||||
background: var(--grey-50); border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-full); padding: 6px 14px; font-size: 13px; font-weight: 500; color: var(--grey-600);
|
||||
}
|
||||
.cs-divider { height: 1px; background: var(--grey-100); margin: var(--sp-8) 0; }
|
||||
.cs-two-col {
|
||||
display: grid; grid-template-columns: 1fr; gap: var(--sp-8); align-items: start;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.cs-two-col { grid-template-columns: 1fr 1fr; }
|
||||
.cs-two-col--wide { grid-template-columns: 3fr 2fr; }
|
||||
}
|
||||
.cs-quote {
|
||||
border-left: 3px solid #D97706;
|
||||
padding: var(--sp-4) var(--sp-5); background: rgba(217,119,6,.04);
|
||||
border-radius: 0 var(--r-md) var(--r-md) 0; margin: var(--sp-5) 0;
|
||||
}
|
||||
.cs-quote p { font-size: 17px; line-height: 1.7; color: var(--grey-800); font-style: italic; margin: 0; }
|
||||
.cs-honest {
|
||||
background: var(--grey-50); border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-lg); padding: var(--sp-4) var(--sp-5); margin: var(--sp-5) 0;
|
||||
}
|
||||
.cs-honest-label {
|
||||
font-size: 11px; font-weight: 700; text-transform: uppercase;
|
||||
letter-spacing: .12em; color: var(--grey-400); margin-bottom: 8px;
|
||||
}
|
||||
.cs-honest p { font-size: 14px; color: var(--grey-600); line-height: 1.65; margin: 0; }
|
||||
.cs-cta {
|
||||
background: linear-gradient(135deg, var(--ink-mid), var(--ink));
|
||||
border-radius: var(--r-2xl); padding: var(--sp-10) var(--sp-8); text-align: center;
|
||||
}
|
||||
.cs-cta h2 { color: var(--white); margin-bottom: var(--sp-4); }
|
||||
.cs-cta p { color: rgba(255,255,255,.65); max-width: 560px; margin: 0 auto var(--sp-6); font-size: 17px; line-height: 1.7; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- NAV -->
|
||||
<nav class="nav" role="navigation" aria-label="Main navigation">
|
||||
<div class="nav__inner">
|
||||
<a class="nav__logo" href="../index.html" aria-label="HELP4BIS home">
|
||||
<img src="../assets/images/logo-cropped.jpg" alt="HELP4BIS" width="140" height="38">
|
||||
</a>
|
||||
<ul class="nav__links" id="nav-links" role="list">
|
||||
<li class="nav__dropdown">
|
||||
<button class="nav__trigger" aria-haspopup="true" aria-expanded="false">Services <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg></button>
|
||||
<ul class="nav__dropdown-menu" role="menu">
|
||||
<li class="nav__menu-group">WordPress</li>
|
||||
<li><a href="../managed-wordpress.html" role="menuitem">Tailored Website Management</a></li>
|
||||
<li><a href="../care-plans.html" role="menuitem">WP Care Plans <span class="menu-price">from $49/mo</span></a></li>
|
||||
<li><a href="../sos-fix.html" role="menuitem">WP SOS Fix <span class="menu-price">$97 flat</span></a></li>
|
||||
<li><a href="../ai-integration.html" role="menuitem">AI Integration</a></li>
|
||||
<li><a href="../plugin-development.html" role="menuitem">Custom Plugin Development</a></li> </ul>
|
||||
</li>
|
||||
<li><a href="../about.html">About</a></li>
|
||||
<li><a href="../index.html#portfolio">Our Work</a></li>
|
||||
<li><a href="../index.html#pricing">Pricing</a></li>
|
||||
<li><a href="../blog/index.html">Blog</a></li>
|
||||
<li><a href="../your-first-week-with-ai.html">AI Guide</a></li>
|
||||
<li><a href="../contact.html">Contact</a></li>
|
||||
<li class="nav__cta-mobile" aria-hidden="true">
|
||||
<a href="../contact.html" class="btn btn-primary">Get Started</a>
|
||||
<a href="../sos-fix.html" class="btn btn-secondary">SOS Fix, $97</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="nav__cta">
|
||||
<a href="../sos-fix.html" class="btn btn-secondary btn-sm">SOS Fix, $97</a>
|
||||
<a href="../contact.html" class="btn btn-primary btn-sm">Get Started</a>
|
||||
</div>
|
||||
<button class="nav__burger" id="nav-burger" aria-label="Open menu" aria-expanded="false" aria-controls="nav-links">
|
||||
<span></span><span></span><span></span>
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- HERO -->
|
||||
<section class="cs-hero" aria-labelledby="cs-heading">
|
||||
<div class="container">
|
||||
<div class="cs-breadcrumb">
|
||||
<a href="../index.html">Home</a>
|
||||
<span>›</span>
|
||||
<a href="../index.html#portfolio">Our Work</a>
|
||||
<span>›</span>
|
||||
<span style="color:rgba(255,255,255,.7);">Crohamhurst</span>
|
||||
</div>
|
||||
<p class="eyebrow" style="color:rgba(217,119,6,.9);">Case Study: Financial Research SaaS</p>
|
||||
<h1 id="cs-heading">Crohamhurst.<br>Gann and cycle analysis<br>built as a proper toolkit.</h1>
|
||||
<p class="cs-hero-sub">A metered SaaS platform I built for financial market researchers who work with astronomical cycles and W.D. Gann methodology. Five specialist computation modules, pricing based on usage, and an API backend that handles the heavy calculation work so the browser doesn't have to.</p>
|
||||
<div class="cs-hero-actions">
|
||||
<a href="https://crohamhurst.app" target="_blank" rel="noopener" class="btn btn-gold">Visit crohamhurst.app →</a>
|
||||
<a href="../ai-integration.html" class="btn btn-secondary">See Custom Development</a>
|
||||
</div>
|
||||
<div class="cs-kpis">
|
||||
<div class="cs-kpi">
|
||||
<div class="cs-kpi-value">5</div>
|
||||
<div class="cs-kpi-label">Analysis Modules</div>
|
||||
</div>
|
||||
<div class="cs-kpi">
|
||||
<div class="cs-kpi-value">SaaS</div>
|
||||
<div class="cs-kpi-label">Product Type</div>
|
||||
</div>
|
||||
<div class="cs-kpi">
|
||||
<div class="cs-kpi-value">3</div>
|
||||
<div class="cs-kpi-label">Paid Tiers</div>
|
||||
</div>
|
||||
<div class="cs-kpi">
|
||||
<div class="cs-kpi-value">AU</div>
|
||||
<div class="cs-kpi-label">Hosted</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- OVERVIEW -->
|
||||
<section class="section" aria-labelledby="overview-heading">
|
||||
<div class="container">
|
||||
<div class="cs-two-col cs-two-col--wide">
|
||||
<div>
|
||||
<p class="eyebrow">Overview</p>
|
||||
<h2 id="overview-heading">Where it came from</h2>
|
||||
<p class="large">Crohamhurst Observatory in Queensland is where Inigo Jones spent decades studying planetary cycles and their relationship to weather and crop patterns. Jones's method, correlating astronomical data with terrestrial outcomes, became the foundation for a style of market analysis popularised by W.D. Gann in the early twentieth century.</p>
|
||||
<p>I picked the name deliberately. Researchers working with Gann methodology need computation tools that handle ephemeris calculations, cycle detection, and geometric price analysis quickly and accurately. Spreadsheets work up to a point. I tried. But five year planetary aspect timelines with custom orb tolerances are the kind of thing that demands a purpose built tool.</p>
|
||||
<p>That's what I built. Five specialist modules, each focused on one type of Gann or cycle analysis. A metered compute model so occasional users pay nothing and heavy users pay for what they use. I host it on Australian infrastructure.</p>
|
||||
<div class="cs-quote">
|
||||
<p>"Gann analysis isn't obscure any more. There's a real community of researchers who take the methodology seriously and need tools that match that seriousness. I built Crohamhurst for them."</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="background:linear-gradient(135deg,#1a1200,#2d1f00);border-radius:var(--r-xl);padding:var(--sp-8);box-shadow:var(--shadow-lg);">
|
||||
<div style="text-align:center;margin-bottom:var(--sp-6);">
|
||||
<div style="font-size:48px;margin-bottom:12px;">🔭</div>
|
||||
<div style="font-family:var(--font-head);font-size:22px;font-weight:900;color:#D97706;letter-spacing:-.02em;">CROHAMHURST</div>
|
||||
<div style="font-size:12px;color:rgba(255,255,255,.4);letter-spacing:.15em;text-transform:uppercase;margin-top:4px;">Gann & Cycle Analysis</div>
|
||||
</div>
|
||||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;">
|
||||
<div style="background:rgba(255,255,255,.05);border-radius:var(--r-md);padding:12px;text-align:center;">
|
||||
<div style="font-size:20px;font-weight:800;color:#D97706;font-family:var(--font-head);">50</div>
|
||||
<div style="font-size:10px;color:rgba(255,255,255,.4);text-transform:uppercase;letter-spacing:.1em;margin-top:3px;">Free units/day</div>
|
||||
</div>
|
||||
<div style="background:rgba(217,119,6,.12);border:1px solid rgba(217,119,6,.25);border-radius:var(--r-md);padding:12px;text-align:center;">
|
||||
<div style="font-size:20px;font-weight:800;color:#D97706;font-family:var(--font-head);">10K</div>
|
||||
<div style="font-size:10px;color:rgba(255,255,255,.4);text-transform:uppercase;letter-spacing:.1em;margin-top:3px;">Pro units/day</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cs-stack" style="margin-top:20px;">
|
||||
<span class="cs-stack-tag">React</span>
|
||||
<span class="cs-stack-tag">Python API</span>
|
||||
<span class="cs-stack-tag">PostgreSQL</span>
|
||||
<span class="cs-stack-tag">Stripe billing</span>
|
||||
<span class="cs-stack-tag">JWT auth</span>
|
||||
<span class="cs-stack-tag">Australian hosting</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- MODULES -->
|
||||
<section class="section section--alt" aria-labelledby="modules-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Computation Modules</p>
|
||||
<h2 id="modules-heading">Five tools that do actual work</h2>
|
||||
<p style="max-width:640px;color:var(--grey-600);font-size:17px;line-height:1.7;margin-bottom:0;">Each module handles a specific type of analysis. They run against the same backend API I wrote, pull from the same astronomical data, and charge compute units based on the computational cost of the request.</p>
|
||||
|
||||
<ul class="cs-module-list">
|
||||
<li class="cs-module-item">
|
||||
<strong>Ephemeris Timelines</strong>
|
||||
<span>Calculates planetary aspect windows over a user-specified date range. Produces a timeline of alignment dates that Gann researchers use to identify potential turning point zones in a market.</span>
|
||||
</li>
|
||||
<li class="cs-module-item">
|
||||
<strong>Bradley Siderograph</strong>
|
||||
<span>Generates the Bradley siderograph curve, a turning point prediction model first published in 1948, with both the original and the Hannula variant. Used to overlay against price charts to identify potential reversal dates.</span>
|
||||
</li>
|
||||
<li class="cs-module-item">
|
||||
<strong>Gann Square of Nine</strong>
|
||||
<span>A geometric price level calculator based on W.D. Gann's Square of Nine method. Enter a price anchor and the module returns the full grid of geometrically significant support and resistance levels.</span>
|
||||
</li>
|
||||
<li class="cs-module-item">
|
||||
<strong>Cycle Scanner</strong>
|
||||
<span>Applies spectral analysis to price series data to identify dominant cycle periods. Surfaces repeating time structures in market data that manual chart reading would miss.</span>
|
||||
</li>
|
||||
<li class="cs-module-item">
|
||||
<strong>Historical Analogs</strong>
|
||||
<span>Pattern matching across historical price data. Given a recent market structure, it finds the closest historical matches and surfaces what followed. A research tool, not a prediction system.</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- HOW IT WORKS -->
|
||||
<section class="section" aria-labelledby="how-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Architecture</p>
|
||||
<h2 id="how-heading">How the platform is built</h2>
|
||||
<p style="max-width:640px;color:var(--grey-600);font-size:17px;line-height:1.7;margin-bottom:0;">I put the calculation engine in a Python API backend, not in the browser. That's the right place for it: astronomical ephemeris computation, FFT cycle analysis, and historical pattern matching aren't jobs for JavaScript in the browser.</p>
|
||||
|
||||
<div class="cs-feature-grid" style="margin-top:var(--sp-6);">
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🖥️</div>
|
||||
<h4>React frontend</h4>
|
||||
<p>A clean, responsive single-page application. Module inputs, result visualisations, account management, and a blog for research commentary. I built it to be fast and uncluttered. Researchers want results, not UI.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">⚙️</div>
|
||||
<h4>Python computation API</h4>
|
||||
<p>The backend handles all mathematical heavy lifting: ephemeris lookups, spectral analysis, geometric calculations, and pattern matching against historical data. Versioned endpoints, structured responses, and async processing for jobs that run longer.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">📊</div>
|
||||
<h4>Metered compute units</h4>
|
||||
<p>Every API request consumes compute units proportional to its cost. Simple lookups are cheap. Deep cycle scans over long date ranges cost more. The model is transparent: users see their usage in real time and can choose the tier that fits how they work.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🔐</div>
|
||||
<h4>Auth and accounts</h4>
|
||||
<p>Authentication with JWT and session management. Users register, log in, and manage their subscription tier within the app. My admin tools let me assign tiers and adjust unit quotas without touching the database.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">💳</div>
|
||||
<h4>Stripe billing</h4>
|
||||
<p>Subscription billing handled by Stripe. Tier upgrades and downgrades take effect immediately. The free tier requires no payment method, so researchers can evaluate the tools before they commit to a paid plan.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">📝</div>
|
||||
<h4>Research blog and announcements</h4>
|
||||
<p>A blog built into the app for publishing Gann and cycle research. An announcement system for product updates and module releases. I manage both from the admin panel without any external CMS.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- PRICING -->
|
||||
<section class="section section--alt" aria-labelledby="pricing-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Pricing Model</p>
|
||||
<h2 id="pricing-heading">Tiers based on usage</h2>
|
||||
<p style="max-width:640px;color:var(--grey-600);font-size:17px;line-height:1.7;margin-bottom:0;">The metered model was a deliberate choice. Assumed is that no two Gann researchers work the same way: some run a handful of checks per week, others run hundreds of queries a day building research archives. A flat subscription penalises light users. A pure pay per use model creates anxiety. Metered tiers split the difference.</p>
|
||||
|
||||
<div class="cs-pricing-grid">
|
||||
<div class="cs-pricing-card">
|
||||
<div class="tier-name">Free</div>
|
||||
<div class="tier-price">$0</div>
|
||||
<div class="tier-units">50 units / day</div>
|
||||
<div class="tier-desc">Evaluate the tools. Run simple calculations. No payment method required.</div>
|
||||
</div>
|
||||
<div class="cs-pricing-card">
|
||||
<div class="tier-name">Hobbyist</div>
|
||||
<div class="tier-price">$19<span>/mo</span></div>
|
||||
<div class="tier-units">1,000 units / day</div>
|
||||
<div class="tier-desc">Regular research sessions. Enough headroom for daily analysis across multiple instruments.</div>
|
||||
</div>
|
||||
<div class="cs-pricing-card featured">
|
||||
<div class="tier-name">Pro</div>
|
||||
<div class="tier-price">$79<span>/mo</span></div>
|
||||
<div class="tier-units">10,000 units / day</div>
|
||||
<div class="tier-desc">Heavy research and bulk analysis. Running all five modules across multiple timeframes and instruments.</div>
|
||||
</div>
|
||||
<div class="cs-pricing-card">
|
||||
<div class="tier-name">Lifetime</div>
|
||||
<div class="tier-price">n/a</div>
|
||||
<div class="tier-units">10,000 units / day</div>
|
||||
<div class="tier-desc">Pro level access with no monthly billing, assigned by admin. Available to founding users.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cs-honest" style="margin-top:var(--sp-6);">
|
||||
<div class="cs-honest-label">On the unit model</div>
|
||||
<p>Compute units aren't a trick to squeeze more money out of users. Simple requests consume very few units. The metering exists because a cycle scan over a multi year date range at high resolution costs me more to compute than a Square of Nine grid does. The model reflects what the calculation costs. Usage is visible in the dashboard at all times and resets daily. No rollover, no surprise bills.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- HONEST NOTE -->
|
||||
<section class="section" aria-labelledby="honest-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Straight Talking</p>
|
||||
<h2 id="honest-heading">What kind of product this is</h2>
|
||||
<div class="cs-two-col">
|
||||
<div>
|
||||
<p>Crohamhurst is a specialist tool for a specific audience. It isn't trying to be a general trading platform or a charting service for retail investors. W.D. Gann methodology has a dedicated community of researchers and traders who take the approach seriously and need computation tools built for it. That's who I built this for.</p>
|
||||
<p>The five modules cover the core analytical methods in the Gann tradition: planetary aspects, geometric price levels, cycle detection, and pattern recognition. They are presented as research tools. The Historical Analogs module in particular surfaces what has followed similar price structures in the past. It doesn't tell users what to do. The work of interpretation stays with the researcher.</p>
|
||||
<p>I built the platform alongside my own active Gann research practice, so the modules were tested against real workflows whilst I developed them, not designed in the abstract. That matters for tools where the edge cases are what researchers hit first.</p>
|
||||
</div>
|
||||
<div>
|
||||
<div class="cs-honest">
|
||||
<div class="cs-honest-label">On the Crohamhurst name</div>
|
||||
<p>Crohamhurst Observatory near Maleny in the Sunshine Coast hinterland was where Inigo Jones conducted his long range climate and crop forecasting from the early 1900s through to 1954. Jones's long range forecasts were published annually and are still considered in Australian agricultural circles. His methods, observing planetary cycles over decades, sit in the same tradition as Gann's market work. The name is my nod to that Queensland connection and to the seriousness of the research tradition the platform supports.</p>
|
||||
</div>
|
||||
<div class="cs-honest" style="margin-top:var(--sp-4);">
|
||||
<div class="cs-honest-label">On market predictions</div>
|
||||
<p>Nothing on Crohamhurst.app constitutes financial advice. The tools surface data and analysis for researchers to interpret. Gann methodology is a research discipline, not a signal service. Users are researchers who understand what they are working with and take responsibility for their own analysis.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- TECH STACK -->
|
||||
<section class="section section--alt" aria-labelledby="stack-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Technical Details</p>
|
||||
<h2 id="stack-heading">The stack</h2>
|
||||
<p style="max-width:640px;color:var(--grey-600);font-size:17px;line-height:1.7;margin-bottom:var(--sp-5);">A modern React frontend, a Python backend API for computation, PostgreSQL for data persistence, Stripe for billing. Containerised and hosted on Australian infrastructure in Brisbane.</p>
|
||||
<div class="cs-stack">
|
||||
<span class="cs-stack-tag">React</span>
|
||||
<span class="cs-stack-tag">Python</span>
|
||||
<span class="cs-stack-tag">PostgreSQL</span>
|
||||
<span class="cs-stack-tag">Docker</span>
|
||||
<span class="cs-stack-tag">JWT auth</span>
|
||||
<span class="cs-stack-tag">Stripe</span>
|
||||
<span class="cs-stack-tag">Australian hosting</span>
|
||||
<span class="cs-stack-tag">Let's Encrypt SSL</span>
|
||||
</div>
|
||||
<p style="margin-top:var(--sp-4);font-size:14px;color:var(--grey-600);">I host it on the same Brisbane server as the rest of the HELP4BIS portfolio. The containerised architecture keeps the frontend and API cleanly separated and lets me scale the computation side on its own if demand requires it.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- CTA -->
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<div class="cs-cta">
|
||||
<h2>Building something that requires specialist computation?</h2>
|
||||
<p>Crohamhurst is an example of what's possible when the right computation engine sits behind a clean interface. If your product involves complex calculations, specialist algorithms, or pricing based on usage, we've built this before.</p>
|
||||
<div class="cs-hero-actions" style="justify-content:center;">
|
||||
<a href="../plugin-development.html" class="btn btn-primary btn-lg">Custom Development</a>
|
||||
<a href="../contact.html" class="btn btn-secondary btn-lg">Talk to us</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-top:var(--sp-8);text-align:center;">
|
||||
<a href="../index.html#portfolio" style="font-size:14px;color:var(--grey-400);">← Back to all work</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FOOTER -->
|
||||
<footer class="footer" aria-label="Site footer">
|
||||
<div class="container">
|
||||
<div class="footer__grid">
|
||||
<div class="footer__brand">
|
||||
<img src="../assets/images/logo-cropped.jpg" alt="HELP4BIS" width="140" height="38">
|
||||
<p>Managed WordPress hosting and maintenance for Australian small businesses. Brisbane based, personal service, WordPress specialist, Brisbane.</p>
|
||||
<p style="margin-top:8px; font-size:12px; color:rgba(255,255,255,.25);">Dutch Digital Dynamics Pty Ltd · ABN 86 081 237 087</p>
|
||||
</div>
|
||||
<div class="footer__col">
|
||||
<h4>Services</h4>
|
||||
<ul class="footer__links">
|
||||
<li><a href="../managed-wordpress.html">Tailored Website Management</a></li>
|
||||
<li><a href="../care-plans.html">WP Care Plans</a></li>
|
||||
<li><a href="../sos-fix.html">WP SOS Fix</a></li>
|
||||
<li><a href="../ai-integration.html">AI Integration</a></li>
|
||||
<li><a href="../plugin-development.html">Plugin Development</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer__col">
|
||||
<h4>Our Work</h4>
|
||||
<ul class="footer__links">
|
||||
<li><a href="dayboro-au.html">Dayboro.au</a></li>
|
||||
<li><a href="gardenbuddy-au.html">GardenBuddy.au</a></li>
|
||||
<li><a href="tawnytrails.html">Tawny Trails</a></li>
|
||||
<li><a href="rds-ink.html">Running Duck Studio</a></li>
|
||||
<li><a href="localbuddy-au.html">LocalBuddy</a></li>
|
||||
<li><a href="m8chat-au.html">M8Chat</a></li>
|
||||
<li><a href="nightcap-nm.html">Nightcap Natural Medicine</a></li>
|
||||
<li><a href="crohamhurst-app.html">Crohamhurst</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer__col">
|
||||
<h4>Contact</h4>
|
||||
<ul class="footer__links">
|
||||
<li><a href="mailto:project@help4bis.com">project@help4bis.com</a></li>
|
||||
<li><a href="../contact.html">Submit a Brief</a></li>
|
||||
<li><a href="../sos-fix.html">Emergency Fix</a></li>
|
||||
</ul>
|
||||
<p style="margin-top:16px; font-size:12px; color:rgba(255,255,255,.3);">Brisbane, Queensland<br>Response within 24 business hours</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer__bottom">
|
||||
<span>© 2026 HELP4BIS, a trading name of Dutch Digital Dynamics Pty Ltd · ABN 86 081 237 087</span>
|
||||
<span><a href="../privacy.html">Privacy</a> · <a href="../terms.html">Terms</a></span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<button id="back-to-top" aria-label="Back to top">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="18 15 12 9 6 15"/></svg>
|
||||
</button>
|
||||
|
||||
<script src="../assets/js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,810 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- Version: 1.2.0 | Created: 2026-05-05 | Updated: 2026-08-16 -->
|
||||
<html lang="en-AU">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Dayboro.au Case Study | HELP4BIS</title>
|
||||
<meta name="description" content="How I built dayboro.au: a hyperlocal weather platform, nine interactive calculators, a Flutter PWA on Google Play, and a Lions Club business directory, all running from a single WordPress instance in Dayboro, Queensland.">
|
||||
<meta name="author" content="HELP4BIS">
|
||||
<meta name="publisher" content="Dutch Digital Dynamics Pty Ltd">
|
||||
<meta name="language" content="en-AU">
|
||||
<meta name="geo.region" content="AU-QLD">
|
||||
<link rel="canonical" href="https://help4bis.com/work/dayboro-au.html">
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content="https://help4bis.com/work/dayboro-au.html">
|
||||
<meta property="og:site_name" content="HELP4BIS">
|
||||
<meta property="og:title" content="Dayboro.au Case Study | HELP4BIS">
|
||||
<meta property="og:description" content="22 years of weather data, nine live data calculators, a Flutter PWA on Google Play, and a community business directory. Here is how I built dayboro.au.">
|
||||
<meta property="og:image" content="https://help4bis.com/assets/images/port-dayboro.jpg">
|
||||
<meta property="og:locale" content="en_AU">
|
||||
<link rel="icon" type="image/jpeg" href="../assets/images/logo-favicon.jpg"> <link rel="stylesheet" href="../assets/css/style.css">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"@id": "https://help4bis.com/work/dayboro-au.html#webpage",
|
||||
"url": "https://help4bis.com/work/dayboro-au.html",
|
||||
"name": "Dayboro.au Case Study | HELP4BIS",
|
||||
"description": "A detailed breakdown of how dayboro.au was built: weather station integration, nine interactive calculators, Flutter PWA, Lions Club business directory, and Gann seasonal forecasting.",
|
||||
"isPartOf": {"@id": "https://help4bis.com/#website"},
|
||||
"breadcrumb": {
|
||||
"@type": "BreadcrumbList",
|
||||
"itemListElement": [
|
||||
{"@type": "ListItem", "position": 1, "name": "Home", "item": "https://help4bis.com/"},
|
||||
{"@type": "ListItem", "position": 2, "name": "Our Work", "item": "https://help4bis.com/#portfolio"},
|
||||
{"@type": "ListItem", "position": 3, "name": "Dayboro.au", "item": "https://help4bis.com/work/dayboro-au.html"}
|
||||
]
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* ── Case study specific styles ── */
|
||||
.cs-hero {
|
||||
background: linear-gradient(160deg, var(--ink) 0%, var(--ink-mid) 60%, #1a2a1a 100%);
|
||||
padding: var(--sp-16) 0 var(--sp-12);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.cs-hero::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -30%;
|
||||
right: -15%;
|
||||
width: 60%;
|
||||
height: 200%;
|
||||
background: radial-gradient(circle, rgba(34,197,94,.06) 0%, transparent 65%);
|
||||
pointer-events: none;
|
||||
}
|
||||
.cs-breadcrumb {
|
||||
font-size: 13px;
|
||||
color: rgba(255,255,255,.45);
|
||||
margin-bottom: var(--sp-5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.cs-breadcrumb a { color: rgba(255,255,255,.45); }
|
||||
.cs-breadcrumb a:hover { color: var(--white); }
|
||||
.cs-breadcrumb span { color: rgba(255,255,255,.25); }
|
||||
.cs-hero h1 {
|
||||
color: var(--white);
|
||||
max-width: 820px;
|
||||
margin-bottom: var(--sp-4);
|
||||
}
|
||||
.cs-hero-sub {
|
||||
font-size: clamp(16px, 2vw, 20px);
|
||||
color: rgba(255,255,255,.65);
|
||||
max-width: 680px;
|
||||
line-height: 1.65;
|
||||
margin-bottom: var(--sp-6);
|
||||
}
|
||||
.cs-hero-actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.btn-green {
|
||||
background: linear-gradient(135deg, #22C55E, #16a34a);
|
||||
color: var(--white);
|
||||
border-color: transparent;
|
||||
box-shadow: 0 4px 14px rgba(34,197,94,.30);
|
||||
}
|
||||
.btn-green:hover {
|
||||
background: linear-gradient(135deg, #16a34a, #15803d);
|
||||
color: var(--white);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
/* KPI stats */
|
||||
.cs-kpis {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 16px;
|
||||
margin-top: var(--sp-8);
|
||||
padding-top: var(--sp-8);
|
||||
border-top: 1px solid rgba(255,255,255,.08);
|
||||
}
|
||||
@media (min-width: 640px) { .cs-kpis { grid-template-columns: repeat(4, 1fr); } }
|
||||
.cs-kpi {
|
||||
text-align: center;
|
||||
}
|
||||
.cs-kpi-value {
|
||||
font-family: var(--font-head);
|
||||
font-size: clamp(32px, 4vw, 52px);
|
||||
font-weight: 900;
|
||||
color: var(--green);
|
||||
line-height: 1;
|
||||
letter-spacing: -0.04em;
|
||||
}
|
||||
.cs-kpi-label {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .12em;
|
||||
color: rgba(255,255,255,.45);
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
/* Feature grid */
|
||||
.cs-feature-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 24px;
|
||||
margin-top: var(--sp-6);
|
||||
}
|
||||
@media (min-width: 640px) { .cs-feature-grid { grid-template-columns: repeat(2, 1fr); } }
|
||||
@media (min-width: 900px) { .cs-feature-grid { grid-template-columns: repeat(3, 1fr); } }
|
||||
.cs-feature-card {
|
||||
background: var(--white);
|
||||
border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-lg);
|
||||
padding: 24px;
|
||||
box-shadow: var(--shadow-card);
|
||||
}
|
||||
.cs-feature-card h4 {
|
||||
font-size: 15px;
|
||||
margin-bottom: 8px;
|
||||
color: var(--ink);
|
||||
}
|
||||
.cs-feature-card p {
|
||||
font-size: 14px;
|
||||
color: var(--grey-600);
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
}
|
||||
.cs-feature-icon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
background: var(--grey-50);
|
||||
border-radius: var(--r-md);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 14px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
/* Calculator list */
|
||||
.cs-calc-list {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 12px;
|
||||
margin-top: var(--sp-5);
|
||||
}
|
||||
@media (min-width: 640px) { .cs-calc-list { grid-template-columns: repeat(2, 1fr); } }
|
||||
@media (min-width: 900px) { .cs-calc-list { grid-template-columns: repeat(3, 1fr); } }
|
||||
.cs-calc-item {
|
||||
background: var(--white);
|
||||
border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-md);
|
||||
padding: 16px 18px;
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
.cs-calc-item strong {
|
||||
display: block;
|
||||
font-family: var(--font-head);
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: var(--ink);
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.cs-calc-item span {
|
||||
font-size: 13px;
|
||||
color: var(--grey-600);
|
||||
line-height: 1.5;
|
||||
}
|
||||
.cs-calc-tier {
|
||||
display: inline-block;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .08em;
|
||||
padding: 2px 8px;
|
||||
border-radius: var(--r-full);
|
||||
margin-top: 8px;
|
||||
}
|
||||
.cs-calc-tier--free { background: rgba(34,197,94,.12); color: #16a34a; }
|
||||
.cs-calc-tier--premium { background: rgba(245,158,11,.12); color: #b45309; }
|
||||
|
||||
/* Stack tags */
|
||||
.cs-stack {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-top: var(--sp-4);
|
||||
}
|
||||
.cs-stack-tag {
|
||||
background: var(--grey-50);
|
||||
border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-full);
|
||||
padding: 6px 14px;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--grey-600);
|
||||
}
|
||||
|
||||
/* Section divider */
|
||||
.cs-divider {
|
||||
height: 1px;
|
||||
background: var(--grey-100);
|
||||
margin: var(--sp-8) 0;
|
||||
}
|
||||
|
||||
/* Two-col layout */
|
||||
.cs-two-col {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: var(--sp-8);
|
||||
align-items: start;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.cs-two-col { grid-template-columns: 1fr 1fr; }
|
||||
.cs-two-col--wide { grid-template-columns: 3fr 2fr; }
|
||||
}
|
||||
|
||||
/* Pull quote */
|
||||
.cs-quote {
|
||||
border-left: 3px solid var(--green);
|
||||
padding: var(--sp-4) var(--sp-5);
|
||||
background: rgba(34,197,94,.04);
|
||||
border-radius: 0 var(--r-md) var(--r-md) 0;
|
||||
margin: var(--sp-5) 0;
|
||||
}
|
||||
.cs-quote p {
|
||||
font-size: 17px;
|
||||
line-height: 1.7;
|
||||
color: var(--grey-800);
|
||||
font-style: italic;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Honest note */
|
||||
.cs-honest {
|
||||
background: var(--grey-50);
|
||||
border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-lg);
|
||||
padding: var(--sp-4) var(--sp-5);
|
||||
margin: var(--sp-5) 0;
|
||||
}
|
||||
.cs-honest-label {
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .12em;
|
||||
color: var(--grey-400);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.cs-honest p {
|
||||
font-size: 14px;
|
||||
color: var(--grey-600);
|
||||
line-height: 1.65;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* CTA block */
|
||||
.cs-cta {
|
||||
background: linear-gradient(135deg, var(--ink-mid), var(--ink));
|
||||
border-radius: var(--r-2xl);
|
||||
padding: var(--sp-10) var(--sp-8);
|
||||
text-align: center;
|
||||
}
|
||||
.cs-cta h2 { color: var(--white); margin-bottom: var(--sp-4); }
|
||||
.cs-cta p { color: rgba(255,255,255,.65); max-width: 560px; margin: 0 auto var(--sp-6); font-size: 17px; line-height: 1.7; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- ═══════════════════════════════════════════════
|
||||
NAV
|
||||
═══════════════════════════════════════════════ -->
|
||||
<nav class="nav" role="navigation" aria-label="Main navigation">
|
||||
<div class="nav__inner">
|
||||
<a class="nav__logo" href="../index.html" aria-label="HELP4BIS home">
|
||||
<img src="../assets/images/logo-cropped.jpg" alt="HELP4BIS" width="140" height="38">
|
||||
</a>
|
||||
<ul class="nav__links" id="nav-links" role="list">
|
||||
<li class="nav__dropdown">
|
||||
<button class="nav__trigger" aria-haspopup="true" aria-expanded="false">Services <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg></button>
|
||||
<ul class="nav__dropdown-menu" role="menu">
|
||||
<li class="nav__menu-group">WordPress</li>
|
||||
<li><a href="../managed-wordpress.html" role="menuitem">Tailored Website Management</a></li>
|
||||
<li><a href="../care-plans.html" role="menuitem">WP Care Plans <span class="menu-price">from $49/mo</span></a></li>
|
||||
<li><a href="../sos-fix.html" role="menuitem">WP SOS Fix <span class="menu-price">$97 flat</span></a></li>
|
||||
<li><a href="../ai-integration.html" role="menuitem">AI Integration</a></li>
|
||||
<li><a href="../plugin-development.html" role="menuitem">Custom Plugin Development</a></li> </ul>
|
||||
</li>
|
||||
<li><a href="../about.html">About</a></li>
|
||||
<li><a href="../index.html#portfolio">Our Work</a></li>
|
||||
<li><a href="../index.html#pricing">Pricing</a></li>
|
||||
<li><a href="../blog/index.html">Blog</a></li>
|
||||
<li><a href="../your-first-week-with-ai.html">AI Guide</a></li>
|
||||
<li><a href="../contact.html">Contact</a></li>
|
||||
<li class="nav__cta-mobile" aria-hidden="true">
|
||||
<a href="../contact.html" class="btn btn-primary">Get Started</a>
|
||||
<a href="../sos-fix.html" class="btn btn-secondary">SOS Fix, $97</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="nav__cta">
|
||||
<a href="../sos-fix.html" class="btn btn-secondary btn-sm">SOS Fix, $97</a>
|
||||
<a href="../contact.html" class="btn btn-primary btn-sm">Get Started</a>
|
||||
</div>
|
||||
<button class="nav__burger" id="nav-burger" aria-label="Open menu" aria-expanded="false" aria-controls="nav-links">
|
||||
<span></span><span></span><span></span>
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- ═══════════════════════════════════════════════
|
||||
HERO
|
||||
═══════════════════════════════════════════════ -->
|
||||
<section class="cs-hero" aria-labelledby="cs-heading">
|
||||
<div class="container">
|
||||
<div class="cs-breadcrumb">
|
||||
<a href="../index.html">Home</a>
|
||||
<span>›</span>
|
||||
<a href="../index.html#portfolio">Our Work</a>
|
||||
<span>›</span>
|
||||
<span style="color:rgba(255,255,255,.7);">Dayboro.au</span>
|
||||
</div>
|
||||
<p class="eyebrow" style="color:rgba(34,197,94,.9);">Case Study: Community Platform</p>
|
||||
<h1 id="cs-heading">Dayboro.au<br>22 years<br>in the making.</h1>
|
||||
<p class="cs-hero-sub">A hyperlocal weather platform, nine interactive calculators connected to my live station data, a Flutter PWA on Google Play, and a Lions Club business directory. I run all of it on a single WordPress instance from a hill in the D'Aguilar Range, Queensland.</p>
|
||||
<div class="cs-hero-actions">
|
||||
<a href="https://dayboro.au" target="_blank" rel="noopener" class="btn btn-green">Visit dayboro.au →</a>
|
||||
<a href="https://app.dayboro.au" target="_blank" rel="noopener" class="btn btn-secondary">Open the app</a>
|
||||
</div>
|
||||
<div class="cs-kpis">
|
||||
<div class="cs-kpi">
|
||||
<div class="cs-kpi-value">2004</div>
|
||||
<div class="cs-kpi-label">Running Since</div>
|
||||
</div>
|
||||
<div class="cs-kpi">
|
||||
<div class="cs-kpi-value">9</div>
|
||||
<div class="cs-kpi-label">Live Data Calculators</div>
|
||||
</div>
|
||||
<div class="cs-kpi">
|
||||
<div class="cs-kpi-value">118+</div>
|
||||
<div class="cs-kpi-label">Businesses Listed</div>
|
||||
</div>
|
||||
<div class="cs-kpi">
|
||||
<div class="cs-kpi-value">5 min</div>
|
||||
<div class="cs-kpi-label">Data Refresh Rate</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════════════════════════════════
|
||||
WHAT IT ACTUALLY IS
|
||||
═══════════════════════════════════════════════ -->
|
||||
<section class="section" aria-labelledby="overview-heading">
|
||||
<div class="container">
|
||||
<div class="cs-two-col cs-two-col--wide">
|
||||
<div>
|
||||
<p class="eyebrow">Overview</p>
|
||||
<h2 id="overview-heading">What it actually is</h2>
|
||||
<p class="large">Most people in Dayboro know the site for the weather. They check it in the morning to see if the creek is up, or if there's a frost warning overnight. That's the front door.</p>
|
||||
<p>Behind it: nine interactive gardening calculators that pull live data from my weather station every five minutes. A Flutter app on Google Play. A community events calendar. A tiered business directory that our local Lions Club uses to replace the old printed phone book. A custom email plugin I wrote that sends weekly weather digests to subscribers. And a Gann seasonal forecast that I cross reference with Inigo Jones lunar cycle predictions.</p>
|
||||
<p>By any honest measure I've overbuilt it for a town of three thousand people. But it works, and the whole infrastructure costs me roughly the same per month as a decent coffee habit.</p>
|
||||
<div class="cs-quote">
|
||||
<p>"BOM's nearest gauged station is at Samford, 12 km southeast and 150 metres lower in elevation. On a typical summer afternoon the two stations can record rainfall that differs by a factor of four. That's why my station exists."</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<img src="../assets/images/port-dayboro.jpg" alt="Dayboro.au weather platform" style="width:100%;border-radius:var(--r-xl);box-shadow:var(--shadow-lg);" loading="lazy">
|
||||
<div class="cs-stack" style="margin-top:20px;">
|
||||
<span class="cs-stack-tag">WordPress</span>
|
||||
<span class="cs-stack-tag">Flutter Web</span>
|
||||
<span class="cs-stack-tag">WeeWX</span>
|
||||
<span class="cs-stack-tag">Python</span>
|
||||
<span class="cs-stack-tag">PMPro Membership</span>
|
||||
<span class="cs-stack-tag">Ecowitt</span>
|
||||
<span class="cs-stack-tag">Service Worker</span>
|
||||
<span class="cs-stack-tag">Custom Plugins</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════════════════════════════════
|
||||
THE WEATHER BACKBONE
|
||||
═══════════════════════════════════════════════ -->
|
||||
<section class="section section--alt" aria-labelledby="weather-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Foundation</p>
|
||||
<h2 id="weather-heading">The weather engine</h2>
|
||||
<p class="section-subtitle" style="text-align:left;margin-left:0;max-width:640px;">My Ecowitt station on Lyndhurst Hill feeds a custom Python pipeline I wrote, generating twelve JSON files every five minutes.</p>
|
||||
|
||||
<div class="cs-feature-grid">
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🌡️</div>
|
||||
<h4>Hardware: Ecowitt sensors</h4>
|
||||
<p>Temperature to 0.1°C resolution, rainfall to 1 mm, wind speed and direction, UV index, solar radiation, soil temperature, lightning strike distance. All the hardware sits on my own site, so I don't depend on anyone else's data.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">⚙️</div>
|
||||
<h4>Processing: WeeWX + Python</h4>
|
||||
<p>WeeWX handles raw sensor ingestion and archive storage. My Python pipeline runs every five minutes: it calculates derived values, builds twelve JSON files, and uploads them to the server automatically. There are no manual steps in the data chain, whilst every step still logs enough that I can trace a bad number back to its sensor.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">📊</div>
|
||||
<h4>Data going back to 2004</h4>
|
||||
<p>22 years of logged temperature and rainfall at Lyndhurst Hill, with varying hardware over the years. The current Ecowitt installation has run continuously since 2023. I publish aggregates and accuracy comparisons against BOM Samford every month.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🔄</div>
|
||||
<h4>Live API: twelve JSON endpoints</h4>
|
||||
<p>The calculators, the Flutter app, and the WordPress widgets all read from the same live weather data feed. One source of truth, refreshed every five minutes. It costs me nothing in external API fees and there are no rate limits.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">⚡</div>
|
||||
<h4>Push notifications</h4>
|
||||
<p>Subscribers to the Dayboro Buddy app receive push notifications for severe weather events: flash flood watch, frost alerts overnight, and heatwave warnings. Delivered via Service Worker push on Android and iOS.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🏠</div>
|
||||
<h4>Home automation integration</h4>
|
||||
<p>The same data feeds my Home Assistant instance, with Sigenergy solar battery management and Amber Electric spot prices. Weather station data informs battery charge scheduling. More solar in the forecast means less grid charging overnight.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════════════════════════════════
|
||||
NINE CALCULATORS
|
||||
═══════════════════════════════════════════════ -->
|
||||
<section class="section" aria-labelledby="calc-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Gardening Tools</p>
|
||||
<h2 id="calc-heading">Nine calculators, all on live data</h2>
|
||||
<p style="max-width:640px;color:var(--grey-600);font-size:17px;line-height:1.7;margin-bottom:0;">Each one pulls from my live station feed, updated every five minutes. They're standard WordPress pages with Elementor HTML widgets. No external API keys, no third party services. The free tier gets a subset of the tools; premium members get all nine plus extended history views.</p>
|
||||
|
||||
<ul class="cs-calc-list">
|
||||
<li class="cs-calc-item">
|
||||
<strong>Frost Risk</strong>
|
||||
<span>Current temperature vs typical minimum. Overnight frost probability based on current humidity, dew point, and the seasonal average for this valley.</span>
|
||||
<div><span class="cs-calc-tier cs-calc-tier--free">Free</span></div>
|
||||
</li>
|
||||
<li class="cs-calc-item">
|
||||
<strong>Companion Planting</strong>
|
||||
<span>Embedded compatibility matrix covering 30+ vegetable and herb combinations. Helps and hinders, with reasoning for each pairing.</span>
|
||||
<div><span class="cs-calc-tier cs-calc-tier--free">Free</span></div>
|
||||
</li>
|
||||
<li class="cs-calc-item">
|
||||
<strong>Harvest Date</strong>
|
||||
<span>Growing degree day calculation using live minimum and maximum temperatures. Enter planting date and crop, get a realistic days to harvest estimate for your specific conditions.</span>
|
||||
<div><span class="cs-calc-tier cs-calc-tier--free">Free</span></div>
|
||||
</li>
|
||||
<li class="cs-calc-item">
|
||||
<strong>Spray Window</strong>
|
||||
<span>Wind speed, humidity, and temperature from the live station. Outputs a simple safe or not safe right now decision for pesticide and herbicide application.</span>
|
||||
<div><span class="cs-calc-tier cs-calc-tier--premium">Premium</span></div>
|
||||
</li>
|
||||
<li class="cs-calc-item">
|
||||
<strong>Soil pH</strong>
|
||||
<span>Client side only, no data fetch needed. pH ranges per crop, current soil pH input, and a guide with quantities for correcting it.</span>
|
||||
<div><span class="cs-calc-tier cs-calc-tier--free">Free</span></div>
|
||||
</li>
|
||||
<li class="cs-calc-item">
|
||||
<strong>Veggie ROI</strong>
|
||||
<span>Live average vegetable prices from a scraped price dataset versus estimated yield from your plot size. Answers the question: is it actually cheaper to grow this myself?</span>
|
||||
<div><span class="cs-calc-tier cs-calc-tier--premium">Premium</span></div>
|
||||
</li>
|
||||
<li class="cs-calc-item">
|
||||
<strong>Pest Risk</strong>
|
||||
<span>Temperature and humidity threshold model for twelve common garden pests. Current conditions fed live. Risk level: low, moderate, or high, with recommended action.</span>
|
||||
<div><span class="cs-calc-tier cs-calc-tier--premium">Premium</span></div>
|
||||
</li>
|
||||
<li class="cs-calc-item">
|
||||
<strong>Watering Schedule</strong>
|
||||
<span>Evapotranspiration estimate derived from live temperature, humidity, wind, and solar radiation data. Adjusts by soil type and plant category.</span>
|
||||
<div><span class="cs-calc-tier cs-calc-tier--premium">Premium</span></div>
|
||||
</li>
|
||||
<li class="cs-calc-item">
|
||||
<strong>Crop Planner</strong>
|
||||
<span>Calendar based planting windows by month for SE Queensland conditions. Covers 40+ crops with sowing method, spacing, and the typical Dayboro first frost and last frost dates.</span>
|
||||
<div><span class="cs-calc-tier cs-calc-tier--free">Free</span></div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="cs-honest">
|
||||
<div class="cs-honest-label">Design note</div>
|
||||
<p>I kept the calculators deliberately simple on the outside. Each one fits in a single Elementor HTML widget: scoped CSS, vanilla JS, no build tools, no npm. They've been running without maintenance since February 2026, and that's not luck, it's the absence of dependencies. If you want a calculator that breaks six months after launch because an npm package updated, mine aren't that.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════════════════════════════════
|
||||
THE MOBILE APP
|
||||
═══════════════════════════════════════════════ -->
|
||||
<section class="section section--alt" aria-labelledby="app-heading">
|
||||
<div class="container">
|
||||
<div class="cs-two-col">
|
||||
<div>
|
||||
<p class="eyebrow">Mobile App</p>
|
||||
<h2 id="app-heading">Dayboro Buddy, on any device</h2>
|
||||
<p class="large">A Flutter Progressive Web App. One codebase, deployed as static files, available on Android via Google Play and on iOS via Safari's Add to Home Screen.</p>
|
||||
<p>The Android APK (package: <code>au.dayboro.app</code>) is on Google Play and installs like a native app. On iPhone, open <a href="https://app.dayboro.au" class="inline-link">app.dayboro.au</a> in Safari, tap the share icon, tap Add to Home Screen. It installs in seconds. No App Store account, no review process, no waiting.</p>
|
||||
<p>The service worker handles offline caching, background sync, and push notifications. Auto update works silently: when I deploy a new version, the service worker detects it on the next load and refreshes. Users are always on the current version without being asked to update anything.</p>
|
||||
|
||||
<div class="cs-feature-grid" style="grid-template-columns:1fr 1fr;margin-top:var(--sp-5);">
|
||||
<div class="cs-feature-card">
|
||||
<h4>App size</h4>
|
||||
<p>3.9 MB. Loads in under 3 seconds on a standard 4G connection.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<h4>Version on Play Store</h4>
|
||||
<p>v2.0.7, live and available at <code>au.dayboro.app</code>.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<h4>Offline mode</h4>
|
||||
<p>Core navigation and cached weather data available without a connection.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<h4>Push notifications</h4>
|
||||
<p>Frost alerts, flood watches, and severe weather warnings delivered to the home screen.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<img src="../assets/images/port-app-dayboro.png" alt="Dayboro Buddy Progressive Web App" style="width:100%;border-radius:var(--r-xl);box-shadow:var(--shadow-lg);" loading="lazy">
|
||||
<div class="cs-honest" style="margin-top:20px;">
|
||||
<div class="cs-honest-label">Why Flutter and not a standard WordPress PWA</div>
|
||||
<p>A standard WordPress PWA gives you a cached version of the site. Flutter gives you a proper application with its own navigation model and a UI that feels native. My weather calculators need to query JSON data, render charts, handle offline state, and update in the background. I tried the WordPress PWA plugins first and they can't do that reliably. Flutter can.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════════════════════════════════
|
||||
COMMUNITY LAYER
|
||||
═══════════════════════════════════════════════ -->
|
||||
<section class="section" aria-labelledby="community-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Community</p>
|
||||
<h2 id="community-heading">The community layer</h2>
|
||||
<p style="max-width:640px;color:var(--grey-600);font-size:17px;line-height:1.7;">Business directory, events calendar, weekly email digest, and a membership model. I built all of it into the same WordPress instance, and it's all interconnected.</p>
|
||||
|
||||
<div class="cs-feature-grid" style="margin-top:var(--sp-6);">
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🏪</div>
|
||||
<h4>Lions Club Business Directory</h4>
|
||||
<p>118 local businesses listed across three tiers: full page, half page, and quarter page. I build the WordPress plugin specifically for this directory, and the Lions Club in Dayboro now uses it as the digital replacement for the annual printed directory. Directory data feeds the Flutter app via a custom REST API.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">📅</div>
|
||||
<h4>Events Calendar</h4>
|
||||
<p>Community events, markets, school dates, and local meetings. Pulled from a custom REST endpoint and displayed on the homepage. The Flutter app reads the same endpoint. One entry point for event data, multiple display surfaces.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">📧</div>
|
||||
<h4>Weekly Weather Digest</h4>
|
||||
<p>A custom email reports plugin (not a third party newsletter service) sends a weekly digest to subscribers. The past seven days of temperature and rainfall, a short summary, and links to the current forecast. The queue runs on WordPress cron. Open rates run consistently above industry average for small community newsletters because every single number in the email is from this valley, not from a regional station 12 km away.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🔐</div>
|
||||
<h4>Membership: Free and Premium</h4>
|
||||
<p>PMPro handles membership. The free tier gives access to the core weather data and four calculators. Premium unlocks all nine calculators, extended historical data, and the seasonal forecasting tools. There's no trial that asks for a credit card. I made the free tier useful on its own, on purpose.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">📱</div>
|
||||
<h4>Push Notifications</h4>
|
||||
<p>Web push notifications via the Dayboro Buddy service worker. Subscribers opt in to frost alerts, flash flood watches, and heatwave warnings. Notifications go through my own WordPress plugin to a push API endpoint, not through a third party notification service.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">📈</div>
|
||||
<h4>Site Analytics: Custom</h4>
|
||||
<p>My rds-siteanalytics plugin tracks page views and reads Gitea issues as a website task list, displayed in the WordPress admin. No Google Analytics, no third party tracking scripts. Visitor data stays on my server.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════════════════════════════════
|
||||
SEASONAL FORECASTING
|
||||
═══════════════════════════════════════════════ -->
|
||||
<section class="section section--alt" aria-labelledby="forecast-heading">
|
||||
<div class="container">
|
||||
<div class="cs-two-col">
|
||||
<div>
|
||||
<p class="eyebrow">Forecasting</p>
|
||||
<h2 id="forecast-heading">Seasonal forecasting: Gann and Inigo Jones</h2>
|
||||
<p class="large">The seasonal forecasting side lives at <a href="https://crohamhurst.app" class="inline-link" target="_blank" rel="noopener">crohamhurst.app</a>, a separate subdomain. It isn't a standard weather forecast.</p>
|
||||
<p>It combines Inigo Jones lunar cycle predictions with a Gann astronomical analysis pipeline I built in Python. The output is a qualitative seasonal outlook: whether the coming month is likely to run wetter or drier than average, based on long cycle positions going back to 1913.</p>
|
||||
<div class="cs-honest">
|
||||
<div class="cs-honest-label">Honest about what it is</div>
|
||||
<p>This is an outlook based on historical cycles, not a deterministic forecast. It doesn't know about La Niña, blocking highs, or the Indian Ocean Dipole. It knows about repeating patterns in the long record that correlate loosely with the positions of the Sun, Moon, and inner planets. Accuracy on wet versus dry calls over a six week window runs around 62 to 65 percent. That's useful for farm planning. It's not useful for scheduling outdoor events, and I say so on the site.</p>
|
||||
</div>
|
||||
<p>The same Gann pipeline also feeds a CFD trading signal system that runs against IG Markets on a demo account, whilst I test whether a methodology W.D. Gann applied to commodity markets in the early 1900s still holds up in modern trading. My results so far are inconclusive, which is the honest answer.</p>
|
||||
</div>
|
||||
<div>
|
||||
<div style="background:var(--ink-mid);border-radius:var(--r-xl);padding:var(--sp-6);color:var(--white);">
|
||||
<p class="eyebrow" style="color:rgba(34,197,94,.9);">How the pipeline works</p>
|
||||
<ol style="list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:16px;">
|
||||
<li style="display:flex;gap:14px;align-items:flex-start;">
|
||||
<span style="flex-shrink:0;width:28px;height:28px;background:var(--green);border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;color:var(--ink);">1</span>
|
||||
<div><strong style="color:var(--white);font-size:14px;">Astronomical data</strong><p style="font-size:13px;color:rgba(255,255,255,.55);margin:4px 0 0;line-height:1.5;">Sun, Moon, and planet positions calculated from NASA ephemeris data. Declinations, aspects, and angular relationships computed daily.</p></div>
|
||||
</li>
|
||||
<li style="display:flex;gap:14px;align-items:flex-start;">
|
||||
<span style="flex-shrink:0;width:28px;height:28px;background:var(--green);border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;color:var(--ink);">2</span>
|
||||
<div><strong style="color:var(--white);font-size:14px;">Inigo Jones cycles</strong><p style="font-size:13px;color:rgba(255,255,255,.55);margin:4px 0 0;line-height:1.5;">Lunar cycle positions mapped against the Jones seasonal calendar for SE Queensland. Crohamhurst Observatory data integrated.</p></div>
|
||||
</li>
|
||||
<li style="display:flex;gap:14px;align-items:flex-start;">
|
||||
<span style="flex-shrink:0;width:28px;height:28px;background:var(--green);border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;color:var(--ink);">3</span>
|
||||
<div><strong style="color:var(--white);font-size:14px;">Gann unified scoring</strong><p style="font-size:13px;color:rgba(255,255,255,.55);margin:4px 0 0;line-height:1.5;">Multiple Gann factors combined into a single directional score. Only scores above 70 are treated as signal grade. Below that, the model abstains.</p></div>
|
||||
</li>
|
||||
<li style="display:flex;gap:14px;align-items:flex-start;">
|
||||
<span style="flex-shrink:0;width:28px;height:28px;background:var(--green);border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;color:var(--ink);">4</span>
|
||||
<div><strong style="color:var(--white);font-size:14px;">Published outlook</strong><p style="font-size:13px;color:rgba(255,255,255,.55);margin:4px 0 0;line-height:1.5;">Monthly outlook published at crohamhurst.app with the cycle rationale and historical comparison years. Free to read, no account required.</p></div>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════════════════════════════════
|
||||
TECH STACK
|
||||
═══════════════════════════════════════════════ -->
|
||||
<section class="section" aria-labelledby="stack-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Under the Hood</p>
|
||||
<h2 id="stack-heading">What it actually runs on</h2>
|
||||
<p style="max-width:600px;color:var(--grey-600);font-size:17px;line-height:1.7;">No managed cloud services, no vendor lock-in, no SaaS subscriptions in the data path. Every component runs on infrastructure I control.</p>
|
||||
|
||||
<div class="cs-feature-grid" style="margin-top:var(--sp-6);">
|
||||
<div class="cs-feature-card">
|
||||
<h4>WordPress + PMPro</h4>
|
||||
<p>Core CMS and membership engine. PMPro handles access control, payment processing, and subscription management. I don't use WooCommerce for memberships. PMPro does it cleaner for this use case.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<h4>Flutter Web</h4>
|
||||
<p>Dart compiled to JavaScript, deployed as static files at app.dayboro.au. Service worker for offline and push. The app itself needs no backend, it reads the same public JSON files as the website.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<h4>WeeWX + Python pipeline</h4>
|
||||
<p>WeeWX handles sensor ingestion. A custom Python module processes the data, runs accuracy calculations, and generates the twelve JSON export files every five minutes via root cron.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<h4>Custom WordPress plugins</h4>
|
||||
<p>Three custom plugins I wrote specifically for this site: dayboro-business-directory (Lions Club listing management + REST API), dayboro-email-reports (queued weekly digest), and rds-siteanalytics (custom analytics + Gitea task integration).</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<h4>DirectAdmin on brisbane01</h4>
|
||||
<p>I host all my sites on a dedicated server in Brisbane. Help4bis.com, dayboro.au, gardenbuddy.au, rds.ink, m8chat.au, and eight other domains all run on the same physical machine. Australian data residency, not US cloud.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<h4>Ecowitt hardware</h4>
|
||||
<p>GW2000 gateway with multiple sensor arrays. Direct local API plus cloud sync. WeeWX reads locally, so my data pipeline doesn't depend on Ecowitt's cloud servers staying up.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cs-divider"></div>
|
||||
|
||||
<div class="cs-two-col">
|
||||
<div>
|
||||
<h3 style="margin-bottom:var(--sp-3);">Full technology list</h3>
|
||||
<div class="cs-stack">
|
||||
<span class="cs-stack-tag">WordPress 6.x</span>
|
||||
<span class="cs-stack-tag">PHP 8.4</span>
|
||||
<span class="cs-stack-tag">MariaDB</span>
|
||||
<span class="cs-stack-tag">PMPro Membership</span>
|
||||
<span class="cs-stack-tag">Elementor Pro</span>
|
||||
<span class="cs-stack-tag">Flutter 3.x</span>
|
||||
<span class="cs-stack-tag">Dart</span>
|
||||
<span class="cs-stack-tag">WeeWX 5.x</span>
|
||||
<span class="cs-stack-tag">Python 3.11</span>
|
||||
<span class="cs-stack-tag">Ecowitt GW2000</span>
|
||||
<span class="cs-stack-tag">Service Worker</span>
|
||||
<span class="cs-stack-tag">Web Push API</span>
|
||||
<span class="cs-stack-tag">REST API</span>
|
||||
<span class="cs-stack-tag">JSON data files</span>
|
||||
<span class="cs-stack-tag">DirectAdmin</span>
|
||||
<span class="cs-stack-tag">Gitea</span>
|
||||
<span class="cs-stack-tag">Home Assistant</span>
|
||||
<span class="cs-stack-tag">Sigenergy</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h3 style="margin-bottom:var(--sp-3);">What I deliberately left out</h3>
|
||||
<p style="color:var(--grey-600);font-size:14px;line-height:1.65;">No Google Analytics, because privacy matters in a small community where everyone knows each other. No third party notification services, push goes through my own endpoint. No CDN, since the server is in Brisbane and the audience is in SE Queensland; the latency is fine. No React, no Next.js, no build pipeline for the widgets. Vanilla JS in Elementor HTML widgets is fast, maintainable, and doesn't break when npm packages update.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════════════════════════════════
|
||||
CTA
|
||||
═══════════════════════════════════════════════ -->
|
||||
<section class="section section--dark" aria-labelledby="cta-heading">
|
||||
<div class="container">
|
||||
<div class="cs-cta">
|
||||
<p class="eyebrow" style="color:rgba(34,197,94,.9);justify-content:center;">What I can build for you</p>
|
||||
<h2 id="cta-heading">Your community, your platform.</h2>
|
||||
<p>Not the whole thing. Something that fits your scale and budget. I bring the tools, the architecture, and over twenty years of building for small communities. What I need from you: a clear description of what problem you're trying to solve and who you're solving it for.</p>
|
||||
<div style="display:flex;gap:12px;justify-content:center;flex-wrap:wrap;">
|
||||
<a href="../contact.html" class="btn btn-primary">Talk to us about your project</a>
|
||||
<a href="../index.html#portfolio" class="btn btn-secondary">See more of our work</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════════════════════════════════
|
||||
FOOTER
|
||||
═══════════════════════════════════════════════ -->
|
||||
<footer class="footer" aria-label="Site footer">
|
||||
<div class="container">
|
||||
<div class="footer__grid">
|
||||
|
||||
<div class="footer__brand">
|
||||
<img src="../assets/images/logo-cropped.jpg" alt="HELP4BIS" width="140" height="38">
|
||||
<p>Managed WordPress hosting and maintenance for Australian small businesses. Brisbane based, personal service, WordPress specialist.</p>
|
||||
<p style="font-size:13px; color:rgba(255,255,255,.4);">Dutch Digital Dynamics Pty Ltd · ABN 86 081 237 087</p>
|
||||
</div>
|
||||
|
||||
<div class="footer__col">
|
||||
<h4>Services</h4>
|
||||
<ul class="footer__links">
|
||||
<li><a href="../managed-wordpress.html">Tailored Website Management</a></li>
|
||||
<li><a href="../care-plans.html">WP Care Plans</a></li>
|
||||
<li><a href="../sos-fix.html">WP SOS Fix</a></li>
|
||||
<li><a href="../ai-integration.html">AI Integration</a></li>
|
||||
<li><a href="../plugin-development.html">Plugin Development</a></li> </ul>
|
||||
</div>
|
||||
|
||||
<div class="footer__col">
|
||||
<h4>Company</h4>
|
||||
<ul class="footer__links">
|
||||
<li><a href="../about.html">About Us</a></li>
|
||||
<li><a href="../index.html#portfolio">Our Work</a></li>
|
||||
<li><a href="../index.html#testimonials">Client Feedback</a></li>
|
||||
<li><a href="../blog/index.html">Blog</a></li>
|
||||
<li><a href="../contact.html">Contact</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="footer__col">
|
||||
<h4>Contact</h4>
|
||||
<ul class="footer__links">
|
||||
<li><a href="mailto:project@help4bis.com">project@help4bis.com</a></li>
|
||||
<li><a href="../contact.html">Submit a Brief</a></li>
|
||||
<li><a href="../sos-fix.html">Emergency Fix</a></li>
|
||||
</ul>
|
||||
<p style="margin-top:1rem; font-size:13px; color:rgba(255,255,255,.4);">
|
||||
Brisbane, Queensland<br>
|
||||
Response within 24 business hours
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="footer__bottom">
|
||||
<span>© 2026 HELP4BIS, a trading name of Dutch Digital Dynamics Pty Ltd · ABN 86 081 237 087</span>
|
||||
<span>
|
||||
<a href="../privacy.html">Privacy Policy</a> ·
|
||||
<a href="../terms.html">Terms</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<button id="back-to-top" aria-label="Back to top" style="position:fixed;bottom:24px;right:24px;width:44px;height:44px;background:var(--red);border:none;border-radius:50%;color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .3s ease;box-shadow:var(--shadow-md);">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="18 15 12 9 6 15"/></svg>
|
||||
</button>
|
||||
|
||||
<script src="../assets/js/main.js"></script>
|
||||
<script src="../analytics/tracker.js" defer></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,493 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- Version: 1.2.0 | Created: 2026-05-05 | Updated: 2026-08-16 -->
|
||||
<html lang="en-AU">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>GardenBuddy.au Case Study | HELP4BIS</title>
|
||||
<meta name="description" content="How I built GardenBuddy.au: a national vegetable garden management platform with climate zones by postcode, live pest pressure, harvest tracking, ROI reports against supermarket prices, and a weekly Gardener Digest email.">
|
||||
<meta name="author" content="HELP4BIS">
|
||||
<meta name="publisher" content="Dutch Digital Dynamics Pty Ltd">
|
||||
<meta name="language" content="en-AU">
|
||||
<meta name="geo.region" content="AU-QLD">
|
||||
<link rel="canonical" href="https://help4bis.com/work/gardenbuddy-au.html">
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content="https://help4bis.com/work/gardenbuddy-au.html">
|
||||
<meta property="og:site_name" content="HELP4BIS">
|
||||
<meta property="og:title" content="GardenBuddy.au Case Study | HELP4BIS">
|
||||
<meta property="og:description" content="A full vegetable garden management platform: climate zones by postcode, live pest pressure, harvest logging, ROI vs Coles and Woolworths prices, and a weekly Gardener Digest. Built on WordPress with our own plugins.">
|
||||
<meta property="og:image" content="https://help4bis.com/assets/images/port-gardenbuddy.jpg">
|
||||
<meta property="og:locale" content="en_AU">
|
||||
<link rel="icon" type="image/jpeg" href="../assets/images/logo-favicon.jpg"> <link rel="stylesheet" href="../assets/css/style.css">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"@id": "https://help4bis.com/work/gardenbuddy-au.html#webpage",
|
||||
"url": "https://help4bis.com/work/gardenbuddy-au.html",
|
||||
"name": "GardenBuddy.au Case Study | HELP4BIS",
|
||||
"description": "A national vegetable garden management platform built on WordPress with custom plugins for climate zone detection, garden bed tracking, harvest logging, live pest pressure, and ROI reports against supermarket prices.",
|
||||
"isPartOf": {"@id": "https://help4bis.com/#website"},
|
||||
"breadcrumb": {
|
||||
"@type": "BreadcrumbList",
|
||||
"itemListElement": [
|
||||
{"@type": "ListItem", "position": 1, "name": "Home", "item": "https://help4bis.com/"},
|
||||
{"@type": "ListItem", "position": 2, "name": "Our Work", "item": "https://help4bis.com/#portfolio"},
|
||||
{"@type": "ListItem", "position": 3, "name": "GardenBuddy.au", "item": "https://help4bis.com/work/gardenbuddy-au.html"}
|
||||
]
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.cs-hero {
|
||||
background: linear-gradient(160deg, var(--ink) 0%, #0d1f0d 50%, #142014 100%);
|
||||
padding: var(--sp-16) 0 var(--sp-12);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.cs-hero::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -30%;
|
||||
right: -15%;
|
||||
width: 60%;
|
||||
height: 200%;
|
||||
background: radial-gradient(circle, rgba(34,197,94,.07) 0%, transparent 65%);
|
||||
pointer-events: none;
|
||||
}
|
||||
.cs-breadcrumb {
|
||||
font-size: 13px;
|
||||
color: rgba(255,255,255,.45);
|
||||
margin-bottom: var(--sp-5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.cs-breadcrumb a { color: rgba(255,255,255,.45); }
|
||||
.cs-breadcrumb a:hover { color: var(--white); }
|
||||
.cs-breadcrumb span { color: rgba(255,255,255,.25); }
|
||||
.cs-hero h1 { color: var(--white); max-width: 820px; margin-bottom: var(--sp-4); }
|
||||
.cs-hero-sub {
|
||||
font-size: clamp(16px, 2vw, 20px);
|
||||
color: rgba(255,255,255,.65);
|
||||
max-width: 680px;
|
||||
line-height: 1.65;
|
||||
margin-bottom: var(--sp-6);
|
||||
}
|
||||
.cs-hero-actions { display: flex; gap: 12px; flex-wrap: wrap; }
|
||||
.btn-green {
|
||||
background: linear-gradient(135deg, #22C55E, #16a34a);
|
||||
color: var(--white);
|
||||
border-color: transparent;
|
||||
box-shadow: 0 4px 14px rgba(34,197,94,.30);
|
||||
}
|
||||
.btn-green:hover { background: linear-gradient(135deg, #16a34a, #15803d); color: var(--white); transform: translateY(-2px); }
|
||||
.cs-kpis {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 16px;
|
||||
margin-top: var(--sp-8);
|
||||
padding-top: var(--sp-8);
|
||||
border-top: 1px solid rgba(255,255,255,.08);
|
||||
}
|
||||
@media (min-width: 640px) { .cs-kpis { grid-template-columns: repeat(4, 1fr); } }
|
||||
.cs-kpi { text-align: center; }
|
||||
.cs-kpi-value {
|
||||
font-family: var(--font-head);
|
||||
font-size: clamp(32px, 4vw, 52px);
|
||||
font-weight: 900;
|
||||
color: var(--green);
|
||||
line-height: 1;
|
||||
letter-spacing: -0.04em;
|
||||
}
|
||||
.cs-kpi-label { font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: .12em; color: rgba(255,255,255,.45); margin-top: 6px; }
|
||||
.cs-feature-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 24px;
|
||||
margin-top: var(--sp-6);
|
||||
}
|
||||
@media (min-width: 640px) { .cs-feature-grid { grid-template-columns: repeat(2, 1fr); } }
|
||||
@media (min-width: 900px) { .cs-feature-grid { grid-template-columns: repeat(3, 1fr); } }
|
||||
.cs-feature-card {
|
||||
background: var(--white);
|
||||
border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-lg);
|
||||
padding: 24px;
|
||||
box-shadow: var(--shadow-card);
|
||||
}
|
||||
.cs-feature-card h4 { font-size: 15px; margin-bottom: 8px; color: var(--ink); }
|
||||
.cs-feature-card p { font-size: 14px; color: var(--grey-600); line-height: 1.6; margin: 0; }
|
||||
.cs-feature-icon { width: 36px; height: 36px; background: var(--grey-50); border-radius: var(--r-md); display: flex; align-items: center; justify-content: center; margin-bottom: 14px; font-size: 18px; }
|
||||
.cs-stack { display: flex; flex-wrap: wrap; gap: 8px; margin-top: var(--sp-4); }
|
||||
.cs-stack-tag { background: var(--grey-50); border: 1px solid var(--grey-100); border-radius: var(--r-full); padding: 6px 14px; font-size: 13px; font-weight: 500; color: var(--grey-600); }
|
||||
.cs-two-col { display: grid; grid-template-columns: 1fr; gap: var(--sp-8); align-items: start; }
|
||||
@media (min-width: 768px) { .cs-two-col { grid-template-columns: 1fr 1fr; } .cs-two-col--wide { grid-template-columns: 3fr 2fr; } }
|
||||
.cs-quote { border-left: 3px solid var(--green); padding: var(--sp-4) var(--sp-5); background: rgba(34,197,94,.04); border-radius: 0 var(--r-md) var(--r-md) 0; margin: var(--sp-5) 0; }
|
||||
.cs-quote p { font-size: 17px; line-height: 1.7; color: var(--grey-800); font-style: italic; margin: 0; }
|
||||
.cs-honest { background: var(--grey-50); border: 1px solid var(--grey-100); border-radius: var(--r-lg); padding: var(--sp-4) var(--sp-5); margin: var(--sp-5) 0; }
|
||||
.cs-honest-label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .12em; color: var(--grey-400); margin-bottom: 8px; }
|
||||
.cs-honest p { font-size: 14px; color: var(--grey-600); line-height: 1.65; margin: 0; }
|
||||
.cs-divider { height: 1px; background: var(--grey-100); margin: var(--sp-8) 0; }
|
||||
.cs-flow {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
margin-top: var(--sp-5);
|
||||
}
|
||||
.cs-flow-step {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
align-items: flex-start;
|
||||
padding: 16px 0;
|
||||
border-bottom: 1px solid var(--grey-100);
|
||||
}
|
||||
.cs-flow-step:last-child { border-bottom: none; }
|
||||
.cs-flow-num {
|
||||
flex-shrink: 0;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
background: var(--green);
|
||||
color: white;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
margin-top: 2px;
|
||||
}
|
||||
.cs-flow-title { font-family: var(--font-head); font-size: 14px; font-weight: 700; color: var(--ink); margin-bottom: 4px; }
|
||||
.cs-flow-desc { font-size: 13px; color: var(--grey-600); line-height: 1.5; }
|
||||
.cs-cta { background: linear-gradient(135deg, var(--ink-mid), var(--ink)); border-radius: var(--r-2xl); padding: var(--sp-10) var(--sp-8); text-align: center; }
|
||||
.cs-cta h2 { color: var(--white); margin-bottom: var(--sp-4); }
|
||||
.cs-cta p { color: rgba(255,255,255,.65); max-width: 560px; margin: 0 auto var(--sp-6); font-size: 17px; line-height: 1.7; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<nav class="nav" role="navigation" aria-label="Main navigation">
|
||||
<div class="nav__inner">
|
||||
<a class="nav__logo" href="../index.html" aria-label="HELP4BIS home">
|
||||
<img src="../assets/images/logo-cropped.jpg" alt="HELP4BIS" width="140" height="38">
|
||||
</a>
|
||||
<ul class="nav__links" id="nav-links" role="list">
|
||||
<li class="nav__dropdown">
|
||||
<button class="nav__trigger" aria-haspopup="true" aria-expanded="false">Services <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg></button>
|
||||
<ul class="nav__dropdown-menu" role="menu">
|
||||
<li class="nav__menu-group">WordPress</li>
|
||||
<li><a href="../managed-wordpress.html" role="menuitem">Tailored Website Management</a></li>
|
||||
<li><a href="../care-plans.html" role="menuitem">WP Care Plans <span class="menu-price">from $49/mo</span></a></li>
|
||||
<li><a href="../sos-fix.html" role="menuitem">WP SOS Fix <span class="menu-price">$97 flat</span></a></li>
|
||||
<li><a href="../ai-integration.html" role="menuitem">AI Integration</a></li>
|
||||
<li><a href="../plugin-development.html" role="menuitem">Custom Plugin Development</a></li> </ul>
|
||||
</li>
|
||||
<li><a href="../about.html">About</a></li>
|
||||
<li><a href="../index.html#portfolio">Our Work</a></li>
|
||||
<li><a href="../index.html#pricing">Pricing</a></li>
|
||||
<li><a href="../blog/index.html">Blog</a></li>
|
||||
<li><a href="../your-first-week-with-ai.html">AI Guide</a></li>
|
||||
<li><a href="../contact.html">Contact</a></li>
|
||||
<li class="nav__cta-mobile" aria-hidden="true">
|
||||
<a href="../contact.html" class="btn btn-primary">Get Started</a>
|
||||
<a href="../sos-fix.html" class="btn btn-secondary">SOS Fix, $97</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="nav__cta">
|
||||
<a href="../sos-fix.html" class="btn btn-secondary btn-sm">SOS Fix, $97</a>
|
||||
<a href="../contact.html" class="btn btn-primary btn-sm">Get Started</a>
|
||||
</div>
|
||||
<button class="nav__burger" id="nav-burger" aria-label="Open menu" aria-expanded="false" aria-controls="nav-links">
|
||||
<span></span><span></span><span></span>
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- HERO -->
|
||||
<section class="cs-hero" aria-labelledby="cs-heading">
|
||||
<div class="container">
|
||||
<div class="cs-breadcrumb">
|
||||
<a href="../index.html">Home</a><span>›</span>
|
||||
<a href="../index.html#portfolio">Our Work</a><span>›</span>
|
||||
<span style="color:rgba(255,255,255,.7);">GardenBuddy.au</span>
|
||||
</div>
|
||||
<p class="eyebrow" style="color:rgba(34,197,94,.9);">Case Study: National Garden Platform</p>
|
||||
<h1 id="cs-heading">GardenBuddy.au.<br>A garden management<br>app built on WordPress.</h1>
|
||||
<p class="cs-hero-sub">Not a calculator page. A full vegetable garden management platform I built as a custom WordPress plugin: climate zones by postcode covering all of Australia, live pest pressure from my weather data, harvest logging, ROI reports against Coles and Woolworths prices, and a weekly Gardener Digest email.</p>
|
||||
<div class="cs-hero-actions">
|
||||
<a href="https://gardenbuddy.au" target="_blank" rel="noopener" class="btn btn-green">Visit gardenbuddy.au →</a>
|
||||
<a href="../contact.html" class="btn btn-secondary">Build something similar</a>
|
||||
</div>
|
||||
<div class="cs-kpis">
|
||||
<div class="cs-kpi"><div class="cs-kpi-value">AU</div><div class="cs-kpi-label">National Coverage</div></div>
|
||||
<div class="cs-kpi"><div class="cs-kpi-value">6</div><div class="cs-kpi-label">Custom Plugins</div></div>
|
||||
<div class="cs-kpi"><div class="cs-kpi-value">4</div><div class="cs-kpi-label">Live Data Sources</div></div>
|
||||
<div class="cs-kpi"><div class="cs-kpi-value">v2.0</div><div class="cs-kpi-label">Plugin Version</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- OVERVIEW -->
|
||||
<section class="section" aria-labelledby="overview-heading">
|
||||
<div class="container">
|
||||
<div class="cs-two-col cs-two-col--wide">
|
||||
<div>
|
||||
<p class="eyebrow">Overview</p>
|
||||
<h2 id="overview-heading">From calculators to a garden management app</h2>
|
||||
<p class="large">The first version of GardenBuddy was a set of gardening calculators I ran on the dayboro.au domain. Useful, but limited to one postcode and one set of conditions. So I rebuilt it as a standalone national platform. A gardener anywhere in Australia enters their postcode and gets advice calibrated to their actual climate zone and what's happening locally right now.</p>
|
||||
<p>The core plugin, "Buddy the Sprout", handles everything a member does: climate zone detection from postcode, garden bed setup, plant tracking from seed to harvest, pest monitoring, watering records, harvest logging, ROI calculations, and automated email recommendations. It pulls live weather data from my weather API and supermarket price data from a separate scraper I wrote that tracks Coles, Woolworths, Aldi, and IGA prices.</p>
|
||||
<div class="cs-quote">
|
||||
<p>"The question I built it to answer: is it cheaper to grow this myself, given my local conditions, than to buy it at Coles? The answer changes depending on where you live, what you grow, and what the shops are charging this week."</p>
|
||||
</div>
|
||||
<div class="cs-stack">
|
||||
<span class="cs-stack-tag">WordPress</span>
|
||||
<span class="cs-stack-tag">Custom Plugin</span>
|
||||
<span class="cs-stack-tag">PMPro Membership</span>
|
||||
<span class="cs-stack-tag">our weather API</span>
|
||||
<span class="cs-stack-tag">Price Scraper</span>
|
||||
<span class="cs-stack-tag">Email Reports</span>
|
||||
<span class="cs-stack-tag">Climate Zone DB</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<img src="../assets/images/port-gardenbuddy.jpg" alt="GardenBuddy.au garden management platform" style="width:100%;border-radius:var(--r-xl);box-shadow:var(--shadow-lg);" loading="lazy">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- HOW IT WORKS -->
|
||||
<section class="section section--alt" aria-labelledby="how-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">How It Works</p>
|
||||
<h2 id="how-heading">From postcode to planting advice in three steps</h2>
|
||||
<div class="cs-two-col">
|
||||
<div>
|
||||
<div class="cs-flow">
|
||||
<div class="cs-flow-step">
|
||||
<div class="cs-flow-num">1</div>
|
||||
<div>
|
||||
<div class="cs-flow-title">Enter your postcode</div>
|
||||
<div class="cs-flow-desc">The platform looks up the climate zone for that postcode from a national database. Australia has eight climate zones. Subtropical SE Queensland is zone 2, temperate Melbourne is zone 6, and so on. Every piece of planting advice, every pest risk threshold, and every growing guide is then filtered to match your zone.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cs-flow-step">
|
||||
<div class="cs-flow-num">2</div>
|
||||
<div>
|
||||
<div class="cs-flow-title">Set up your garden beds</div>
|
||||
<div class="cs-flow-desc">Add one or more garden beds with dimensions, soil type, and sun exposure. Then add plants to each bed: the variety, planting date, and how many seeds or seedlings went in. From that point, the platform tracks growth stages automatically from growing degree day data it pulls off the weather API. You don't update anything by hand.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cs-flow-step">
|
||||
<div class="cs-flow-num">3</div>
|
||||
<div>
|
||||
<div class="cs-flow-title">Get live recommendations</div>
|
||||
<div class="cs-flow-desc">Current temperature and humidity from my weather API feed the pest pressure model. If conditions favour aphids or fungal disease for your zone, you get an alert. The "Plant Now" panel shows what's in season for your postcode this month. The weekly Gardener Digest email summarises conditions, upcoming plant tasks, and current supermarket prices for what you are growing.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cs-flow-step">
|
||||
<div class="cs-flow-num">4</div>
|
||||
<div>
|
||||
<div class="cs-flow-title">Log your harvests</div>
|
||||
<div class="cs-flow-desc">Every harvest gets logged: the vegetable, the weight in kilos, and the date. The platform calculates your ROI: what you grew versus what you'd have paid at the supermarket for the same quantity. The price comparison uses the live scraped price data, not a fixed number.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="background:var(--ink-mid);border-radius:var(--r-xl);padding:var(--sp-6);color:var(--white);">
|
||||
<p class="eyebrow" style="color:rgba(34,197,94,.9);">What the platform tracks</p>
|
||||
<ul style="list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:14px;">
|
||||
<li style="display:flex;gap:12px;align-items:flex-start;">
|
||||
<span style="color:var(--green);font-size:18px;flex-shrink:0;">🌱</span>
|
||||
<div><strong style="color:var(--white);font-size:14px;">Garden beds and plants</strong><p style="font-size:13px;color:rgba(255,255,255,.55);margin:4px 0 0;line-height:1.5;">Add beds, add plants per bed, track planting dates, growth stages, expected harvest windows.</p></div>
|
||||
</li>
|
||||
<li style="display:flex;gap:12px;align-items:flex-start;">
|
||||
<span style="color:var(--green);font-size:18px;flex-shrink:0;">🌿</span>
|
||||
<div><strong style="color:var(--white);font-size:14px;">Pest and treatment records</strong><p style="font-size:13px;color:rgba(255,255,255,.55);margin:4px 0 0;line-height:1.5;">Log pest sightings and treatments applied. Checked against live pest pressure alerts.</p></div>
|
||||
</li>
|
||||
<li style="display:flex;gap:12px;align-items:flex-start;">
|
||||
<span style="color:var(--green);font-size:18px;flex-shrink:0;">💧</span>
|
||||
<div><strong style="color:var(--white);font-size:14px;">Watering, fertilising, mulching</strong><p style="font-size:13px;color:rgba(255,255,255,.55);margin:4px 0 0;line-height:1.5;">Record maintenance events per bed. The platform tracks when each bed was last watered and flags overdue tasks.</p></div>
|
||||
</li>
|
||||
<li style="display:flex;gap:12px;align-items:flex-start;">
|
||||
<span style="color:var(--green);font-size:18px;flex-shrink:0;">⚖️</span>
|
||||
<div><strong style="color:var(--white);font-size:14px;">Harvest history and ROI</strong><p style="font-size:13px;color:rgba(255,255,255,.55);margin:4px 0 0;line-height:1.5;">Every kilo logged. ROI calculated monthly against current Coles/Woolworths/Aldi/IGA average prices.</p></div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- LIVE DATA SOURCES -->
|
||||
<section class="section" aria-labelledby="data-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Live Data</p>
|
||||
<h2 id="data-heading">Four live data sources, all integrated</h2>
|
||||
<p style="max-width:640px;color:var(--grey-600);font-size:17px;line-height:1.7;">Static gardening advice is what most apps give you. I connected GardenBuddy to live data so the advice reflects what's happening now: current weather, current pest conditions, current supermarket prices.</p>
|
||||
|
||||
<div class="cs-feature-grid">
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🌦️</div>
|
||||
<h4>Weather data from our weather API</h4>
|
||||
<p>Current temperature, humidity, rainfall, and evapotranspiration from my Lyndhurst Hill weather station. The pest pressure model and the watering schedule calculator read from this API in real time. Members outside Dayboro get BOM sourced conditions for their postcode through the same API layer.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🛒</div>
|
||||
<h4>Supermarket price scraper</h4>
|
||||
<p>A separate gardenbuddy-prices plugin I wrote scrapes current vegetable prices from Coles, Woolworths, Aldi, and IGA at regular intervals. The ROI calculator uses these live prices, not fixed averages. If zucchini drops to $1.50/kg at Coles, the ROI on growing it drops with it.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🐛</div>
|
||||
<h4>Pest pressure model</h4>
|
||||
<p>The gardenbuddy-pests plugin maintains a model of pest activity thresholds by climate zone. Current temperature and humidity from the weather API feed into the model. If conditions are in the danger range for aphids, fungal disease, or caterpillar activity in zone 2, members in that zone get an alert.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🗓️</div>
|
||||
<h4>Planting calendar by postcode</h4>
|
||||
<p>The growzone-landing-pages plugin generates planting guides per climate zone. Enter a postcode, get a "what to plant this month" recommendation calibrated to the eight Australian climate zones, not just my own subtropical corner of SE Queensland.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">📧</div>
|
||||
<h4>Weekly Gardener Digest</h4>
|
||||
<p>Built on the same dayboro-email-reports plugin engine I use on dayboro.au. The weekly digest covers current pest pressure, plant tasks due this week, upcoming weather, and supermarket prices for the vegetables the member is growing. It's personalised per member from their garden bed contents.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🧑🌾</div>
|
||||
<h4>Demo garden</h4>
|
||||
<p>A fully populated example garden showing every feature: beds, plants at different growth stages, past harvest records, pest alerts, and an ROI report. New users can explore the demo garden without signing up, so they see exactly what the platform does before they commit.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cs-honest">
|
||||
<div class="cs-honest-label">Version 2: what changed</div>
|
||||
<p>Version 1 was a set of static calculators using weather data files from dayboro.au. It worked for Dayboro but not for anyone on a different postcode. Version 2 was a full (re)-build: a national climate zone database, a weather API layer that can serve conditions for any Australian postcode, and a proper user account system with garden bed management. The plugin version number (v2.0.6) reflects this. It isn't an incremental update, it's a different product.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- TECH STACK -->
|
||||
<section class="section section--alt" aria-labelledby="stack-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Under the Hood</p>
|
||||
<h2 id="stack-heading">Six custom plugins, one platform</h2>
|
||||
<p style="max-width:640px;color:var(--grey-600);font-size:17px;line-height:1.7;">I built the platform entirely on WordPress with custom plugins. No SaaS garden service behind it, no app framework from someone else. Every piece of it is code I wrote and own. There's no licence fee sitting under it that isn't mine.</p>
|
||||
|
||||
<div class="cs-feature-grid" style="margin-top:var(--sp-6);">
|
||||
<div class="cs-feature-card">
|
||||
<h4>garden-buddy (core)</h4>
|
||||
<p>The main plugin, "Buddy the Sprout" v2.0.6. Garden bed management, plant tracking, growth stage calculation, harvest logging, ROI reports, the My Garden dashboard, and everything members see and click. 20+ shortcodes covering the whole platform.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<h4>gardenbuddy-pests</h4>
|
||||
<p>Pest pressure model by climate zone. Temperature and humidity thresholds for 12 common garden pests. It reads the weather API to flag active risk conditions. Alerts appear in the My Garden dashboard and the weekly email.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<h4>gardenbuddy-prices</h4>
|
||||
<p>Supermarket price scraper. Tracks current retail prices for 40+ vegetables across Coles, Woolworths, Aldi, and IGA. Feeds the ROI calculator and the monthly price report section of the Gardener Digest.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<h4>gardenbuddy-buddy-check</h4>
|
||||
<p>A health check plugin that monitors the platform's data pipelines (weather API connectivity, price scraper freshness, cron job execution) and surfaces any failures in the WordPress admin before members notice them.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<h4>growzone-landing-pages</h4>
|
||||
<p>Generates landing pages for each of the eight Australian climate zones and for specific postcodes, tuned for organic search. "What to grow in zone 6 this month" style pages that bring gardeners to the platform.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<h4>dayboro-email-reports (shared)</h4>
|
||||
<p>The same email reports engine I run across dayboro.au. Queued sending, personalised content per subscriber, open tracking. On GardenBuddy it generates the weekly Gardener Digest with each member's own garden data.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cs-divider"></div>
|
||||
<h3 style="margin-bottom:var(--sp-3);">Full technology list</h3>
|
||||
<div class="cs-stack">
|
||||
<span class="cs-stack-tag">WordPress 6.x</span>
|
||||
<span class="cs-stack-tag">PHP 8.4</span>
|
||||
<span class="cs-stack-tag">MariaDB</span>
|
||||
<span class="cs-stack-tag">PMPro Membership</span>
|
||||
<span class="cs-stack-tag">Elementor Pro</span>
|
||||
<span class="cs-stack-tag">our weather API</span>
|
||||
<span class="cs-stack-tag">Redis cache</span>
|
||||
<span class="cs-stack-tag">Custom price scraper</span>
|
||||
<span class="cs-stack-tag">Australian climate zone DB</span>
|
||||
<span class="cs-stack-tag">Custom email queue</span>
|
||||
<span class="cs-stack-tag">BOM weather data</span>
|
||||
<span class="cs-stack-tag">DirectAdmin</span>
|
||||
<span class="cs-stack-tag">Google Site Kit</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- CTA -->
|
||||
<section class="section section--dark" aria-labelledby="cta-heading">
|
||||
<div class="container">
|
||||
<div class="cs-cta">
|
||||
<p class="eyebrow" style="color:rgba(34,197,94,.9);justify-content:center;">What we can build for you</p>
|
||||
<h2 id="cta-heading">A membership platform with live data baked in.</h2>
|
||||
<p>The GardenBuddy architecture (custom plugin, live data API, personalised email, content by postcode, PMPro membership) is a pattern I've now built twice, whilst the code stays mine to reuse on the next project. If your product involves connecting a member to live local data and giving them a personalised dashboard, this is the stack I'd use.</p>
|
||||
<div style="display:flex;gap:12px;justify-content:center;flex-wrap:wrap;">
|
||||
<a href="../contact.html" class="btn btn-primary">Talk to us about your project</a>
|
||||
<a href="../plugin-development.html" class="btn btn-secondary">Custom plugin development</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="footer" aria-label="Site footer">
|
||||
<div class="container">
|
||||
<div class="footer__grid">
|
||||
<div class="footer__brand">
|
||||
<img src="../assets/images/logo-cropped.jpg" alt="HELP4BIS" width="140" height="38">
|
||||
<p>Managed WordPress hosting and maintenance for Australian small businesses. Brisbane based, personal service, WordPress specialist, Brisbane.</p>
|
||||
<p style="font-size:13px; color:rgba(255,255,255,.4);">Dutch Digital Dynamics Pty Ltd · ABN 86 081 237 087</p>
|
||||
</div>
|
||||
<div class="footer__col">
|
||||
<h4>Services</h4>
|
||||
<ul class="footer__links">
|
||||
<li><a href="../managed-wordpress.html">Tailored Website Management</a></li>
|
||||
<li><a href="../care-plans.html">WP Care Plans</a></li>
|
||||
<li><a href="../sos-fix.html">WP SOS Fix</a></li>
|
||||
<li><a href="../ai-integration.html">AI Integration</a></li>
|
||||
<li><a href="../plugin-development.html">Plugin Development</a></li> </ul>
|
||||
</div>
|
||||
<div class="footer__col">
|
||||
<h4>Company</h4>
|
||||
<ul class="footer__links">
|
||||
<li><a href="../about.html">About Us</a></li>
|
||||
<li><a href="../index.html#portfolio">Our Work</a></li>
|
||||
<li><a href="../index.html#testimonials">Client Feedback</a></li>
|
||||
<li><a href="../blog/index.html">Blog</a></li>
|
||||
<li><a href="../contact.html">Contact</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer__col">
|
||||
<h4>Contact</h4>
|
||||
<ul class="footer__links">
|
||||
<li><a href="mailto:project@help4bis.com">project@help4bis.com</a></li>
|
||||
<li><a href="../contact.html">Submit a Brief</a></li>
|
||||
<li><a href="../sos-fix.html">Emergency Fix</a></li>
|
||||
</ul>
|
||||
<p style="margin-top:1rem; font-size:13px; color:rgba(255,255,255,.4);">Brisbane, Queensland<br>Response within 24 business hours</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer__bottom">
|
||||
<span>© 2026 HELP4BIS, a trading name of Dutch Digital Dynamics Pty Ltd · ABN 86 081 237 087</span>
|
||||
<span><a href="../privacy.html">Privacy Policy</a> · <a href="../terms.html">Terms</a></span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<button id="back-to-top" aria-label="Back to top" style="position:fixed;bottom:24px;right:24px;width:44px;height:44px;background:var(--red);border:none;border-radius:50%;color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .3s ease;box-shadow:var(--shadow-md);">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="18 15 12 9 6 15"/></svg>
|
||||
</button>
|
||||
<script src="../assets/js/main.js"></script>
|
||||
<script src="../analytics/tracker.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,518 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- Version: 1.2.0 | Created: 2026-05-05 | Updated: 2026-08-16 -->
|
||||
<html lang="en-AU">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>LocalBuddy Case Study | HELP4BIS</title>
|
||||
<meta name="description" content="How I built LocalBuddy.au: a community SaaS platform for Australian councils, community groups, and neighbourhoods. Events, directories, marketplace, and Matrix messaging, multi tenant, from $0 to $249/month.">
|
||||
<meta name="author" content="HELP4BIS">
|
||||
<meta name="publisher" content="Dutch Digital Dynamics Pty Ltd">
|
||||
<meta name="language" content="en-AU">
|
||||
<meta name="geo.region" content="AU-QLD">
|
||||
<link rel="canonical" href="https://help4bis.com/work/localbuddy-au.html">
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content="https://help4bis.com/work/localbuddy-au.html">
|
||||
<meta property="og:site_name" content="HELP4BIS">
|
||||
<meta property="og:title" content="LocalBuddy Case Study | HELP4BIS">
|
||||
<meta property="og:description" content="A community SaaS platform built in Brisbane for Australian councils and community groups: events, directories, marketplace, and secure messaging in one package.">
|
||||
<meta property="og:image" content="https://help4bis.com/assets/images/port-localbuddy.png">
|
||||
<meta property="og:locale" content="en_AU">
|
||||
<link rel="icon" type="image/jpeg" href="../assets/images/logo-favicon.jpg"> <link rel="stylesheet" href="../assets/css/style.css">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"@id": "https://help4bis.com/work/localbuddy-au.html#webpage",
|
||||
"url": "https://help4bis.com/work/localbuddy-au.html",
|
||||
"name": "LocalBuddy Case Study, HELP4BIS",
|
||||
"description": "Community SaaS platform for Australian councils and community groups: events, business directory, marketplace, and Matrix messaging.",
|
||||
"isPartOf": {"@id": "https://help4bis.com/#website"},
|
||||
"breadcrumb": {
|
||||
"@type": "BreadcrumbList",
|
||||
"itemListElement": [
|
||||
{"@type": "ListItem", "position": 1, "name": "Home", "item": "https://help4bis.com/"},
|
||||
{"@type": "ListItem", "position": 2, "name": "Our Work", "item": "https://help4bis.com/#portfolio"},
|
||||
{"@type": "ListItem", "position": 3, "name": "LocalBuddy", "item": "https://help4bis.com/work/localbuddy-au.html"}
|
||||
]
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.cs-hero {
|
||||
background: linear-gradient(160deg, var(--ink) 0%, var(--ink-mid) 60%, #1a1500 100%);
|
||||
padding: var(--sp-16) 0 var(--sp-12);
|
||||
position: relative; overflow: hidden;
|
||||
}
|
||||
.cs-hero::before {
|
||||
content: ''; position: absolute; top: -30%; right: -15%;
|
||||
width: 60%; height: 200%;
|
||||
background: radial-gradient(circle, rgba(245,158,11,.06) 0%, transparent 65%);
|
||||
pointer-events: none;
|
||||
}
|
||||
.cs-breadcrumb {
|
||||
font-size: 13px; color: rgba(255,255,255,.45);
|
||||
margin-bottom: var(--sp-5); display: flex; align-items: center; gap: 8px;
|
||||
}
|
||||
.cs-breadcrumb a { color: rgba(255,255,255,.45); }
|
||||
.cs-breadcrumb a:hover { color: var(--white); }
|
||||
.cs-breadcrumb span { color: rgba(255,255,255,.25); }
|
||||
.cs-hero h1 { color: var(--white); max-width: 820px; margin-bottom: var(--sp-4); }
|
||||
.cs-hero-sub {
|
||||
font-size: clamp(16px, 2vw, 20px); color: rgba(255,255,255,.65);
|
||||
max-width: 680px; line-height: 1.65; margin-bottom: var(--sp-6);
|
||||
}
|
||||
.cs-hero-actions { display: flex; gap: 12px; flex-wrap: wrap; }
|
||||
.btn-amber {
|
||||
background: linear-gradient(135deg, #F59E0B, #d97706);
|
||||
color: #1a1200; border-color: transparent;
|
||||
box-shadow: 0 4px 14px rgba(245,158,11,.35);
|
||||
font-weight: 700;
|
||||
}
|
||||
.btn-amber:hover {
|
||||
background: linear-gradient(135deg, #d97706, #b45309);
|
||||
color: #1a1200; transform: translateY(-2px);
|
||||
}
|
||||
.cs-kpis {
|
||||
display: grid; grid-template-columns: repeat(2, 1fr);
|
||||
gap: 16px; margin-top: var(--sp-8); padding-top: var(--sp-8);
|
||||
border-top: 1px solid rgba(255,255,255,.08);
|
||||
}
|
||||
@media (min-width: 640px) { .cs-kpis { grid-template-columns: repeat(4, 1fr); } }
|
||||
.cs-kpi { text-align: center; }
|
||||
.cs-kpi-value {
|
||||
font-family: var(--font-head); font-size: clamp(32px, 4vw, 52px);
|
||||
font-weight: 900; color: #F59E0B; line-height: 1; letter-spacing: -0.04em;
|
||||
}
|
||||
.cs-kpi-label {
|
||||
font-size: 12px; font-weight: 600; text-transform: uppercase;
|
||||
letter-spacing: .12em; color: rgba(255,255,255,.45); margin-top: 6px;
|
||||
}
|
||||
.cs-feature-grid {
|
||||
display: grid; grid-template-columns: 1fr; gap: 24px; margin-top: var(--sp-6);
|
||||
}
|
||||
@media (min-width: 640px) { .cs-feature-grid { grid-template-columns: repeat(2, 1fr); } }
|
||||
@media (min-width: 900px) { .cs-feature-grid { grid-template-columns: repeat(3, 1fr); } }
|
||||
.cs-feature-card {
|
||||
background: var(--white); border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-lg); padding: 24px; box-shadow: var(--shadow-card);
|
||||
}
|
||||
.cs-feature-card h4 { font-size: 15px; margin-bottom: 8px; color: var(--ink); }
|
||||
.cs-feature-card p { font-size: 14px; color: var(--grey-600); line-height: 1.6; margin: 0; }
|
||||
.cs-feature-icon {
|
||||
width: 36px; height: 36px; background: var(--grey-50); border-radius: var(--r-md);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
margin-bottom: 14px; font-size: 18px;
|
||||
}
|
||||
.cs-pricing-grid {
|
||||
display: grid; grid-template-columns: 1fr; gap: 20px; margin-top: var(--sp-6);
|
||||
}
|
||||
@media (min-width: 640px) { .cs-pricing-grid { grid-template-columns: repeat(2, 1fr); } }
|
||||
@media (min-width: 900px) { .cs-pricing-grid { grid-template-columns: repeat(4, 1fr); } }
|
||||
.cs-tier {
|
||||
background: var(--white); border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-lg); padding: 20px; box-shadow: var(--shadow-sm);
|
||||
}
|
||||
.cs-tier--featured {
|
||||
border-color: #F59E0B; box-shadow: 0 0 0 1px #F59E0B, var(--shadow-card);
|
||||
}
|
||||
.cs-tier-price {
|
||||
font-family: var(--font-head); font-size: 28px; font-weight: 800;
|
||||
color: var(--ink); letter-spacing: -0.03em; margin: 8px 0 4px;
|
||||
}
|
||||
.cs-tier-price span { font-size: 14px; font-weight: 400; color: var(--grey-600); }
|
||||
.cs-tier h5 { font-size: 14px; font-weight: 700; color: var(--grey-600); text-transform: uppercase; letter-spacing: .08em; margin: 0; }
|
||||
.cs-tier-target { font-size: 13px; color: var(--grey-600); margin: 0 0 12px; }
|
||||
.cs-tier-features { list-style: none; padding: 0; margin: 12px 0 0; }
|
||||
.cs-tier-features li { font-size: 13px; color: var(--grey-700); padding: 4px 0; border-top: 1px solid var(--grey-50); }
|
||||
.cs-stack { display: flex; flex-wrap: wrap; gap: 8px; margin-top: var(--sp-4); }
|
||||
.cs-stack-tag {
|
||||
background: var(--grey-50); border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-full); padding: 6px 14px; font-size: 13px; font-weight: 500; color: var(--grey-600);
|
||||
}
|
||||
.cs-two-col {
|
||||
display: grid; grid-template-columns: 1fr; gap: var(--sp-8); align-items: start;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.cs-two-col { grid-template-columns: 1fr 1fr; }
|
||||
.cs-two-col--wide { grid-template-columns: 3fr 2fr; }
|
||||
}
|
||||
.cs-quote {
|
||||
border-left: 3px solid #F59E0B;
|
||||
padding: var(--sp-4) var(--sp-5); background: rgba(245,158,11,.04);
|
||||
border-radius: 0 var(--r-md) var(--r-md) 0; margin: var(--sp-5) 0;
|
||||
}
|
||||
.cs-quote p { font-size: 17px; line-height: 1.7; color: var(--grey-800); font-style: italic; margin: 0; }
|
||||
.cs-honest {
|
||||
background: var(--grey-50); border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-lg); padding: var(--sp-4) var(--sp-5); margin: var(--sp-5) 0;
|
||||
}
|
||||
.cs-honest-label {
|
||||
font-size: 11px; font-weight: 700; text-transform: uppercase;
|
||||
letter-spacing: .12em; color: var(--grey-400); margin-bottom: 8px;
|
||||
}
|
||||
.cs-honest p { font-size: 14px; color: var(--grey-600); line-height: 1.65; margin: 0; }
|
||||
.cs-cta {
|
||||
background: linear-gradient(135deg, var(--ink-mid), var(--ink));
|
||||
border-radius: var(--r-2xl); padding: var(--sp-10) var(--sp-8); text-align: center;
|
||||
}
|
||||
.cs-cta h2 { color: var(--white); margin-bottom: var(--sp-4); }
|
||||
.cs-cta p { color: rgba(255,255,255,.65); max-width: 560px; margin: 0 auto var(--sp-6); font-size: 17px; line-height: 1.7; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- NAV -->
|
||||
<nav class="nav" role="navigation" aria-label="Main navigation">
|
||||
<div class="nav__inner">
|
||||
<a class="nav__logo" href="../index.html" aria-label="HELP4BIS home">
|
||||
<img src="../assets/images/logo-cropped.jpg" alt="HELP4BIS" width="140" height="38">
|
||||
</a>
|
||||
<ul class="nav__links" id="nav-links" role="list">
|
||||
<li class="nav__dropdown">
|
||||
<button class="nav__trigger" aria-haspopup="true" aria-expanded="false">Services <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg></button>
|
||||
<ul class="nav__dropdown-menu" role="menu">
|
||||
<li class="nav__menu-group">WordPress</li>
|
||||
<li><a href="../managed-wordpress.html" role="menuitem">Tailored Website Management</a></li>
|
||||
<li><a href="../care-plans.html" role="menuitem">WP Care Plans <span class="menu-price">from $49/mo</span></a></li>
|
||||
<li><a href="../sos-fix.html" role="menuitem">WP SOS Fix <span class="menu-price">$97 flat</span></a></li>
|
||||
<li><a href="../ai-integration.html" role="menuitem">AI Integration</a></li>
|
||||
<li><a href="../plugin-development.html" role="menuitem">Custom Plugin Development</a></li> </ul>
|
||||
</li>
|
||||
<li><a href="../about.html">About</a></li>
|
||||
<li><a href="../index.html#portfolio">Our Work</a></li>
|
||||
<li><a href="../index.html#pricing">Pricing</a></li>
|
||||
<li><a href="../blog/index.html">Blog</a></li>
|
||||
<li><a href="../your-first-week-with-ai.html">AI Guide</a></li>
|
||||
<li><a href="../contact.html">Contact</a></li>
|
||||
<li class="nav__cta-mobile" aria-hidden="true">
|
||||
<a href="../contact.html" class="btn btn-primary">Get Started</a>
|
||||
<a href="../sos-fix.html" class="btn btn-secondary">SOS Fix, $97</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="nav__cta">
|
||||
<a href="../sos-fix.html" class="btn btn-secondary btn-sm">SOS Fix, $97</a>
|
||||
<a href="../contact.html" class="btn btn-primary btn-sm">Get Started</a>
|
||||
</div>
|
||||
<button class="nav__burger" id="nav-burger" aria-label="Open menu" aria-expanded="false" aria-controls="nav-links">
|
||||
<span></span><span></span><span></span>
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- HERO -->
|
||||
<section class="cs-hero" aria-labelledby="cs-heading">
|
||||
<div class="container">
|
||||
<div class="cs-breadcrumb">
|
||||
<a href="../index.html">Home</a>
|
||||
<span>›</span>
|
||||
<a href="../index.html#portfolio">Our Work</a>
|
||||
<span>›</span>
|
||||
<span style="color:rgba(255,255,255,.7);">LocalBuddy</span>
|
||||
</div>
|
||||
<p class="eyebrow" style="color:rgba(245,158,11,.9);">Case Study: Community SaaS Platform</p>
|
||||
<h1 id="cs-heading">LocalBuddy.<br>Community infrastructure<br>for Australian neighbourhoods.</h1>
|
||||
<p class="cs-hero-sub">A multi tenant community platform I built in Brisbane for local councils, community groups, and neighbourhood associations. Events and RSVPs, a business directory, a buy, sell and swap marketplace, and secure messaging on Matrix, all in one package, running under their own branding.</p>
|
||||
<div class="cs-hero-actions">
|
||||
<a href="https://localbuddy.au" target="_blank" rel="noopener" class="btn btn-amber">Visit localbuddy.au →</a>
|
||||
<a href="../contact.html" class="btn btn-secondary">Ask about this for your community</a>
|
||||
</div>
|
||||
<div class="cs-kpis">
|
||||
<div class="cs-kpi">
|
||||
<div class="cs-kpi-value">AU</div>
|
||||
<div class="cs-kpi-label">Built for Australia</div>
|
||||
</div>
|
||||
<div class="cs-kpi">
|
||||
<div class="cs-kpi-value">$0</div>
|
||||
<div class="cs-kpi-label">Free Tier Exists</div>
|
||||
</div>
|
||||
<div class="cs-kpi">
|
||||
<div class="cs-kpi-value">4</div>
|
||||
<div class="cs-kpi-label">Core Modules</div>
|
||||
</div>
|
||||
<div class="cs-kpi">
|
||||
<div class="cs-kpi-value">Multi</div>
|
||||
<div class="cs-kpi-label">Tenant Architecture</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- OVERVIEW -->
|
||||
<section class="section" aria-labelledby="overview-heading">
|
||||
<div class="container">
|
||||
<div class="cs-two-col cs-two-col--wide">
|
||||
<div>
|
||||
<p class="eyebrow">Overview</p>
|
||||
<h2 id="overview-heading">What it actually is</h2>
|
||||
<p class="large">Most community groups I deal with (Lions clubs, P&C associations, neighbourhood watch groups, rural fire brigades) run their communication across three or four different platforms that don't talk to each other. Facebook for announcements, a separate spreadsheet for the directory, email chains for RSVPs, and WhatsApp for the daily chat that nobody outside can see.</p>
|
||||
<p>I built LocalBuddy to consolidate those into a single platform that runs under the community's own branding. The council or group gets their own subdomain, their own colour scheme, and their own data. The underlying infrastructure is shared across tenants, which is where the (re)-usability of the platform keeps the cost down. They look independent even though they aren't running their own server.</p>
|
||||
<p>The four modules cover the four things communities actually need: knowing what's on this weekend, finding a local tradie, selling a second hand lawnmower, and talking to each other without the feed algorithm deciding who sees what.</p>
|
||||
<div class="cs-quote">
|
||||
<p>"Nextdoor exists. Facebook Groups exist. Neither is owned by the community, neither runs on Australian servers, and neither lets the group admin control what data is collected and where it goes. That is the gap."</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<img src="../assets/images/port-localbuddy.png" alt="LocalBuddy community platform" style="width:100%;border-radius:var(--r-xl);box-shadow:var(--shadow-lg);" loading="lazy">
|
||||
<div class="cs-stack" style="margin-top:20px;">
|
||||
<span class="cs-stack-tag">Static HTML</span>
|
||||
<span class="cs-stack-tag">Matrix Protocol</span>
|
||||
<span class="cs-stack-tag">Multi-Tenant SaaS</span>
|
||||
<span class="cs-stack-tag">REST API</span>
|
||||
<span class="cs-stack-tag">Custom Branding</span>
|
||||
<span class="cs-stack-tag">Australian Hosted</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FOUR MODULES -->
|
||||
<section class="section section--alt" aria-labelledby="modules-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Core Modules</p>
|
||||
<h2 id="modules-heading">Four things communities actually need</h2>
|
||||
<p style="max-width:640px;color:var(--grey-600);font-size:17px;line-height:1.7;margin-bottom:0;">I designed each module for how a community group actually works. No feature chasing, no "engagement metrics", just the tools that reduce the admin burden of running a local organisation.</p>
|
||||
|
||||
<div class="cs-feature-grid">
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">📅</div>
|
||||
<h4>Events + RSVP + Calendar</h4>
|
||||
<p>Post events, collect RSVPs, send reminders. The calendar view shows what's on this week and this month. RSVP confirmation emails go out automatically. The admin sees a live headcount. No spreadsheet required.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🏪</div>
|
||||
<h4>Business Directory with Reviews</h4>
|
||||
<p>The local business directory with categories, search, contact details, and community reviews. Businesses can claim their listing. The directory admin approves new listings and removes stale ones. Replaces the printed community guide.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🔄</div>
|
||||
<h4>Buy, Sell, Swap Marketplace</h4>
|
||||
<p>A neighbourhood marketplace for second hand goods, free items, and services. Listings expire automatically. Photo uploads supported. Not Facebook Marketplace, but it's yours: no algorithm, no data mining, no ads.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">💬</div>
|
||||
<h4>Secure Messaging on Matrix</h4>
|
||||
<p>Group and private messaging runs on the Matrix protocol. Open standard, federated, encrypted end to end. The community's messages are stored on Australian infrastructure I manage. No vendor lock in; the protocol is publicly documented.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🎨</div>
|
||||
<h4>Custom Branding Per Tenant</h4>
|
||||
<p>Each community gets their own subdomain and their own colour scheme. The Dayboro Lions Club looks like the Dayboro Lions Club, not "powered by LocalBuddy with a logo in the corner." Branding is configurable from the tenant admin panel.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">📊</div>
|
||||
<h4>Analytics Dashboard</h4>
|
||||
<p>Tenant admins can see how the platform is being used: active members, event attendance trends, directory search terms, marketplace listing activity. The data belongs to the tenant and stays in Australia, on infrastructure I run.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- PRICING -->
|
||||
<section class="section" aria-labelledby="pricing-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Pricing</p>
|
||||
<h2 id="pricing-heading">Tiers built for community budgets</h2>
|
||||
<p style="max-width:640px;color:var(--grey-600);font-size:17px;line-height:1.7;margin-bottom:0;">Community groups don't have IT budgets, so I priced the tiers around that. The free tier costs nothing and does the real job. Councils and larger organisations that need SLAs, custom domains, and support have a path to paid tiers that reflects the value, whilst the free tier stays functional rather than a crippled demo.</p>
|
||||
|
||||
<div class="cs-pricing-grid">
|
||||
<div class="cs-tier">
|
||||
<h5>Community</h5>
|
||||
<div class="cs-tier-price">$0 <span>/month</span></div>
|
||||
<p class="cs-tier-target">Clubs, sporting groups, neighbourhood associations</p>
|
||||
<ul class="cs-tier-features">
|
||||
<li>All four modules</li>
|
||||
<li>Up to 200 members</li>
|
||||
<li>LocalBuddy subdomain</li>
|
||||
<li>Standard support</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="cs-tier">
|
||||
<h5>Group</h5>
|
||||
<div class="cs-tier-price">$49 <span>/month</span></div>
|
||||
<p class="cs-tier-target">Active community groups, RSLs, Lions clubs</p>
|
||||
<ul class="cs-tier-features">
|
||||
<li>Everything in Community</li>
|
||||
<li>Up to 1,000 members</li>
|
||||
<li>Custom domain</li>
|
||||
<li>Custom branding</li>
|
||||
<li>Priority support</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="cs-tier cs-tier--featured">
|
||||
<h5>Organisation</h5>
|
||||
<div class="cs-tier-price">$149 <span>/month</span></div>
|
||||
<p class="cs-tier-target">Business chambers, regional groups, large associations</p>
|
||||
<ul class="cs-tier-features">
|
||||
<li>Everything in Group</li>
|
||||
<li>Unlimited members</li>
|
||||
<li>Analytics dashboard</li>
|
||||
<li>API access</li>
|
||||
<li>SLA guarantee</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="cs-tier">
|
||||
<h5>Council</h5>
|
||||
<div class="cs-tier-price">$249 <span>/month</span></div>
|
||||
<p class="cs-tier-target">Local councils, regional development boards</p>
|
||||
<ul class="cs-tier-features">
|
||||
<li>Everything in Organisation</li>
|
||||
<li>Multi suburb deployment</li>
|
||||
<li>White label (no LocalBuddy branding)</li>
|
||||
<li>Dedicated support contact</li>
|
||||
<li>Custom feature development</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ARCHITECTURE -->
|
||||
<section class="section section--alt" aria-labelledby="arch-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Under the Hood</p>
|
||||
<h2 id="arch-heading">Multi tenant architecture</h2>
|
||||
<div class="cs-two-col">
|
||||
<div>
|
||||
<p>LocalBuddy runs on a multi tenant architecture where all tenants share the same underlying infrastructure but are isolated at the data layer. A community in Dayboro can't see the data of a community in Toowoomba. As the platform admin, I can see all tenants for operational purposes.</p>
|
||||
<p>The landing page at localbuddy.au is a static HTML site I wrote. No WordPress, no framework. It loads fast, it doesn't break, and it doesn't need updating every time a WordPress plugin releases a security patch. I keep the platform application on separate infrastructure behind the scenes.</p>
|
||||
<p>Matrix for messaging was my deliberate choice. The Matrix protocol is open, federated, and well documented. If LocalBuddy ever shut down or a community wanted to host their messaging themselves, they could export their room history and move to any Matrix compatible server. That isn't possible with WhatsApp or Facebook Messenger.</p>
|
||||
</div>
|
||||
<div>
|
||||
<div class="cs-feature-card" style="margin-bottom:16px;">
|
||||
<div class="cs-feature-icon">🏗️</div>
|
||||
<h4>Tenant isolation</h4>
|
||||
<p>Each tenant has their own database schema prefix. Events, directory listings, marketplace items, and member records are scoped per tenant. Cross-tenant queries are not possible from tenant-level code.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card" style="margin-bottom:16px;">
|
||||
<div class="cs-feature-icon">🌐</div>
|
||||
<h4>Custom domains</h4>
|
||||
<p>Paid tiers get their own subdomain or custom domain. The platform provisions SSL automatically. From the community's perspective, it's their website.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🔐</div>
|
||||
<h4>Australian data sovereignty</h4>
|
||||
<p>I store all data in Australia. No content moderation AI, no advertising targeting, no data sharing with third parties. The community owns their member data.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cs-honest">
|
||||
<div class="cs-honest-label">Current status</div>
|
||||
<p>LocalBuddy is in active development. The platform architecture and landing page are built. The deployment model and tenant provisioning system are functional. The first community tenants are the Dayboro Lions Club directory (which runs on the same infrastructure as dayboro.au) and a pilot group in the Moreton Bay region. I haven't opened public sign up for new communities without prior contact. That's deliberate while I refine the onboarding process.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- TECH STACK -->
|
||||
<section class="section" aria-labelledby="stack-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Technical Details</p>
|
||||
<h2 id="stack-heading">Full stack</h2>
|
||||
<div class="cs-two-col">
|
||||
<div>
|
||||
<h4 style="font-size:15px;margin-bottom:12px;color:var(--ink);">Landing page</h4>
|
||||
<div class="cs-stack" style="margin-top:0;">
|
||||
<span class="cs-stack-tag">Static HTML</span>
|
||||
<span class="cs-stack-tag">Vanilla CSS</span>
|
||||
<span class="cs-stack-tag">No framework dependency</span>
|
||||
<span class="cs-stack-tag">Australian hosted</span>
|
||||
</div>
|
||||
<h4 style="font-size:15px;margin-bottom:12px;margin-top:24px;color:var(--ink);">Platform application</h4>
|
||||
<div class="cs-stack" style="margin-top:0;">
|
||||
<span class="cs-stack-tag">REST API backend</span>
|
||||
<span class="cs-stack-tag">Multi-tenant database</span>
|
||||
<span class="cs-stack-tag">Matrix protocol (messaging)</span>
|
||||
<span class="cs-stack-tag">Platform API layer</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4 style="font-size:15px;margin-bottom:12px;color:var(--ink);">Infrastructure</h4>
|
||||
<div class="cs-stack" style="margin-top:0;">
|
||||
<span class="cs-stack-tag">DirectAdmin, brisbane01</span>
|
||||
<span class="cs-stack-tag">Let's Encrypt SSL</span>
|
||||
<span class="cs-stack-tag">Australian data centre</span>
|
||||
<span class="cs-stack-tag">Automatic subdomain provisioning</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- CTA -->
|
||||
<section class="section section--alt">
|
||||
<div class="container">
|
||||
<div class="cs-cta">
|
||||
<h2>Running a community group or local council?</h2>
|
||||
<p>If you're managing a community organisation on a mix of Facebook, email chains, and shared Google Docs, I built LocalBuddy for exactly that situation. Get in touch and I'll talk you through whether it fits.</p>
|
||||
<div class="cs-hero-actions" style="justify-content:center;">
|
||||
<a href="https://localbuddy.au" target="_blank" rel="noopener" class="btn btn-primary btn-lg">See the platform</a>
|
||||
<a href="../contact.html" class="btn btn-secondary btn-lg">Talk to us</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-top:var(--sp-8);text-align:center;">
|
||||
<a href="../index.html#portfolio" style="font-size:14px;color:var(--grey-400);">← Back to all work</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FOOTER -->
|
||||
<footer class="footer" aria-label="Site footer">
|
||||
<div class="container">
|
||||
<div class="footer__grid">
|
||||
<div class="footer__brand">
|
||||
<img src="../assets/images/logo-cropped.jpg" alt="HELP4BIS" width="140" height="38">
|
||||
<p>Managed WordPress hosting and maintenance for Australian small businesses. Brisbane based, personal service, WordPress specialist.</p>
|
||||
<p style="margin-top:8px; font-size:12px; color:rgba(255,255,255,.25);">Dutch Digital Dynamics Pty Ltd · ABN 86 081 237 087</p>
|
||||
</div>
|
||||
<div class="footer__col">
|
||||
<h4>Services</h4>
|
||||
<ul class="footer__links">
|
||||
<li><a href="../managed-wordpress.html">Tailored Website Management</a></li>
|
||||
<li><a href="../care-plans.html">WP Care Plans</a></li>
|
||||
<li><a href="../sos-fix.html">WP SOS Fix</a></li>
|
||||
<li><a href="../ai-integration.html">AI Integration</a></li>
|
||||
<li><a href="../plugin-development.html">Plugin Development</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer__col">
|
||||
<h4>Our Work</h4>
|
||||
<ul class="footer__links">
|
||||
<li><a href="dayboro-au.html">Dayboro.au</a></li>
|
||||
<li><a href="gardenbuddy-au.html">GardenBuddy.au</a></li>
|
||||
<li><a href="tawnytrails.html">Tawny Trails</a></li>
|
||||
<li><a href="rds-ink.html">Running Duck Studio</a></li>
|
||||
<li><a href="localbuddy-au.html">LocalBuddy</a></li>
|
||||
<li><a href="m8chat-au.html">M8Chat</a></li>
|
||||
<li><a href="nightcap-nm.html">Nightcap Natural Medicine</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer__col">
|
||||
<h4>Contact</h4>
|
||||
<ul class="footer__links">
|
||||
<li><a href="mailto:project@help4bis.com">project@help4bis.com</a></li>
|
||||
<li><a href="../contact.html">Submit a Brief</a></li>
|
||||
<li><a href="../sos-fix.html">Emergency Fix</a></li>
|
||||
</ul>
|
||||
<p style="margin-top:16px; font-size:12px; color:rgba(255,255,255,.3);">Brisbane, Queensland<br>Response within 24 business hours</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer__bottom">
|
||||
<span>© 2026 HELP4BIS, a trading name of Dutch Digital Dynamics Pty Ltd · ABN 86 081 237 087</span>
|
||||
<span><a href="../privacy.html">Privacy</a> · <a href="../terms.html">Terms</a></span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<button id="back-to-top" aria-label="Back to top">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="18 15 12 9 6 15"/></svg>
|
||||
</button>
|
||||
|
||||
<script src="../assets/js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,517 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- Version: 1.3.0 | Created: 2026-05-05 | Updated: 2026-08-16 -->
|
||||
<html lang="en-AU">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>M8Chat Case Study | HELP4BIS</title>
|
||||
<meta name="description" content="How I built M8Chat: a self hosted Matrix and Element chat server with Jitsi video conferencing and a Flutter mobile app, all running on private Australian infrastructure. No US big tech required.">
|
||||
<meta name="author" content="HELP4BIS">
|
||||
<meta name="publisher" content="Dutch Digital Dynamics Pty Ltd">
|
||||
<meta name="language" content="en-AU">
|
||||
<meta name="geo.region" content="AU-QLD">
|
||||
<link rel="canonical" href="https://help4bis.com/work/m8chat-au.html">
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content="https://help4bis.com/work/m8chat-au.html">
|
||||
<meta property="og:site_name" content="HELP4BIS">
|
||||
<meta property="og:title" content="M8Chat Case Study | HELP4BIS">
|
||||
<meta property="og:description" content="Self hosted Matrix chat, Jitsi video conferencing and a Flutter mobile app, all running on private Australian servers. No Zoom, no Slack, no data in the US.">
|
||||
<meta property="og:image" content="https://help4bis.com/assets/images/port-m8chat.png">
|
||||
<meta property="og:locale" content="en_AU">
|
||||
<link rel="icon" type="image/jpeg" href="../assets/images/logo-favicon.jpg"> <link rel="stylesheet" href="../assets/css/style.css">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"@id": "https://help4bis.com/work/m8chat-au.html#webpage",
|
||||
"url": "https://help4bis.com/work/m8chat-au.html",
|
||||
"name": "M8Chat Case Study, HELP4BIS",
|
||||
"description": "Self hosted Matrix chat, Jitsi video conferencing and a Flutter mobile app on private Australian infrastructure.",
|
||||
"isPartOf": {"@id": "https://help4bis.com/#website"},
|
||||
"breadcrumb": {
|
||||
"@type": "BreadcrumbList",
|
||||
"itemListElement": [
|
||||
{"@type": "ListItem", "position": 1, "name": "Home", "item": "https://help4bis.com/"},
|
||||
{"@type": "ListItem", "position": 2, "name": "Our Work", "item": "https://help4bis.com/#portfolio"},
|
||||
{"@type": "ListItem", "position": 3, "name": "M8Chat", "item": "https://help4bis.com/work/m8chat-au.html"}
|
||||
]
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.cs-hero {
|
||||
background: linear-gradient(160deg, var(--ink) 0%, #0f1a2e 60%, #0a0f1a 100%);
|
||||
padding: var(--sp-16) 0 var(--sp-12);
|
||||
position: relative; overflow: hidden;
|
||||
}
|
||||
.cs-hero::before {
|
||||
content: ''; position: absolute; top: -30%; right: -15%;
|
||||
width: 60%; height: 200%;
|
||||
background: radial-gradient(circle, rgba(99,102,241,.07) 0%, transparent 65%);
|
||||
pointer-events: none;
|
||||
}
|
||||
.cs-breadcrumb {
|
||||
font-size: 13px; color: rgba(255,255,255,.45);
|
||||
margin-bottom: var(--sp-5); display: flex; align-items: center; gap: 8px;
|
||||
}
|
||||
.cs-breadcrumb a { color: rgba(255,255,255,.45); }
|
||||
.cs-breadcrumb a:hover { color: var(--white); }
|
||||
.cs-breadcrumb span { color: rgba(255,255,255,.25); }
|
||||
.cs-hero h1 { color: var(--white); max-width: 820px; margin-bottom: var(--sp-4); }
|
||||
.cs-hero-sub {
|
||||
font-size: clamp(16px, 2vw, 20px); color: rgba(255,255,255,.65);
|
||||
max-width: 680px; line-height: 1.65; margin-bottom: var(--sp-6);
|
||||
}
|
||||
.cs-hero-actions { display: flex; gap: 12px; flex-wrap: wrap; }
|
||||
.btn-indigo {
|
||||
background: linear-gradient(135deg, #6366f1, #4f46e5);
|
||||
color: var(--white); border-color: transparent;
|
||||
box-shadow: 0 4px 14px rgba(99,102,241,.35);
|
||||
}
|
||||
.btn-indigo:hover {
|
||||
background: linear-gradient(135deg, #4f46e5, #4338ca);
|
||||
color: var(--white); transform: translateY(-2px);
|
||||
}
|
||||
.cs-kpis {
|
||||
display: grid; grid-template-columns: repeat(2, 1fr);
|
||||
gap: 16px; margin-top: var(--sp-8); padding-top: var(--sp-8);
|
||||
border-top: 1px solid rgba(255,255,255,.08);
|
||||
}
|
||||
@media (min-width: 640px) { .cs-kpis { grid-template-columns: repeat(4, 1fr); } }
|
||||
.cs-kpi { text-align: center; }
|
||||
.cs-kpi-value {
|
||||
font-family: var(--font-head); font-size: clamp(32px, 4vw, 52px);
|
||||
font-weight: 900; color: #818cf8; line-height: 1; letter-spacing: -0.04em;
|
||||
}
|
||||
.cs-kpi-label {
|
||||
font-size: 12px; font-weight: 600; text-transform: uppercase;
|
||||
letter-spacing: .12em; color: rgba(255,255,255,.45); margin-top: 6px;
|
||||
}
|
||||
.cs-feature-grid {
|
||||
display: grid; grid-template-columns: 1fr; gap: 24px; margin-top: var(--sp-6);
|
||||
}
|
||||
@media (min-width: 640px) { .cs-feature-grid { grid-template-columns: repeat(2, 1fr); } }
|
||||
@media (min-width: 900px) { .cs-feature-grid { grid-template-columns: repeat(3, 1fr); } }
|
||||
.cs-feature-card {
|
||||
background: var(--white); border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-lg); padding: 24px; box-shadow: var(--shadow-card);
|
||||
}
|
||||
.cs-feature-card h4 { font-size: 15px; margin-bottom: 8px; color: var(--ink); }
|
||||
.cs-feature-card p { font-size: 14px; color: var(--grey-600); line-height: 1.6; margin: 0; }
|
||||
.cs-feature-icon {
|
||||
width: 36px; height: 36px; background: var(--grey-50); border-radius: var(--r-md);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
margin-bottom: 14px; font-size: 18px;
|
||||
}
|
||||
.cs-server-grid {
|
||||
display: grid; grid-template-columns: 1fr; gap: 16px; margin-top: var(--sp-5);
|
||||
}
|
||||
@media (min-width: 640px) { .cs-server-grid { grid-template-columns: repeat(2, 1fr); } }
|
||||
.cs-server-card {
|
||||
background: var(--white); border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-lg); padding: 20px; box-shadow: var(--shadow-sm);
|
||||
}
|
||||
.cs-server-card h5 { font-size: 14px; font-weight: 700; color: var(--ink); margin-bottom: 4px; }
|
||||
.cs-server-domain { font-size: 13px; color: #6366f1; font-weight: 600; margin-bottom: 8px; font-family: monospace; }
|
||||
.cs-server-card p { font-size: 13px; color: var(--grey-600); line-height: 1.55; margin: 0; }
|
||||
.cs-stack { display: flex; flex-wrap: wrap; gap: 8px; margin-top: var(--sp-4); }
|
||||
.cs-stack-tag {
|
||||
background: var(--grey-50); border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-full); padding: 6px 14px; font-size: 13px; font-weight: 500; color: var(--grey-600);
|
||||
}
|
||||
.cs-two-col {
|
||||
display: grid; grid-template-columns: 1fr; gap: var(--sp-8); align-items: start;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.cs-two-col { grid-template-columns: 1fr 1fr; }
|
||||
.cs-two-col--wide { grid-template-columns: 3fr 2fr; }
|
||||
}
|
||||
.cs-quote {
|
||||
border-left: 3px solid #6366f1;
|
||||
padding: var(--sp-4) var(--sp-5); background: rgba(99,102,241,.04);
|
||||
border-radius: 0 var(--r-md) var(--r-md) 0; margin: var(--sp-5) 0;
|
||||
}
|
||||
.cs-quote p { font-size: 17px; line-height: 1.7; color: var(--grey-800); font-style: italic; margin: 0; }
|
||||
.cs-honest {
|
||||
background: var(--grey-50); border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-lg); padding: var(--sp-4) var(--sp-5); margin: var(--sp-5) 0;
|
||||
}
|
||||
.cs-honest-label {
|
||||
font-size: 11px; font-weight: 700; text-transform: uppercase;
|
||||
letter-spacing: .12em; color: var(--grey-400); margin-bottom: 8px;
|
||||
}
|
||||
.cs-honest p { font-size: 14px; color: var(--grey-600); line-height: 1.65; margin: 0; }
|
||||
.cs-cta {
|
||||
background: linear-gradient(135deg, var(--ink-mid), var(--ink));
|
||||
border-radius: var(--r-2xl); padding: var(--sp-10) var(--sp-8); text-align: center;
|
||||
}
|
||||
.cs-cta h2 { color: var(--white); margin-bottom: var(--sp-4); }
|
||||
.cs-cta p { color: rgba(255,255,255,.65); max-width: 560px; margin: 0 auto var(--sp-6); font-size: 17px; line-height: 1.7; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- NAV -->
|
||||
<nav class="nav" role="navigation" aria-label="Main navigation">
|
||||
<div class="nav__inner">
|
||||
<a class="nav__logo" href="../index.html" aria-label="HELP4BIS home">
|
||||
<img src="../assets/images/logo-cropped.jpg" alt="HELP4BIS" width="140" height="38">
|
||||
</a>
|
||||
<ul class="nav__links" id="nav-links" role="list">
|
||||
<li class="nav__dropdown">
|
||||
<button class="nav__trigger" aria-haspopup="true" aria-expanded="false">Services <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg></button>
|
||||
<ul class="nav__dropdown-menu" role="menu">
|
||||
<li class="nav__menu-group">WordPress</li>
|
||||
<li><a href="../managed-wordpress.html" role="menuitem">Tailored Website Management</a></li>
|
||||
<li><a href="../care-plans.html" role="menuitem">WP Care Plans <span class="menu-price">from $49/mo</span></a></li>
|
||||
<li><a href="../sos-fix.html" role="menuitem">WP SOS Fix <span class="menu-price">$97 flat</span></a></li>
|
||||
<li><a href="../ai-integration.html" role="menuitem">AI Integration</a></li>
|
||||
<li><a href="../plugin-development.html" role="menuitem">Custom Plugin Development</a></li> </ul>
|
||||
</li>
|
||||
<li><a href="../about.html">About</a></li>
|
||||
<li><a href="../index.html#portfolio">Our Work</a></li>
|
||||
<li><a href="../index.html#pricing">Pricing</a></li>
|
||||
<li><a href="../blog/index.html">Blog</a></li>
|
||||
<li><a href="../your-first-week-with-ai.html">AI Guide</a></li>
|
||||
<li><a href="../contact.html">Contact</a></li>
|
||||
<li class="nav__cta-mobile" aria-hidden="true">
|
||||
<a href="../contact.html" class="btn btn-primary">Get Started</a>
|
||||
<a href="../sos-fix.html" class="btn btn-secondary">SOS Fix, $97</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="nav__cta">
|
||||
<a href="../sos-fix.html" class="btn btn-secondary btn-sm">SOS Fix, $97</a>
|
||||
<a href="../contact.html" class="btn btn-primary btn-sm">Get Started</a>
|
||||
</div>
|
||||
<button class="nav__burger" id="nav-burger" aria-label="Open menu" aria-expanded="false" aria-controls="nav-links">
|
||||
<span></span><span></span><span></span>
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- HERO -->
|
||||
<section class="cs-hero" aria-labelledby="cs-heading">
|
||||
<div class="container">
|
||||
<div class="cs-breadcrumb">
|
||||
<a href="../index.html">Home</a>
|
||||
<span>›</span>
|
||||
<a href="../index.html#portfolio">Our Work</a>
|
||||
<span>›</span>
|
||||
<span style="color:rgba(255,255,255,.7);">M8Chat</span>
|
||||
</div>
|
||||
<p class="eyebrow" style="color:rgba(129,140,248,.9);">Case Study: Secure Communications Platform</p>
|
||||
<h1 id="cs-heading">M8Chat.<br>Chat, video, and mobile,<br>without giving it all to US big tech.</h1>
|
||||
<p class="cs-hero-sub">A self hosted Matrix messaging server, Jitsi video conferencing and a Flutter mobile app, all running on private Australian VPS infrastructure. No Zoom account, no Slack subscription, no message history sitting in someone else's US data centre.</p>
|
||||
<div class="cs-hero-actions">
|
||||
<a href="https://m8chat.au" target="_blank" rel="noopener" class="btn btn-indigo">Visit m8chat.au →</a>
|
||||
<a href="https://app.m8chat.au" target="_blank" rel="noopener" class="btn btn-secondary">Open the app</a>
|
||||
</div>
|
||||
<div class="cs-kpis">
|
||||
<div class="cs-kpi">
|
||||
<div class="cs-kpi-value">E2E</div>
|
||||
<div class="cs-kpi-label">Encrypted</div>
|
||||
</div>
|
||||
<div class="cs-kpi">
|
||||
<div class="cs-kpi-value">AU</div>
|
||||
<div class="cs-kpi-label">Data Sovereign</div>
|
||||
</div>
|
||||
<div class="cs-kpi">
|
||||
<div class="cs-kpi-value">VPS</div>
|
||||
<div class="cs-kpi-label">Private Infrastructure</div>
|
||||
</div>
|
||||
<div class="cs-kpi">
|
||||
<div class="cs-kpi-value">Open</div>
|
||||
<div class="cs-kpi-label">Source Stack</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- OVERVIEW -->
|
||||
<section class="section" aria-labelledby="overview-heading">
|
||||
<div class="container">
|
||||
<div class="cs-two-col cs-two-col--wide">
|
||||
<div>
|
||||
<p class="eyebrow">Overview</p>
|
||||
<h2 id="overview-heading">What it actually is</h2>
|
||||
<p class="large">Zoom is fine until it isn't. At some point you start wondering where the recordings go, whether Zoom keeps the chat logs for their own purposes, and whether "HIPAA compliant" on a US platform means the same thing it would mean on Australian infrastructure. I hear those questions more from health workers, legal services and community organisations than most vendors admit.</p>
|
||||
<p>M8Chat is the answer I built for myself and for community use. It runs on the Matrix protocol (open, federated, end to end encrypted) on my own Matrix Homeserver infrastructure in Australia. Video conferencing runs on a separate dedicated VPS. The mobile and web app is my own Flutter Matrix client, deployed as a PWA at app.m8chat.au and available as an APK for Android.</p>
|
||||
<p>The entire stack is open source. If M8Chat shut down tomorrow, every user could take their conversation history and move to any other Matrix server. The data belongs to the users, not to the platform. That matters to me more than any feature list.</p>
|
||||
<div class="cs-quote">
|
||||
<p>"Matrix is a properly decentralised protocol. Your chat history isn't locked to M8Chat the way it's locked to WhatsApp or Slack. That's the design, not a marketing claim."</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<img src="../assets/images/port-m8chat.png" alt="M8Chat secure communications platform" style="width:100%;border-radius:var(--r-xl);box-shadow:var(--shadow-lg);" loading="lazy">
|
||||
<div class="cs-stack" style="margin-top:20px;">
|
||||
<span class="cs-stack-tag">Matrix Protocol</span>
|
||||
<span class="cs-stack-tag">Jitsi Video Conferencing</span>
|
||||
<span class="cs-stack-tag">Flutter (custom client)</span>
|
||||
<span class="cs-stack-tag">Docker</span>
|
||||
<span class="cs-stack-tag">Australian VPS</span>
|
||||
<span class="cs-stack-tag">E2E Encryption</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- SERVER ARCHITECTURE -->
|
||||
<section class="section section--alt" aria-labelledby="servers-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Infrastructure</p>
|
||||
<h2 id="servers-heading">What runs where</h2>
|
||||
<p style="max-width:640px;color:var(--grey-600);font-size:17px;line-height:1.7;margin-bottom:0;">Three separate servers. Each one doing one thing. Chat and video on dedicated VPS instances keeps them from competing for resources, and it means a Jitsi call dropping doesn't take the chat server with it.</p>
|
||||
|
||||
<div class="cs-server-grid">
|
||||
<div class="cs-server-card">
|
||||
<h5>Matrix homeserver</h5>
|
||||
<div class="cs-server-domain">chat.m8chat.au</div>
|
||||
<p>My Matrix homeserver handles all protocol operations: room management, message storage, federation with the broader Matrix network, and push notifications. Containerised, with a solid database backend. This is the core of the platform.</p>
|
||||
</div>
|
||||
<div class="cs-server-card">
|
||||
<h5>Video conferencing</h5>
|
||||
<div class="cs-server-domain">conf.m8chat.au</div>
|
||||
<p>A full video conferencing stack on a dedicated VPS, with media bridging, conference management, and session recording. Separate from the chat server, so a heavy video call doesn't affect message delivery.</p>
|
||||
</div>
|
||||
<div class="cs-server-card">
|
||||
<h5>Landing page + app</h5>
|
||||
<div class="cs-server-domain">m8chat.au · app.m8chat.au</div>
|
||||
<p>The WordPress landing page and the Flutter PWA run on the Brisbane shared server alongside the rest of the HELP4BIS portfolio. The app connects to the Matrix homeserver via the standard Matrix client API.</p>
|
||||
</div>
|
||||
<div class="cs-server-card">
|
||||
<h5>app2.m8chat.au</h5>
|
||||
<div class="cs-server-domain">app2.m8chat.au</div>
|
||||
<p>A staging and alternate deployment of the Flutter app. I use it for testing new builds before they go to the main app subdomain, and it doubles as a fallback endpoint during major app updates.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FLUTTER APP -->
|
||||
<section class="section" aria-labelledby="app-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Mobile App</p>
|
||||
<h2 id="app-heading">The Flutter app</h2>
|
||||
<div class="cs-two-col">
|
||||
<div>
|
||||
<p>The M8Chat app is my own Flutter Matrix client. I build it specifically for this platform, and it has grown with every release since. I control the full codebase: branding, features, release schedule, and what data the app collects (which is nothing beyond what the Matrix protocol requires).</p>
|
||||
<p>The app is available three ways: as a Flutter PWA at <code>app.m8chat.au</code> (works in any modern browser, and you can add it to the home screen on Android and iOS), as a direct APK download for Android (sideload, no Google Play required), and via the Google Play store.</p>
|
||||
<p>Core features: text messaging, file sharing, voice messages, end to end encrypted rooms, communities, and video calls that launch with one tap. Video calls open in my conferencing infrastructure without leaving the app.</p>
|
||||
</div>
|
||||
<div>
|
||||
<div class="cs-feature-card" style="margin-bottom:16px;">
|
||||
<div class="cs-feature-icon">📱</div>
|
||||
<h4>Three deployment targets</h4>
|
||||
<p>PWA at app.m8chat.au, APK sideload, and Google Play. Users pick the delivery method that suits their situation. Enterprise users who can't install from the Play Store can use the APK or the browser app.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card" style="margin-bottom:16px;">
|
||||
<div class="cs-feature-icon">🔗</div>
|
||||
<h4>Jitsi integration</h4>
|
||||
<p>One tap from a Matrix room starts a video call at conf.m8chat.au. The conference runs on private infrastructure. There's no Zoom account required and no third party call relay involved.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🔄</div>
|
||||
<h4>Full control of the codebase</h4>
|
||||
<p>I own the app code. New features get added when they make sense for the users, not on someone else's roadmap. Security patches go on quickly because there's no external upstream to wait on.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- MATRIX PROTOCOL -->
|
||||
<section class="section section--alt" aria-labelledby="matrix-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Why Matrix</p>
|
||||
<h2 id="matrix-heading">The protocol choice</h2>
|
||||
<div class="cs-two-col">
|
||||
<div>
|
||||
<p>Matrix is an open communication protocol, not a product. The spec is publicly documented, multiple open server implementations exist, and any Matrix client can connect to any Matrix server. There's no vendor lock in at the protocol level.</p>
|
||||
<p>Federation means M8Chat users can communicate with users on any other Matrix server in the world (matrix.org, a company's self hosted instance, a government Matrix deployment) without those users needing an M8Chat account. It works the same way email does: you don't need a Gmail account to email someone at Gmail.</p>
|
||||
<p>End to end encryption is available for private rooms and direct messages. Keys are stored on the user's devices. The server operator, and that includes me, can't read encrypted messages. That's the whole point.</p>
|
||||
</div>
|
||||
<div>
|
||||
<div class="cs-feature-grid" style="margin-top:0;grid-template-columns:1fr;">
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🌐</div>
|
||||
<h4>Federation with the Matrix network</h4>
|
||||
<p>M8Chat users can join rooms on other Matrix servers, communicate with users on matrix.org, and take part in the broader decentralised network. This isn't a walled garden.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🔑</div>
|
||||
<h4>E2E encryption</h4>
|
||||
<p>Private rooms and direct messages support end to end encryption using the Olm and Megolm cryptographic protocols. Messages are encrypted on the sender's device and decrypted on the receiver's. The server stores ciphertext, not plaintext.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cs-honest" style="margin-top:var(--sp-5);">
|
||||
<div class="cs-honest-label">Honest note: operational complexity</div>
|
||||
<p>Running a Matrix Homeserver is not trivial. The server is resource hungry, federation can create unexpected load from large public rooms, and the database grows faster than most people expect because Matrix stores the full event graph of every room. I monitor the server load, prune old data on a schedule, and I've had to tune the configuration several times since the initial deployment. It's more like running a mail server than running a WordPress site. Anyone considering self hosted Matrix should factor in that operational overhead, not just the initial setup cost.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- TECH STACK -->
|
||||
<section class="section" aria-labelledby="stack-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Technical Details</p>
|
||||
<h2 id="stack-heading">Full stack</h2>
|
||||
<div class="cs-two-col">
|
||||
<div>
|
||||
<h4 style="font-size:15px;margin-bottom:12px;color:var(--ink);">Chat infrastructure (chat.m8chat.au)</h4>
|
||||
<div class="cs-stack" style="margin-top:0;">
|
||||
<span class="cs-stack-tag">Matrix homeserver</span>
|
||||
<span class="cs-stack-tag">Containerised stack</span>
|
||||
<span class="cs-stack-tag">Nginx reverse proxy</span>
|
||||
<span class="cs-stack-tag">Let's Encrypt SSL</span>
|
||||
<span class="cs-stack-tag">Media relay</span>
|
||||
</div>
|
||||
<h4 style="font-size:15px;margin-bottom:12px;margin-top:24px;color:var(--ink);">Video conferencing (conf.m8chat.au)</h4>
|
||||
<div class="cs-stack" style="margin-top:0;">
|
||||
<span class="cs-stack-tag">Jitsi conferencing stack</span>
|
||||
<span class="cs-stack-tag">Media bridge</span>
|
||||
<span class="cs-stack-tag">Session recording</span>
|
||||
<span class="cs-stack-tag">Containerised stack</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4 style="font-size:15px;margin-bottom:12px;color:var(--ink);">Mobile app</h4>
|
||||
<div class="cs-stack" style="margin-top:0;">
|
||||
<span class="cs-stack-tag">Flutter 3.x (custom client)</span>
|
||||
<span class="cs-stack-tag">Dart</span>
|
||||
<span class="cs-stack-tag">Service Worker PWA</span>
|
||||
<span class="cs-stack-tag">Android APK</span>
|
||||
<span class="cs-stack-tag">Google Play</span>
|
||||
</div>
|
||||
<h4 style="font-size:15px;margin-bottom:12px;margin-top:24px;color:var(--ink);">Web + landing</h4>
|
||||
<div class="cs-stack" style="margin-top:0;">
|
||||
<span class="cs-stack-tag">WordPress (m8chat.au)</span>
|
||||
<span class="cs-stack-tag">Flutter PWA (app.m8chat.au)</span>
|
||||
<span class="cs-stack-tag">DirectAdmin, brisbane01</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- USE CASES -->
|
||||
<section class="section section--alt" aria-labelledby="use-cases-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Who Is It For</p>
|
||||
<h2 id="use-cases-heading">When self hosted messaging makes sense</h2>
|
||||
<p style="max-width:640px;color:var(--grey-600);font-size:17px;line-height:1.7;margin-bottom:0;">This isn't for everyone. Most small businesses don't need to self host their communications. But for some situations the data sovereignty argument is real.</p>
|
||||
|
||||
<div class="cs-feature-grid">
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🏥</div>
|
||||
<h4>Health practitioners</h4>
|
||||
<p>GPs, psychologists and allied health workers who send patient information via messaging and want that data to stay in Australia on infrastructure they control, rather than on US servers under US law.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">⚖️</div>
|
||||
<h4>Legal and financial services</h4>
|
||||
<p>Firms with client confidentiality obligations who need to show where communications are stored and under whose jurisdiction. Australian hosted messaging with documented retention policies.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🏛️</div>
|
||||
<h4>Community organisations</h4>
|
||||
<p>Councils, volunteer emergency services, community groups who want member communications on infrastructure they control rather than dependent on Facebook Groups or WhatsApp staying free and functional.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🏢</div>
|
||||
<h4>Small businesses leaving Slack</h4>
|
||||
<p>Teams who have outgrown free Slack tiers and want a permanent self hosted alternative. The Slack pricing cliff at the free tier limit makes Matrix a cost effective option for teams of five to thirty people.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🔬</div>
|
||||
<h4>Research and academic</h4>
|
||||
<p>Research groups handling sensitive data, unpublished material, or material subject to research ethics approvals who need a documented chain of custody for communications.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">👥</div>
|
||||
<h4>M8Chat direct community use</h4>
|
||||
<p>M8Chat runs as a community service for individuals and small groups who simply want a free, private, Australian alternative to WhatsApp or Telegram. No surveillance capitalism, no ads, no algorithm deciding what you see.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- CTA -->
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<div class="cs-cta">
|
||||
<h2>Want your own self-hosted Matrix instance?</h2>
|
||||
<p>I can deploy, configure and maintain a Matrix homeserver for your organisation on Australian infrastructure. I handle the operational complexity. You get the sovereignty.</p>
|
||||
<div class="cs-hero-actions" style="justify-content:center;">
|
||||
<a href="https://m8chat.au" target="_blank" rel="noopener" class="btn btn-primary btn-lg">Try M8Chat free</a>
|
||||
<a href="../contact.html" class="btn btn-secondary btn-lg">Ask about private deployment</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-top:var(--sp-8);text-align:center;">
|
||||
<a href="../index.html#portfolio" style="font-size:14px;color:var(--grey-400);">← Back to all work</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FOOTER -->
|
||||
<footer class="footer" aria-label="Site footer">
|
||||
<div class="container">
|
||||
<div class="footer__grid">
|
||||
<div class="footer__brand">
|
||||
<img src="../assets/images/logo-cropped.jpg" alt="HELP4BIS" width="140" height="38">
|
||||
<p>Managed WordPress hosting and maintenance for Australian small businesses. Brisbane based, personal service, WordPress specialist.</p>
|
||||
<p style="margin-top:8px; font-size:12px; color:rgba(255,255,255,.25);">Dutch Digital Dynamics Pty Ltd · ABN 86 081 237 087</p>
|
||||
</div>
|
||||
<div class="footer__col">
|
||||
<h4>Services</h4>
|
||||
<ul class="footer__links">
|
||||
<li><a href="../managed-wordpress.html">Tailored Website Management</a></li>
|
||||
<li><a href="../care-plans.html">WP Care Plans</a></li>
|
||||
<li><a href="../sos-fix.html">WP SOS Fix</a></li>
|
||||
<li><a href="../ai-integration.html">AI Integration</a></li>
|
||||
<li><a href="../plugin-development.html">Plugin Development</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer__col">
|
||||
<h4>Our Work</h4>
|
||||
<ul class="footer__links">
|
||||
<li><a href="dayboro-au.html">Dayboro.au</a></li>
|
||||
<li><a href="gardenbuddy-au.html">GardenBuddy.au</a></li>
|
||||
<li><a href="tawnytrails.html">Tawny Trails</a></li>
|
||||
<li><a href="rds-ink.html">Running Duck Studio</a></li>
|
||||
<li><a href="localbuddy-au.html">LocalBuddy</a></li>
|
||||
<li><a href="m8chat-au.html">M8Chat</a></li>
|
||||
<li><a href="nightcap-nm.html">Nightcap Natural Medicine</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer__col">
|
||||
<h4>Contact</h4>
|
||||
<ul class="footer__links">
|
||||
<li><a href="mailto:project@help4bis.com">project@help4bis.com</a></li>
|
||||
<li><a href="../contact.html">Submit a Brief</a></li>
|
||||
<li><a href="../sos-fix.html">Emergency Fix</a></li>
|
||||
</ul>
|
||||
<p style="margin-top:16px; font-size:12px; color:rgba(255,255,255,.3);">Brisbane, Queensland<br>Response within 24 business hours</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer__bottom">
|
||||
<span>© 2026 HELP4BIS, a trading name of Dutch Digital Dynamics Pty Ltd · ABN 86 081 237 087</span>
|
||||
<span><a href="../privacy.html">Privacy</a> · <a href="../terms.html">Terms</a></span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<button id="back-to-top" aria-label="Back to top">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="18 15 12 9 6 15"/></svg>
|
||||
</button>
|
||||
|
||||
<script src="../assets/js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,450 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- Version: 1.2.0 | Created: 2026-05-05 | Updated: 2026-08-16 -->
|
||||
<html lang="en-AU">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Nightcap Natural Medicine Case Study | HELP4BIS</title>
|
||||
<meta name="description" content="How I built and manage nightcap-nm.au: a professional naturopathy practice website for Therese Latta in South East Queensland, on managed WordPress with Elementor Pro.">
|
||||
<meta name="author" content="HELP4BIS">
|
||||
<meta name="publisher" content="Dutch Digital Dynamics Pty Ltd">
|
||||
<meta name="language" content="en-AU">
|
||||
<meta name="geo.region" content="AU-QLD">
|
||||
<link rel="canonical" href="https://help4bis.com/work/nightcap-nm.html">
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content="https://help4bis.com/work/nightcap-nm.html">
|
||||
<meta property="og:site_name" content="HELP4BIS">
|
||||
<meta property="og:title" content="Nightcap Natural Medicine Case Study | HELP4BIS">
|
||||
<meta property="og:description" content="Managed WordPress for a naturopathy practice: professional, fast, reliable, and maintained by someone who actually looks after it.">
|
||||
<meta property="og:image" content="https://help4bis.com/assets/images/port-nightcap.png">
|
||||
<meta property="og:locale" content="en_AU">
|
||||
<link rel="icon" type="image/jpeg" href="../assets/images/logo-favicon.jpg"> <link rel="stylesheet" href="../assets/css/style.css">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"@id": "https://help4bis.com/work/nightcap-nm.html#webpage",
|
||||
"url": "https://help4bis.com/work/nightcap-nm.html",
|
||||
"name": "Nightcap Natural Medicine Case Study, HELP4BIS",
|
||||
"description": "Managed WordPress site for Nightcap Natural Medicine, a naturopathy practice in South East Queensland.",
|
||||
"isPartOf": {"@id": "https://help4bis.com/#website"},
|
||||
"breadcrumb": {
|
||||
"@type": "BreadcrumbList",
|
||||
"itemListElement": [
|
||||
{"@type": "ListItem", "position": 1, "name": "Home", "item": "https://help4bis.com/"},
|
||||
{"@type": "ListItem", "position": 2, "name": "Our Work", "item": "https://help4bis.com/#portfolio"},
|
||||
{"@type": "ListItem", "position": 3, "name": "Nightcap Natural Medicine", "item": "https://help4bis.com/work/nightcap-nm.html"}
|
||||
]
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.cs-hero {
|
||||
background: linear-gradient(160deg, var(--ink) 0%, var(--ink-mid) 60%, #0e1a1a 100%);
|
||||
padding: var(--sp-16) 0 var(--sp-12);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.cs-hero::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -30%;
|
||||
right: -15%;
|
||||
width: 60%;
|
||||
height: 200%;
|
||||
background: radial-gradient(circle, rgba(20,184,166,.06) 0%, transparent 65%);
|
||||
pointer-events: none;
|
||||
}
|
||||
.cs-breadcrumb {
|
||||
font-size: 13px;
|
||||
color: rgba(255,255,255,.45);
|
||||
margin-bottom: var(--sp-5);
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
}
|
||||
.cs-breadcrumb a { color: rgba(255,255,255,.45); }
|
||||
.cs-breadcrumb a:hover { color: var(--white); }
|
||||
.cs-breadcrumb span { color: rgba(255,255,255,.25); }
|
||||
.cs-hero h1 { color: var(--white); max-width: 820px; margin-bottom: var(--sp-4); }
|
||||
.cs-hero-sub {
|
||||
font-size: clamp(16px, 2vw, 20px);
|
||||
color: rgba(255,255,255,.65);
|
||||
max-width: 680px; line-height: 1.65; margin-bottom: var(--sp-6);
|
||||
}
|
||||
.cs-hero-actions { display: flex; gap: 12px; flex-wrap: wrap; }
|
||||
.btn-teal {
|
||||
background: linear-gradient(135deg, #14b8a6, #0d9488);
|
||||
color: var(--white); border-color: transparent;
|
||||
box-shadow: 0 4px 14px rgba(20,184,166,.30);
|
||||
}
|
||||
.btn-teal:hover {
|
||||
background: linear-gradient(135deg, #0d9488, #0f766e);
|
||||
color: var(--white); transform: translateY(-2px);
|
||||
}
|
||||
.cs-kpis {
|
||||
display: grid; grid-template-columns: repeat(2, 1fr);
|
||||
gap: 16px; margin-top: var(--sp-8); padding-top: var(--sp-8);
|
||||
border-top: 1px solid rgba(255,255,255,.08);
|
||||
}
|
||||
@media (min-width: 640px) { .cs-kpis { grid-template-columns: repeat(4, 1fr); } }
|
||||
.cs-kpi { text-align: center; }
|
||||
.cs-kpi-value {
|
||||
font-family: var(--font-head); font-size: clamp(32px, 4vw, 52px);
|
||||
font-weight: 900; color: #14b8a6; line-height: 1; letter-spacing: -0.04em;
|
||||
}
|
||||
.cs-kpi-label {
|
||||
font-size: 12px; font-weight: 600; text-transform: uppercase;
|
||||
letter-spacing: .12em; color: rgba(255,255,255,.45); margin-top: 6px;
|
||||
}
|
||||
.cs-feature-grid {
|
||||
display: grid; grid-template-columns: 1fr; gap: 24px; margin-top: var(--sp-6);
|
||||
}
|
||||
@media (min-width: 640px) { .cs-feature-grid { grid-template-columns: repeat(2, 1fr); } }
|
||||
@media (min-width: 900px) { .cs-feature-grid { grid-template-columns: repeat(3, 1fr); } }
|
||||
.cs-feature-card {
|
||||
background: var(--white); border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-lg); padding: 24px; box-shadow: var(--shadow-card);
|
||||
}
|
||||
.cs-feature-card h4 { font-size: 15px; margin-bottom: 8px; color: var(--ink); }
|
||||
.cs-feature-card p { font-size: 14px; color: var(--grey-600); line-height: 1.6; margin: 0; }
|
||||
.cs-feature-icon {
|
||||
width: 36px; height: 36px; background: var(--grey-50); border-radius: var(--r-md);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
margin-bottom: 14px; font-size: 18px;
|
||||
}
|
||||
.cs-page-list {
|
||||
margin: 0; padding: 0; list-style: none;
|
||||
display: grid; grid-template-columns: 1fr; gap: 8px; margin-top: var(--sp-5);
|
||||
}
|
||||
@media (min-width: 640px) { .cs-page-list { grid-template-columns: repeat(2, 1fr); } }
|
||||
@media (min-width: 900px) { .cs-page-list { grid-template-columns: repeat(3, 1fr); } }
|
||||
.cs-page-item {
|
||||
background: var(--white); border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-md); padding: 14px 18px; box-shadow: var(--shadow-sm);
|
||||
font-size: 14px; font-weight: 500; color: var(--ink);
|
||||
}
|
||||
.cs-page-item span { display: block; font-size: 13px; color: var(--grey-600); font-weight: 400; margin-top: 3px; }
|
||||
.cs-stack { display: flex; flex-wrap: wrap; gap: 8px; margin-top: var(--sp-4); }
|
||||
.cs-stack-tag {
|
||||
background: var(--grey-50); border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-full); padding: 6px 14px; font-size: 13px; font-weight: 500; color: var(--grey-600);
|
||||
}
|
||||
.cs-divider { height: 1px; background: var(--grey-100); margin: var(--sp-8) 0; }
|
||||
.cs-two-col {
|
||||
display: grid; grid-template-columns: 1fr; gap: var(--sp-8); align-items: start;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.cs-two-col { grid-template-columns: 1fr 1fr; }
|
||||
.cs-two-col--wide { grid-template-columns: 3fr 2fr; }
|
||||
}
|
||||
.cs-quote {
|
||||
border-left: 3px solid #14b8a6;
|
||||
padding: var(--sp-4) var(--sp-5); background: rgba(20,184,166,.04);
|
||||
border-radius: 0 var(--r-md) var(--r-md) 0; margin: var(--sp-5) 0;
|
||||
}
|
||||
.cs-quote p { font-size: 17px; line-height: 1.7; color: var(--grey-800); font-style: italic; margin: 0; }
|
||||
.cs-honest {
|
||||
background: var(--grey-50); border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-lg); padding: var(--sp-4) var(--sp-5); margin: var(--sp-5) 0;
|
||||
}
|
||||
.cs-honest-label {
|
||||
font-size: 11px; font-weight: 700; text-transform: uppercase;
|
||||
letter-spacing: .12em; color: var(--grey-400); margin-bottom: 8px;
|
||||
}
|
||||
.cs-honest p { font-size: 14px; color: var(--grey-600); line-height: 1.65; margin: 0; }
|
||||
.cs-cta {
|
||||
background: linear-gradient(135deg, var(--ink-mid), var(--ink));
|
||||
border-radius: var(--r-2xl); padding: var(--sp-10) var(--sp-8); text-align: center;
|
||||
}
|
||||
.cs-cta h2 { color: var(--white); margin-bottom: var(--sp-4); }
|
||||
.cs-cta p { color: rgba(255,255,255,.65); max-width: 560px; margin: 0 auto var(--sp-6); font-size: 17px; line-height: 1.7; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- NAV -->
|
||||
<nav class="nav" role="navigation" aria-label="Main navigation">
|
||||
<div class="nav__inner">
|
||||
<a class="nav__logo" href="../index.html" aria-label="HELP4BIS home">
|
||||
<img src="../assets/images/logo-cropped.jpg" alt="HELP4BIS" width="140" height="38">
|
||||
</a>
|
||||
<ul class="nav__links" id="nav-links" role="list">
|
||||
<li class="nav__dropdown">
|
||||
<button class="nav__trigger" aria-haspopup="true" aria-expanded="false">Services <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg></button>
|
||||
<ul class="nav__dropdown-menu" role="menu">
|
||||
<li class="nav__menu-group">WordPress</li>
|
||||
<li><a href="../managed-wordpress.html" role="menuitem">Tailored Website Management</a></li>
|
||||
<li><a href="../care-plans.html" role="menuitem">WP Care Plans <span class="menu-price">from $49/mo</span></a></li>
|
||||
<li><a href="../sos-fix.html" role="menuitem">WP SOS Fix <span class="menu-price">$97 flat</span></a></li>
|
||||
<li><a href="../ai-integration.html" role="menuitem">AI Integration</a></li>
|
||||
<li><a href="../plugin-development.html" role="menuitem">Custom Plugin Development</a></li> </ul>
|
||||
</li>
|
||||
<li><a href="../about.html">About</a></li>
|
||||
<li><a href="../index.html#portfolio">Our Work</a></li>
|
||||
<li><a href="../index.html#pricing">Pricing</a></li>
|
||||
<li><a href="../blog/index.html">Blog</a></li>
|
||||
<li><a href="../your-first-week-with-ai.html">AI Guide</a></li>
|
||||
<li><a href="../contact.html">Contact</a></li>
|
||||
<li class="nav__cta-mobile" aria-hidden="true">
|
||||
<a href="../contact.html" class="btn btn-primary">Get Started</a>
|
||||
<a href="../sos-fix.html" class="btn btn-secondary">SOS Fix, $97</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="nav__cta">
|
||||
<a href="../sos-fix.html" class="btn btn-secondary btn-sm">SOS Fix, $97</a>
|
||||
<a href="../contact.html" class="btn btn-primary btn-sm">Get Started</a>
|
||||
</div>
|
||||
<button class="nav__burger" id="nav-burger" aria-label="Open menu" aria-expanded="false" aria-controls="nav-links">
|
||||
<span></span><span></span><span></span>
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- HERO -->
|
||||
<section class="cs-hero" aria-labelledby="cs-heading">
|
||||
<div class="container">
|
||||
<div class="cs-breadcrumb">
|
||||
<a href="../index.html">Home</a>
|
||||
<span>›</span>
|
||||
<a href="../index.html#portfolio">Our Work</a>
|
||||
<span>›</span>
|
||||
<span style="color:rgba(255,255,255,.7);">Nightcap Natural Medicine</span>
|
||||
</div>
|
||||
<p class="eyebrow" style="color:rgba(20,184,166,.9);">Case Study: Health Practice Website</p>
|
||||
<h1 id="cs-heading">Nightcap Natural Medicine.<br>A practice website<br>that does its job.</h1>
|
||||
<p class="cs-hero-sub">A professional naturopathy website I built for Therese Latta in South East Queensland. Clean, fast, properly maintained, and set up so patients understand what Therese does and how to book.</p>
|
||||
<div class="cs-hero-actions">
|
||||
<a href="https://nightcap-nm.au" target="_blank" rel="noopener" class="btn btn-teal">Visit nightcap-nm.au →</a>
|
||||
<a href="../managed-wordpress.html" class="btn btn-secondary">See Managed WordPress</a>
|
||||
</div>
|
||||
<div class="cs-kpis">
|
||||
<div class="cs-kpi">
|
||||
<div class="cs-kpi-value">WP</div>
|
||||
<div class="cs-kpi-label">Platform</div>
|
||||
</div>
|
||||
<div class="cs-kpi">
|
||||
<div class="cs-kpi-value">7</div>
|
||||
<div class="cs-kpi-label">Core Pages</div>
|
||||
</div>
|
||||
<div class="cs-kpi">
|
||||
<div class="cs-kpi-value">12</div>
|
||||
<div class="cs-kpi-label">Services Listed</div>
|
||||
</div>
|
||||
<div class="cs-kpi">
|
||||
<div class="cs-kpi-value">QLD</div>
|
||||
<div class="cs-kpi-label">Location</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- OVERVIEW -->
|
||||
<section class="section" aria-labelledby="overview-heading">
|
||||
<div class="container">
|
||||
<div class="cs-two-col cs-two-col--wide">
|
||||
<div>
|
||||
<p class="eyebrow">Overview</p>
|
||||
<h2 id="overview-heading">What it actually is</h2>
|
||||
<p class="large">Therese Latta is a naturopath. Her patients come from the Nightcap Range area and further afield across South East Queensland. They need to understand what naturopathy is, what conditions Therese works with, and how to get in touch. That's what the website does.</p>
|
||||
<p>This isn't a complex build, and I'm happy to say so. No custom plugins, no app, no membership system. It's a well built, properly maintained WordPress site with Elementor Pro, hosted on the same Brisbane server as the rest of my portfolio. What makes it work is the content and the maintenance. Therese knows her field; the website communicates it clearly.</p>
|
||||
<p>The value of managed hosting for a solo health practitioner isn't the technology, it's the removal of the maintenance burden. Therese doesn't want to spend her Sundays checking whether WordPress updated correctly and whether a plugin conflict broke the contact form. I handle that, whilst she gets on with her clinical work.</p>
|
||||
<div class="cs-quote">
|
||||
<p>"A solo practice has one person doing everything: clinical work, administration, marketing, and website maintenance. The website is the one thing she shouldn't have to think about."</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<img src="../assets/images/port-nightcap.png" alt="Nightcap Natural Medicine website" style="width:100%;border-radius:var(--r-xl);box-shadow:var(--shadow-lg);" loading="lazy">
|
||||
<div class="cs-stack" style="margin-top:20px;">
|
||||
<span class="cs-stack-tag">WordPress</span>
|
||||
<span class="cs-stack-tag">Elementor Pro</span>
|
||||
<span class="cs-stack-tag">Managed Hosting</span>
|
||||
<span class="cs-stack-tag">Brisbane Server</span>
|
||||
<span class="cs-stack-tag">Let's Encrypt SSL</span>
|
||||
<span class="cs-stack-tag">Daily Backups</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- PAGES -->
|
||||
<section class="section section--alt" aria-labelledby="pages-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Site Structure</p>
|
||||
<h2 id="pages-heading">What the site covers</h2>
|
||||
<p style="max-width:640px;color:var(--grey-600);font-size:17px;line-height:1.7;margin-bottom:0;">Seven core pages, each one answering a specific question a prospective patient asks before booking. Nothing extra.</p>
|
||||
|
||||
<ul class="cs-page-list">
|
||||
<li class="cs-page-item">Home<span>Introduction, trust signals, and a clear path to booking.</span></li>
|
||||
<li class="cs-page-item">About Therese<span>Qualifications, philosophy, and why she became a naturopath.</span></li>
|
||||
<li class="cs-page-item">6 Principles of Naturopathy<span>Explains the foundational principles of naturopathic practice for patients who are new to it.</span></li>
|
||||
<li class="cs-page-item">Services<span>12 health areas Therese works with: digestive health, hormonal support, stress management, and more.</span></li>
|
||||
<li class="cs-page-item">Blog<span>Health and wellbeing articles written by Therese. Updated as she has time; no artificial publishing schedule.</span></li>
|
||||
<li class="cs-page-item">Useful Links<span>Curated external resources Therese recommends to patients.</span></li>
|
||||
<li class="cs-page-item">Contact<span>Inquiry form and booking information.</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- WHAT MANAGED ACTUALLY MEANS -->
|
||||
<section class="section" aria-labelledby="managed-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">What the Management Covers</p>
|
||||
<h2 id="managed-heading">What "managed" actually means here</h2>
|
||||
<p style="max-width:640px;color:var(--grey-600);font-size:17px;line-height:1.7;margin-bottom:0;">For a site like this (no online shop, no complex integrations, no custom plugins) managed hosting is mostly about prevention and response. You don't notice it when it works.</p>
|
||||
|
||||
<div class="cs-feature-grid" style="margin-top:var(--sp-6);">
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🛡️</div>
|
||||
<h4>Daily backups</h4>
|
||||
<p>Offsite backups run every 24 hours. If something goes wrong (a plugin update breaks a page, the server has a bad day) there's always a clean restore point within 24 hours of the current state.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🔄</div>
|
||||
<h4>Plugin and core updates</h4>
|
||||
<p>WordPress core, Elementor Pro, and all installed plugins are tested and updated regularly. When a security patch comes out, it goes in. When an update breaks something, I fix it before Therese notices.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🔒</div>
|
||||
<h4>SSL and security</h4>
|
||||
<p>Let's Encrypt SSL renews automatically. Login hardening, file permission checks, and malware scanning run as scheduled tasks. No extra plugin subscriptions, no extra cost.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">⚡</div>
|
||||
<h4>Performance</h4>
|
||||
<p>The site runs on the Brisbane server with PHP 8.4. Page caching means the site serves fast on shared infrastructure without needing a dedicated server for a site at this traffic level.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">✏️</div>
|
||||
<h4>Content edits</h4>
|
||||
<p>When Therese adds a new service, updates her bio, or wants to change the contact information, she emails through the brief and it gets done within 24 hours. No Elementor training required.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">📧</div>
|
||||
<h4>Professional email</h4>
|
||||
<p>Business email on the nightcap-nm.au domain is included. I've configured SPF, DKIM, and DMARC properly so Therese's emails don't end up in spam folders.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- HONEST NOTE -->
|
||||
<section class="section section--alt" aria-labelledby="honest-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Straight Talking</p>
|
||||
<h2 id="honest-heading">What this is and what it is not</h2>
|
||||
<div class="cs-two-col">
|
||||
<div>
|
||||
<p>Nightcap Natural Medicine is the kind of site most web agencies would undersell themselves building. It isn't complex, it doesn't have impressive technical features, and it wouldn't win awards at a digital agency portfolio review. I'm fine with that.</p>
|
||||
<p>What it is: a well built, properly maintained website that works reliably for a solo health practitioner who has better things to do than manage a website. Therese's job is looking after patients. The website's job is being there when someone searches for a naturopath in the area, whilst presenting Therese's practice professionally.</p>
|
||||
<p>That's what I built. And it costs less per month than two tanks of petrol.</p>
|
||||
</div>
|
||||
<div>
|
||||
<div class="cs-honest">
|
||||
<div class="cs-honest-label">On bookings integration</div>
|
||||
<p>Nightcap-nm.au currently uses a contact form rather than an online booking system. Online booking tools for health practitioners (Halaxy, Power Diary, Cliniko) vary a lot in how they embed and whether they're worth the extra monthly cost for a sole practitioner. If Therese decides to add one, I'll do the integration; it's straightforward. For now the contact form works and adds no external dependency.</p>
|
||||
</div>
|
||||
<div class="cs-honest" style="margin-top:var(--sp-4);">
|
||||
<div class="cs-honest-label">AHPRA compliance</div>
|
||||
<p>Naturopaths in Australia operate under specific AHPRA advertising standards. Health claims, testimonials, and before and after content require care. I review the site when content changes to keep it compliant. I flag anything that looks borderline; Therese makes the final call as the registered practitioner.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- TECH STACK -->
|
||||
<section class="section" aria-labelledby="stack-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Technical Details</p>
|
||||
<h2 id="stack-heading">The stack</h2>
|
||||
<p style="max-width:640px;color:var(--grey-600);font-size:17px;line-height:1.7;margin-bottom:var(--sp-5);">Nothing exotic. The point of a managed WordPress platform is that the stack is reliable and well understood, so I can solve problems fast when they come up.</p>
|
||||
<div class="cs-stack">
|
||||
<span class="cs-stack-tag">WordPress 6.x</span>
|
||||
<span class="cs-stack-tag">Elementor Pro</span>
|
||||
<span class="cs-stack-tag">PHP 8.4</span>
|
||||
<span class="cs-stack-tag">MariaDB</span>
|
||||
<span class="cs-stack-tag">Let's Encrypt SSL</span>
|
||||
<span class="cs-stack-tag">DirectAdmin, brisbane01</span>
|
||||
<span class="cs-stack-tag">Australian hosting</span>
|
||||
<span class="cs-stack-tag">Professional email</span>
|
||||
</div>
|
||||
<p style="margin-top:var(--sp-4);font-size:14px;color:var(--grey-600);">Hosting is on the same Brisbane server as the rest of my portfolio under DirectAdmin. Uptime is monitored via an external pinger; I get alerted before Therese notices any downtime.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- CTA -->
|
||||
<section class="section section--alt">
|
||||
<div class="container">
|
||||
<div class="cs-cta">
|
||||
<h2>A professional practice website, properly maintained.</h2>
|
||||
<p>If you run a solo health practice, a consulting business, or any professional service where the website needs to be reliable but you don't want to manage it yourself, this is exactly what Tailored Website Management is for.</p>
|
||||
<div class="cs-hero-actions" style="justify-content:center;">
|
||||
<a href="../managed-wordpress.html" class="btn btn-primary btn-lg">See what's included</a>
|
||||
<a href="../contact.html" class="btn btn-secondary btn-lg">Talk to us</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-top:var(--sp-8);text-align:center;">
|
||||
<a href="../index.html#portfolio" style="font-size:14px;color:var(--grey-400);">← Back to all work</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FOOTER -->
|
||||
<footer class="footer" aria-label="Site footer">
|
||||
<div class="container">
|
||||
<div class="footer__grid">
|
||||
<div class="footer__brand">
|
||||
<img src="../assets/images/logo-cropped.jpg" alt="HELP4BIS" width="140" height="38">
|
||||
<p>Managed WordPress hosting and maintenance for Australian small businesses. Brisbane based, personal service, WordPress specialist.</p>
|
||||
<p style="margin-top:8px; font-size:12px; color:rgba(255,255,255,.25);">Dutch Digital Dynamics Pty Ltd · ABN 86 081 237 087</p>
|
||||
</div>
|
||||
<div class="footer__col">
|
||||
<h4>Services</h4>
|
||||
<ul class="footer__links">
|
||||
<li><a href="../managed-wordpress.html">Tailored Website Management</a></li>
|
||||
<li><a href="../care-plans.html">WP Care Plans</a></li>
|
||||
<li><a href="../sos-fix.html">WP SOS Fix</a></li>
|
||||
<li><a href="../ai-integration.html">AI Integration</a></li>
|
||||
<li><a href="../plugin-development.html">Plugin Development</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer__col">
|
||||
<h4>Our Work</h4>
|
||||
<ul class="footer__links">
|
||||
<li><a href="dayboro-au.html">Dayboro.au</a></li>
|
||||
<li><a href="gardenbuddy-au.html">GardenBuddy.au</a></li>
|
||||
<li><a href="tawnytrails.html">Tawny Trails</a></li>
|
||||
<li><a href="rds-ink.html">Running Duck Studio</a></li>
|
||||
<li><a href="localbuddy-au.html">LocalBuddy</a></li>
|
||||
<li><a href="m8chat-au.html">M8Chat</a></li>
|
||||
<li><a href="nightcap-nm.html">Nightcap Natural Medicine</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer__col">
|
||||
<h4>Contact</h4>
|
||||
<ul class="footer__links">
|
||||
<li><a href="mailto:project@help4bis.com">project@help4bis.com</a></li>
|
||||
<li><a href="../contact.html">Submit a Brief</a></li>
|
||||
<li><a href="../sos-fix.html">Emergency Fix</a></li>
|
||||
</ul>
|
||||
<p style="margin-top:16px; font-size:12px; color:rgba(255,255,255,.3);">Brisbane, Queensland<br>Response within 24 business hours</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer__bottom">
|
||||
<span>© 2026 HELP4BIS, a trading name of Dutch Digital Dynamics Pty Ltd · ABN 86 081 237 087</span>
|
||||
<span><a href="../privacy.html">Privacy</a> · <a href="../terms.html">Terms</a></span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<button id="back-to-top" aria-label="Back to top">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="18 15 12 9 6 15"/></svg>
|
||||
</button>
|
||||
|
||||
<script src="../assets/js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,590 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- Version: 1.3.0 | Created: 2026-05-05 | Updated: 2026-08-16 -->
|
||||
<html lang="en-AU">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Running Duck Studio Case Study | HELP4BIS</title>
|
||||
<meta name="description" content="How I built rds.ink: a WooCommerce art gallery, a Flutter PWA with augmented reality painting previews, and a custom plugin suite for a working artist studio in Queensland.">
|
||||
<meta name="author" content="HELP4BIS">
|
||||
<meta name="publisher" content="Dutch Digital Dynamics Pty Ltd">
|
||||
<meta name="language" content="en-AU">
|
||||
<meta name="geo.region" content="AU-QLD">
|
||||
<link rel="canonical" href="https://help4bis.com/work/rds-ink.html">
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content="https://help4bis.com/work/rds-ink.html">
|
||||
<meta property="og:site_name" content="HELP4BIS">
|
||||
<meta property="og:title" content="Running Duck Studio Case Study | HELP4BIS">
|
||||
<meta property="og:description" content="WooCommerce art gallery, augmented reality painting previews via Flutter, and custom plugin development for a working Queensland artist studio.">
|
||||
<meta property="og:image" content="https://help4bis.com/assets/images/rds-managed-wordpress.jpg">
|
||||
<meta property="og:locale" content="en_AU">
|
||||
<link rel="icon" type="image/jpeg" href="../assets/images/logo-favicon.jpg"> <link rel="stylesheet" href="../assets/css/style.css">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"@id": "https://help4bis.com/work/rds-ink.html#webpage",
|
||||
"url": "https://help4bis.com/work/rds-ink.html",
|
||||
"name": "Running Duck Studio Case Study, HELP4BIS",
|
||||
"description": "WooCommerce art gallery with Flutter PWA, AR painting previews, and custom plugin suite for Running Duck Studio.",
|
||||
"isPartOf": {"@id": "https://help4bis.com/#website"},
|
||||
"breadcrumb": {
|
||||
"@type": "BreadcrumbList",
|
||||
"itemListElement": [
|
||||
{"@type": "ListItem", "position": 1, "name": "Home", "item": "https://help4bis.com/"},
|
||||
{"@type": "ListItem", "position": 2, "name": "Our Work", "item": "https://help4bis.com/#portfolio"},
|
||||
{"@type": "ListItem", "position": 3, "name": "Running Duck Studio", "item": "https://help4bis.com/work/rds-ink.html"}
|
||||
]
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.cs-hero {
|
||||
background: linear-gradient(160deg, var(--ink) 0%, var(--ink-mid) 60%, #1a1010 100%);
|
||||
padding: var(--sp-16) 0 var(--sp-12);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.cs-hero::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -30%;
|
||||
right: -15%;
|
||||
width: 60%;
|
||||
height: 200%;
|
||||
background: radial-gradient(circle, rgba(232,53,42,.05) 0%, transparent 65%);
|
||||
pointer-events: none;
|
||||
}
|
||||
.cs-breadcrumb {
|
||||
font-size: 13px;
|
||||
color: rgba(255,255,255,.45);
|
||||
margin-bottom: var(--sp-5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.cs-breadcrumb a { color: rgba(255,255,255,.45); }
|
||||
.cs-breadcrumb a:hover { color: var(--white); }
|
||||
.cs-breadcrumb span { color: rgba(255,255,255,.25); }
|
||||
.cs-hero h1 {
|
||||
color: var(--white);
|
||||
max-width: 820px;
|
||||
margin-bottom: var(--sp-4);
|
||||
}
|
||||
.cs-hero-sub {
|
||||
font-size: clamp(16px, 2vw, 20px);
|
||||
color: rgba(255,255,255,.65);
|
||||
max-width: 680px;
|
||||
line-height: 1.65;
|
||||
margin-bottom: var(--sp-6);
|
||||
}
|
||||
.cs-hero-actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.btn-red {
|
||||
background: linear-gradient(135deg, #E8352A, #b91c1c);
|
||||
color: var(--white);
|
||||
border-color: transparent;
|
||||
box-shadow: 0 4px 14px rgba(232,53,42,.30);
|
||||
}
|
||||
.btn-red:hover {
|
||||
background: linear-gradient(135deg, #b91c1c, #991b1b);
|
||||
color: var(--white);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
.cs-kpis {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 16px;
|
||||
margin-top: var(--sp-8);
|
||||
padding-top: var(--sp-8);
|
||||
border-top: 1px solid rgba(255,255,255,.08);
|
||||
}
|
||||
@media (min-width: 640px) { .cs-kpis { grid-template-columns: repeat(4, 1fr); } }
|
||||
.cs-kpi { text-align: center; }
|
||||
.cs-kpi-value {
|
||||
font-family: var(--font-head);
|
||||
font-size: clamp(32px, 4vw, 52px);
|
||||
font-weight: 900;
|
||||
color: #E8352A;
|
||||
line-height: 1;
|
||||
letter-spacing: -0.04em;
|
||||
}
|
||||
.cs-kpi-label {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .12em;
|
||||
color: rgba(255,255,255,.45);
|
||||
margin-top: 6px;
|
||||
}
|
||||
.cs-feature-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 24px;
|
||||
margin-top: var(--sp-6);
|
||||
}
|
||||
@media (min-width: 640px) { .cs-feature-grid { grid-template-columns: repeat(2, 1fr); } }
|
||||
@media (min-width: 900px) { .cs-feature-grid { grid-template-columns: repeat(3, 1fr); } }
|
||||
.cs-feature-card {
|
||||
background: var(--white);
|
||||
border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-lg);
|
||||
padding: 24px;
|
||||
box-shadow: var(--shadow-card);
|
||||
}
|
||||
.cs-feature-card h4 { font-size: 15px; margin-bottom: 8px; color: var(--ink); }
|
||||
.cs-feature-card p { font-size: 14px; color: var(--grey-600); line-height: 1.6; margin: 0; }
|
||||
.cs-feature-icon {
|
||||
width: 36px; height: 36px;
|
||||
background: var(--grey-50);
|
||||
border-radius: var(--r-md);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
margin-bottom: 14px; font-size: 18px;
|
||||
}
|
||||
.cs-plugin-list {
|
||||
margin: 0; padding: 0; list-style: none;
|
||||
display: grid; grid-template-columns: 1fr; gap: 12px;
|
||||
margin-top: var(--sp-5);
|
||||
}
|
||||
@media (min-width: 640px) { .cs-plugin-list { grid-template-columns: repeat(2, 1fr); } }
|
||||
.cs-plugin-item {
|
||||
background: var(--white);
|
||||
border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-md);
|
||||
padding: 16px 18px;
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
.cs-plugin-item strong {
|
||||
display: block; font-family: var(--font-head);
|
||||
font-size: 14px; font-weight: 700; color: var(--ink); margin-bottom: 4px;
|
||||
}
|
||||
.cs-plugin-item span { font-size: 13px; color: var(--grey-600); line-height: 1.5; }
|
||||
.cs-plugin-version {
|
||||
display: inline-block; font-size: 11px; font-weight: 700;
|
||||
text-transform: uppercase; letter-spacing: .08em;
|
||||
padding: 2px 8px; border-radius: var(--r-full); margin-top: 8px;
|
||||
background: rgba(232,53,42,.1); color: #b91c1c;
|
||||
}
|
||||
.cs-stack {
|
||||
display: flex; flex-wrap: wrap; gap: 8px; margin-top: var(--sp-4);
|
||||
}
|
||||
.cs-stack-tag {
|
||||
background: var(--grey-50); border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-full); padding: 6px 14px;
|
||||
font-size: 13px; font-weight: 500; color: var(--grey-600);
|
||||
}
|
||||
.cs-divider { height: 1px; background: var(--grey-100); margin: var(--sp-8) 0; }
|
||||
.cs-two-col {
|
||||
display: grid; grid-template-columns: 1fr; gap: var(--sp-8); align-items: start;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.cs-two-col { grid-template-columns: 1fr 1fr; }
|
||||
.cs-two-col--wide { grid-template-columns: 3fr 2fr; }
|
||||
}
|
||||
.cs-quote {
|
||||
border-left: 3px solid #E8352A;
|
||||
padding: var(--sp-4) var(--sp-5);
|
||||
background: rgba(232,53,42,.04);
|
||||
border-radius: 0 var(--r-md) var(--r-md) 0;
|
||||
margin: var(--sp-5) 0;
|
||||
}
|
||||
.cs-quote p { font-size: 17px; line-height: 1.7; color: var(--grey-800); font-style: italic; margin: 0; }
|
||||
.cs-honest {
|
||||
background: var(--grey-50); border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-lg); padding: var(--sp-4) var(--sp-5); margin: var(--sp-5) 0;
|
||||
}
|
||||
.cs-honest-label {
|
||||
font-size: 11px; font-weight: 700; text-transform: uppercase;
|
||||
letter-spacing: .12em; color: var(--grey-400); margin-bottom: 8px;
|
||||
}
|
||||
.cs-honest p { font-size: 14px; color: var(--grey-600); line-height: 1.65; margin: 0; }
|
||||
.cs-cta {
|
||||
background: linear-gradient(135deg, var(--ink-mid), var(--ink));
|
||||
border-radius: var(--r-2xl); padding: var(--sp-10) var(--sp-8); text-align: center;
|
||||
}
|
||||
.cs-cta h2 { color: var(--white); margin-bottom: var(--sp-4); }
|
||||
.cs-cta p { color: rgba(255,255,255,.65); max-width: 560px; margin: 0 auto var(--sp-6); font-size: 17px; line-height: 1.7; }
|
||||
.cs-ar-flow {
|
||||
display: grid; grid-template-columns: 1fr; gap: 16px; margin-top: var(--sp-5);
|
||||
}
|
||||
@media (min-width: 640px) { .cs-ar-flow { grid-template-columns: repeat(3, 1fr); } }
|
||||
.cs-ar-step {
|
||||
background: var(--white); border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-lg); padding: 20px; box-shadow: var(--shadow-sm);
|
||||
text-align: center;
|
||||
}
|
||||
.cs-ar-step-num {
|
||||
width: 36px; height: 36px; background: #E8352A; color: var(--white);
|
||||
border-radius: 50%; display: flex; align-items: center; justify-content: center;
|
||||
font-family: var(--font-head); font-weight: 800; font-size: 16px;
|
||||
margin: 0 auto 12px;
|
||||
}
|
||||
.cs-ar-step h5 { font-size: 14px; font-weight: 700; color: var(--ink); margin-bottom: 6px; }
|
||||
.cs-ar-step p { font-size: 13px; color: var(--grey-600); line-height: 1.55; margin: 0; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- NAV -->
|
||||
<nav class="nav" role="navigation" aria-label="Main navigation">
|
||||
<div class="nav__inner">
|
||||
<a class="nav__logo" href="../index.html" aria-label="HELP4BIS home">
|
||||
<img src="../assets/images/logo-cropped.jpg" alt="HELP4BIS" width="140" height="38">
|
||||
</a>
|
||||
<ul class="nav__links" id="nav-links" role="list">
|
||||
<li class="nav__dropdown">
|
||||
<button class="nav__trigger" aria-haspopup="true" aria-expanded="false">Services <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg></button>
|
||||
<ul class="nav__dropdown-menu" role="menu">
|
||||
<li class="nav__menu-group">WordPress</li>
|
||||
<li><a href="../managed-wordpress.html" role="menuitem">Tailored Website Management</a></li>
|
||||
<li><a href="../care-plans.html" role="menuitem">WP Care Plans <span class="menu-price">from $49/mo</span></a></li>
|
||||
<li><a href="../sos-fix.html" role="menuitem">WP SOS Fix <span class="menu-price">$97 flat</span></a></li>
|
||||
<li><a href="../ai-integration.html" role="menuitem">AI Integration</a></li>
|
||||
<li><a href="../plugin-development.html" role="menuitem">Custom Plugin Development</a></li> </ul>
|
||||
</li>
|
||||
<li><a href="../about.html">About</a></li>
|
||||
<li><a href="../index.html#portfolio">Our Work</a></li>
|
||||
<li><a href="../index.html#pricing">Pricing</a></li>
|
||||
<li><a href="../blog/index.html">Blog</a></li>
|
||||
<li><a href="../your-first-week-with-ai.html">AI Guide</a></li>
|
||||
<li><a href="../contact.html">Contact</a></li>
|
||||
<li class="nav__cta-mobile" aria-hidden="true">
|
||||
<a href="../contact.html" class="btn btn-primary">Get Started</a>
|
||||
<a href="../sos-fix.html" class="btn btn-secondary">SOS Fix, $97</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="nav__cta">
|
||||
<a href="../sos-fix.html" class="btn btn-secondary btn-sm">SOS Fix, $97</a>
|
||||
<a href="../contact.html" class="btn btn-primary btn-sm">Get Started</a>
|
||||
</div>
|
||||
<button class="nav__burger" id="nav-burger" aria-label="Open menu" aria-expanded="false" aria-controls="nav-links">
|
||||
<span></span><span></span><span></span>
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- HERO -->
|
||||
<section class="cs-hero" aria-labelledby="cs-heading">
|
||||
<div class="container">
|
||||
<div class="cs-breadcrumb">
|
||||
<a href="../index.html">Home</a>
|
||||
<span>›</span>
|
||||
<a href="../index.html#portfolio">Our Work</a>
|
||||
<span>›</span>
|
||||
<span style="color:rgba(255,255,255,.7);">Running Duck Studio</span>
|
||||
</div>
|
||||
<p class="eyebrow" style="color:rgba(232,53,42,.9);">Case Study: Art Gallery + App</p>
|
||||
<h1 id="cs-heading">Running Duck Studio.<br>Selling art online<br>is harder than it looks.</h1>
|
||||
<p class="cs-hero-sub">A WooCommerce art gallery with augmented reality painting previews, a Flutter app that shows the work in your space before you buy, and a custom plugin suite I built specifically for how a working artist studio actually sells.</p>
|
||||
<div class="cs-hero-actions">
|
||||
<a href="https://rds.ink" target="_blank" rel="noopener" class="btn btn-red">Visit rds.ink →</a>
|
||||
<a href="https://flutter.rds.ink" target="_blank" rel="noopener" class="btn btn-secondary">Open the app</a>
|
||||
</div>
|
||||
<div class="cs-kpis">
|
||||
<div class="cs-kpi">
|
||||
<div class="cs-kpi-value">WC</div>
|
||||
<div class="cs-kpi-label">Sales Platform</div>
|
||||
</div>
|
||||
<div class="cs-kpi">
|
||||
<div class="cs-kpi-value">5</div>
|
||||
<div class="cs-kpi-label">Custom Plugins</div>
|
||||
</div>
|
||||
<div class="cs-kpi">
|
||||
<div class="cs-kpi-value">AR</div>
|
||||
<div class="cs-kpi-label">In Room Previews</div>
|
||||
</div>
|
||||
<div class="cs-kpi">
|
||||
<div class="cs-kpi-value">8.4MB</div>
|
||||
<div class="cs-kpi-label">Flutter PWA</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- OVERVIEW -->
|
||||
<section class="section" aria-labelledby="overview-heading">
|
||||
<div class="container">
|
||||
<div class="cs-two-col cs-two-col--wide">
|
||||
<div>
|
||||
<p class="eyebrow">Overview</p>
|
||||
<h2 id="overview-heading">What it actually is</h2>
|
||||
<p class="large">Danielle runs a working art studio. She paints originals, prints limited editions, and sells through the website. Standard WooCommerce wasn't built for original artwork. There's no concept of a one of a kind piece that's gone when it sells, no way to mark something as SOLD with context rather than just deleting it, and no way to show the buyer what the painting looks like at life size on their wall before they commit.</p>
|
||||
<p>So I built what was missing. A custom plugin suite that handles the art gallery's specific needs: SOLD badge display with history tracking, a commission inquiry form, an artwork dimenions field, category filtering for the gallery view, and a Related Works shortcode. On top of that I built a Flutter progressive web app with augmented reality, where the buyer can point their phone camera at their wall and see the painting at real scale.</p>
|
||||
<p>The AR feature is the part I spend the most time explaining, but it sells the hardest when people actually try it. Danielle uploads a photo of the painting and a short video. The AR target gets compiled in the browser. The Flutter app opens a camera overlay and shows the work in the room.</p>
|
||||
<div class="cs-quote">
|
||||
<p>"Selling original art online has one central problem: people can't tell how big it is or whether it will work on their wall. The AR preview solves that directly."</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<img src="../assets/images/rds-managed-wordpress.jpg" alt="Running Duck Studio website" style="width:100%;border-radius:var(--r-xl);box-shadow:var(--shadow-lg);" loading="lazy">
|
||||
<div class="cs-stack" style="margin-top:20px;">
|
||||
<span class="cs-stack-tag">WordPress</span>
|
||||
<span class="cs-stack-tag">WooCommerce</span>
|
||||
<span class="cs-stack-tag">Flutter Web</span>
|
||||
<span class="cs-stack-tag">Augmented Reality</span>
|
||||
<span class="cs-stack-tag">Gelato Print-on-Demand</span>
|
||||
<span class="cs-stack-tag">Custom Plugins</span>
|
||||
<span class="cs-stack-tag">REST API</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- AR EXPERIENCE -->
|
||||
<section class="section section--alt" aria-labelledby="ar-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Signature Feature</p>
|
||||
<h2 id="ar-heading">How the AR preview works</h2>
|
||||
<p style="max-width:640px;color:var(--grey-600);font-size:17px;line-height:1.7;margin-bottom:0;">Danielle does the entire setup from the WordPress admin. No technical knowledge required after the initial build I did. The whole pipeline runs from her laptop.</p>
|
||||
|
||||
<div class="cs-ar-flow">
|
||||
<div class="cs-ar-step">
|
||||
<div class="cs-ar-step-num">1</div>
|
||||
<h5>Upload painting + video</h5>
|
||||
<p>Danielle uploads a straight photo of the painting and a short video of it hanging in the studio. Both go into the rds-ar-manager plugin.</p>
|
||||
</div>
|
||||
<div class="cs-ar-step">
|
||||
<div class="cs-ar-step-num">2</div>
|
||||
<h5>AR target compiles in the browser</h5>
|
||||
<p>The plugin compiles the AR target in the browser. No processing on my server, no external AR service subscription. The target image descriptor is stored with the product.</p>
|
||||
</div>
|
||||
<div class="cs-ar-step">
|
||||
<div class="cs-ar-step-num">3</div>
|
||||
<h5>Buyer opens Flutter app</h5>
|
||||
<p>The Flutter PWA at flutter.rds.ink reads the product data via REST API. The buyer taps "View in your space" and the app opens a camera overlay showing the painting at real scale on their wall.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cs-honest" style="margin-top:var(--sp-6);">
|
||||
<div class="cs-honest-label">Honest note</div>
|
||||
<p>The AR feature works well on mid range Android and current iOS. Older phones with limited camera APIs see a standard overlay without full spatial tracking. It's a real improvement for most buyers, not a universal replacement for visiting the studio. I document this clearly in the app.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- PLUGIN SUITE -->
|
||||
<section class="section" aria-labelledby="plugins-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Custom Development</p>
|
||||
<h2 id="plugins-heading">Five plugins, one purpose</h2>
|
||||
<p style="max-width:640px;color:var(--grey-600);font-size:17px;line-height:1.7;margin-bottom:0;">Standard WooCommerce treats every product the same. I wrote these plugins because original artwork isn't the same as a T shirt. Each one fills a specific gap in how the gallery actually works.</p>
|
||||
|
||||
<ul class="cs-plugin-list">
|
||||
<li class="cs-plugin-item">
|
||||
<strong>rds-core</strong>
|
||||
<span>Core gallery functionality: product display, pricing, SOLD badge with history, commission inquiry form, Similar Works shortcode, category filter bar, and artwork dimensions. The plugin that makes WooCommerce behave like an art gallery rather than a general shop.</span>
|
||||
</li>
|
||||
<li class="cs-plugin-item">
|
||||
<strong>rds-ar-manager</strong>
|
||||
<span>AR experience management. Danielle uploads painting image and video via a metabox on the product edit screen. The plugin handles AR target compilation and makes it available to the Flutter app.</span>
|
||||
</li>
|
||||
<li class="cs-plugin-item">
|
||||
<strong>rds-flutter-config</strong>
|
||||
<span>Controls the look, feel, and content of the Flutter PWA from WP admin. Theme colours, featured collections, and navigation structure can all be changed without redeploying the app.</span>
|
||||
</li>
|
||||
<li class="cs-plugin-item">
|
||||
<strong>rds-image-guard</strong>
|
||||
<span class="cs-plugin-version">Active</span>
|
||||
<span>Disables right click save and drag based image theft on all gallery pages. Doesn't prevent determined copying but removes casual right click downloads. Standard protection for selling original digital previews of artwork.</span>
|
||||
</li>
|
||||
<li class="cs-plugin-item">
|
||||
<strong>rds-seo-command</strong>
|
||||
<span class="cs-plugin-version">Active</span>
|
||||
<span>SEO tooling for the gallery: auto-generates meta descriptions from product data, builds structured data markup for individual artwork pages, and handles canonical URLs across the category and tag views.</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- PRINT ON DEMAND -->
|
||||
<section class="section section--alt" aria-labelledby="pod-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Commerce Layer</p>
|
||||
<h2 id="pod-heading">Originals plus print on demand</h2>
|
||||
<p style="max-width:640px;color:var(--grey-600);font-size:17px;line-height:1.7;margin-bottom:var(--sp-6);">Running Duck Studio sells two things: original paintings at original prices, and print reproductions via Gelato. Gelato handles fulfilment. They print and ship from the production facility closest to the buyer, and the WooCommerce integration I set up connects the two.</p>
|
||||
|
||||
<div class="cs-feature-grid" style="margin-top:0;">
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🎨</div>
|
||||
<h4>Original paintings</h4>
|
||||
<p>Each original is a single WooCommerce product with a custom SOLD state I built. When it sells, the product switches to SOLD, shows the sold price and date, and remains visible as portfolio history rather than disappearing from the site.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🖨️</div>
|
||||
<h4>Gelato print on demand</h4>
|
||||
<p>Limited edition prints are fulfilled by Gelato. The buyer places a WooCommerce order; Gelato picks it up automatically and handles printing, packaging, and shipping. No inventory, no fulfilment work on Danielle's end, and nothing manual for me either.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">📦</div>
|
||||
<h4>Commission inquiries</h4>
|
||||
<p>The commission form (part of rds-core) captures buyer requirements, preferred size, colour palette, and budget. It feeds into a structured email workflow rather than a generic contact form. Danielle gets everything she needs in one message.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cs-honest" style="margin-top:var(--sp-6);">
|
||||
<div class="cs-honest-label">Honest note: Gelato</div>
|
||||
<p>Gelato's WooCommerce API has specific requirements around product variant mapping that I had to document carefully. When Gelato updates their product catalogue, variant IDs can change and previously mapped products need relinking, so it is important keep the variant mapping current. It's not a set and forget integration. I handle those updates as part of the ongoing management relationship.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FLUTTER APP -->
|
||||
<section class="section" aria-labelledby="app-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Mobile Experience</p>
|
||||
<h2 id="app-heading">The Flutter app</h2>
|
||||
<div class="cs-two-col">
|
||||
<div>
|
||||
<p>The Flutter progressive web app I wrote at <strong>flutter.rds.ink</strong> is an 8.4 MB build that runs in the browser on any device. No app store download required. The buyer opens it from their phone browser or via a QR code on the gallery page.</p>
|
||||
<p>The app reads product data from the WordPress REST API on launch. Featured collections, theme colours, and the gallery structure all come from the rds-flutter-config plugin, so the app stays in sync with the website without being redeployed every time Danielle adds a new collection.</p>
|
||||
<p>Core screens: gallery browse by category, individual artwork detail with AR trigger, Danielle's story, commission inquiry form, and a direct link to the WooCommerce cart. I run the cart in a WebView pointed at the WordPress site so I don't duplicate the payment integration.</p>
|
||||
</div>
|
||||
<div>
|
||||
<div class="cs-feature-card" style="margin-bottom:16px;">
|
||||
<div class="cs-feature-icon">📱</div>
|
||||
<h4>PWA, no app store required</h4>
|
||||
<p>Works on Android and iOS via the browser. Users can add it to their home screen and it behaves like an installed app. The service worker caches the gallery for offline browsing.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card" style="margin-bottom:16px;">
|
||||
<div class="cs-feature-icon">🔗</div>
|
||||
<h4>Live data from WordPress</h4>
|
||||
<p>The app reads the product catalogue via REST API. New artwork appears in the app automatically when published in WordPress. I don't need to redeploy anything for content updates.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🛒</div>
|
||||
<h4>Cart via WebView</h4>
|
||||
<p>Purchases complete through the WooCommerce site inside a WebView. No duplicated payment integration, no Stripe keys managed in two places.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- TECH STACK -->
|
||||
<section class="section section--alt" aria-labelledby="stack-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Technical Details</p>
|
||||
<h2 id="stack-heading">Full stack</h2>
|
||||
<div class="cs-two-col">
|
||||
<div>
|
||||
<h4 style="font-size:15px;margin-bottom:12px;color:var(--ink);">Web platform</h4>
|
||||
<div class="cs-stack" style="margin-top:0;">
|
||||
<span class="cs-stack-tag">WordPress 6.x</span>
|
||||
<span class="cs-stack-tag">WooCommerce</span>
|
||||
<span class="cs-stack-tag">Elementor Pro</span>
|
||||
<span class="cs-stack-tag">rds-core</span>
|
||||
<span class="cs-stack-tag">rds-ar-manager</span>
|
||||
<span class="cs-stack-tag">rds-flutter-config</span>
|
||||
<span class="cs-stack-tag">rds-image-guard</span>
|
||||
<span class="cs-stack-tag">rds-seo-command</span>
|
||||
<span class="cs-stack-tag">Gelato integration</span>
|
||||
</div>
|
||||
<h4 style="font-size:15px;margin-bottom:12px;margin-top:24px;color:var(--ink);">Mobile app</h4>
|
||||
<div class="cs-stack" style="margin-top:0;">
|
||||
<span class="cs-stack-tag">Flutter 3.x</span>
|
||||
<span class="cs-stack-tag">Dart</span>
|
||||
<span class="cs-stack-tag">WebXR AR</span>
|
||||
<span class="cs-stack-tag">Service Worker PWA</span>
|
||||
<span class="cs-stack-tag">REST API consumer</span>
|
||||
<span class="cs-stack-tag">WebView cart</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4 style="font-size:15px;margin-bottom:12px;color:var(--ink);">Infrastructure</h4>
|
||||
<div class="cs-stack" style="margin-top:0;">
|
||||
<span class="cs-stack-tag">DirectAdmin, brisbane01</span>
|
||||
<span class="cs-stack-tag">PHP 8.4</span>
|
||||
<span class="cs-stack-tag">MariaDB</span>
|
||||
<span class="cs-stack-tag">Let's Encrypt SSL</span>
|
||||
<span class="cs-stack-tag">rds.ink (WooCommerce)</span>
|
||||
<span class="cs-stack-tag">flutter.rds.ink (Flutter PWA)</span>
|
||||
</div>
|
||||
<div class="cs-honest" style="margin-top:24px;">
|
||||
<div class="cs-honest-label">What this costs to run</div>
|
||||
<p>The platform runs on shared infrastructure on the same Brisbane server as the rest of my portfolio. Total hosting cost for rds.ink and the Flutter subdomain is included in the Tailored Website Management plan at $200/month. Gelato charges per print fulfilled; there's no monthly fee for their integration.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- CTA -->
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<div class="cs-cta">
|
||||
<h2>Want a WooCommerce store that actually fits your business?</h2>
|
||||
<p>Standard WooCommerce is a solid foundation. The question is whether it fits what you actually sell. If it doesn't, I build the parts that are missing.</p>
|
||||
<div class="cs-hero-actions" style="justify-content:center;">
|
||||
<a href="../contact.html" class="btn btn-primary btn-lg">Talk to us</a>
|
||||
<a href="../plugin-development.html" class="btn btn-secondary btn-lg">Custom plugin development</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-top:var(--sp-8);text-align:center;">
|
||||
<a href="../index.html#portfolio" style="font-size:14px;color:var(--grey-400);">← Back to all work</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FOOTER -->
|
||||
<footer class="footer" aria-label="Site footer">
|
||||
<div class="container">
|
||||
<div class="footer__grid">
|
||||
<div class="footer__brand">
|
||||
<img src="../assets/images/logo-cropped.jpg" alt="HELP4BIS" width="140" height="38">
|
||||
<p>Managed WordPress hosting and maintenance for Australian small businesses. Brisbane based, personal service, WordPress specialist.</p>
|
||||
<p style="margin-top:8px; font-size:12px; color:rgba(255,255,255,.25);">Dutch Digital Dynamics Pty Ltd · ABN 86 081 237 087</p>
|
||||
</div>
|
||||
<div class="footer__col">
|
||||
<h4>Services</h4>
|
||||
<ul class="footer__links">
|
||||
<li><a href="../managed-wordpress.html">Tailored Website Management</a></li>
|
||||
<li><a href="../care-plans.html">WP Care Plans</a></li>
|
||||
<li><a href="../sos-fix.html">WP SOS Fix</a></li>
|
||||
<li><a href="../ai-integration.html">AI Integration</a></li>
|
||||
<li><a href="../plugin-development.html">Plugin Development</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer__col">
|
||||
<h4>Our Work</h4>
|
||||
<ul class="footer__links">
|
||||
<li><a href="dayboro-au.html">Dayboro.au</a></li>
|
||||
<li><a href="gardenbuddy-au.html">GardenBuddy.au</a></li>
|
||||
<li><a href="tawnytrails.html">Tawny Trails</a></li>
|
||||
<li><a href="rds-ink.html">Running Duck Studio</a></li>
|
||||
<li><a href="localbuddy-au.html">LocalBuddy</a></li>
|
||||
<li><a href="m8chat-au.html">M8Chat</a></li>
|
||||
<li><a href="nightcap-nm.html">Nightcap Natural Medicine</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer__col">
|
||||
<h4>Contact</h4>
|
||||
<ul class="footer__links">
|
||||
<li><a href="mailto:project@help4bis.com">project@help4bis.com</a></li>
|
||||
<li><a href="../contact.html">Submit a Brief</a></li>
|
||||
<li><a href="../sos-fix.html">Emergency Fix</a></li>
|
||||
</ul>
|
||||
<p style="margin-top:16px; font-size:12px; color:rgba(255,255,255,.3);">Brisbane, Queensland<br>Response within 24 business hours</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer__bottom">
|
||||
<span>© 2026 HELP4BIS, a trading name of Dutch Digital Dynamics Pty Ltd · ABN 86 081 237 087</span>
|
||||
<span><a href="../privacy.html">Privacy</a> · <a href="../terms.html">Terms</a></span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<button id="back-to-top" aria-label="Back to top">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="18 15 12 9 6 15"/></svg>
|
||||
</button>
|
||||
|
||||
<script src="../assets/js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,539 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- Version: 1.2.0 | Created: 2026-05-05 | Updated: 2026-08-16 -->
|
||||
<html lang="en-AU">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Tawny Trails Case Study | HELP4BIS</title>
|
||||
<meta name="description" content="How Tawny Trails was built: 22 venues, 3 curated itineraries, a custom REST API, a Flutter PWA, and a membership platform for a rural arts and tourism trail in SE Queensland.">
|
||||
<meta name="author" content="HELP4BIS">
|
||||
<meta name="publisher" content="Dutch Digital Dynamics Pty Ltd">
|
||||
<meta name="language" content="en-AU">
|
||||
<meta name="geo.region" content="AU-QLD">
|
||||
<link rel="canonical" href="https://help4bis.com/work/tawnytrails.html">
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content="https://help4bis.com/work/tawnytrails.html">
|
||||
<meta property="og:site_name" content="HELP4BIS">
|
||||
<meta property="og:title" content="Tawny Trails Case Study | HELP4BIS">
|
||||
<meta property="og:description" content="22 venues, 3 itineraries, a custom Flutter PWA, and a WordPress REST API for a rural arts and tourism trail in the D'Aguilar Range, SE Queensland.">
|
||||
<meta property="og:image" content="https://help4bis.com/assets/images/tawny-trails.jpg">
|
||||
<meta property="og:locale" content="en_AU">
|
||||
<link rel="icon" type="image/jpeg" href="../assets/images/logo-favicon.jpg"> <link rel="stylesheet" href="../assets/css/style.css">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"@id": "https://help4bis.com/work/tawnytrails.html#webpage",
|
||||
"url": "https://help4bis.com/work/tawnytrails.html",
|
||||
"name": "Tawny Trails Case Study | HELP4BIS",
|
||||
"description": "A rural arts and tourism trail platform: 22 venues, 3 curated itineraries, a custom WordPress REST API, Flutter PWA, accessibility map, and PMPro membership, built for tawnytrails.com.",
|
||||
"isPartOf": {"@id": "https://help4bis.com/#website"},
|
||||
"breadcrumb": {
|
||||
"@type": "BreadcrumbList",
|
||||
"itemListElement": [
|
||||
{"@type": "ListItem", "position": 1, "name": "Home", "item": "https://help4bis.com/"},
|
||||
{"@type": "ListItem", "position": 2, "name": "Our Work", "item": "https://help4bis.com/#portfolio"},
|
||||
{"@type": "ListItem", "position": 3, "name": "Tawny Trails", "item": "https://help4bis.com/work/tawnytrails.html"}
|
||||
]
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.cs-hero {
|
||||
background: linear-gradient(160deg, var(--ink) 0%, #1a1a0d 50%, #1a2a10 100%);
|
||||
padding: var(--sp-16) 0 var(--sp-12);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.cs-hero::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -30%;
|
||||
right: -15%;
|
||||
width: 60%;
|
||||
height: 200%;
|
||||
background: radial-gradient(circle, rgba(245,158,11,.06) 0%, transparent 65%);
|
||||
pointer-events: none;
|
||||
}
|
||||
.cs-breadcrumb {
|
||||
font-size: 13px;
|
||||
color: rgba(255,255,255,.45);
|
||||
margin-bottom: var(--sp-5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.cs-breadcrumb a { color: rgba(255,255,255,.45); }
|
||||
.cs-breadcrumb a:hover { color: var(--white); }
|
||||
.cs-breadcrumb span { color: rgba(255,255,255,.25); }
|
||||
.cs-hero h1 { color: var(--white); max-width: 820px; margin-bottom: var(--sp-4); }
|
||||
.cs-hero-sub {
|
||||
font-size: clamp(16px, 2vw, 20px);
|
||||
color: rgba(255,255,255,.65);
|
||||
max-width: 680px;
|
||||
line-height: 1.65;
|
||||
margin-bottom: var(--sp-6);
|
||||
}
|
||||
.cs-hero-actions { display: flex; gap: 12px; flex-wrap: wrap; }
|
||||
.btn-amber {
|
||||
background: linear-gradient(135deg, var(--amber), #d97706);
|
||||
color: var(--ink);
|
||||
border-color: transparent;
|
||||
box-shadow: 0 4px 14px rgba(245,158,11,.30);
|
||||
}
|
||||
.btn-amber:hover {
|
||||
background: linear-gradient(135deg, #fbbf24, var(--amber));
|
||||
color: var(--ink);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
.cs-kpis {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 16px;
|
||||
margin-top: var(--sp-8);
|
||||
padding-top: var(--sp-8);
|
||||
border-top: 1px solid rgba(255,255,255,.08);
|
||||
}
|
||||
@media (min-width: 640px) { .cs-kpis { grid-template-columns: repeat(4, 1fr); } }
|
||||
.cs-kpi { text-align: center; }
|
||||
.cs-kpi-value {
|
||||
font-family: var(--font-head);
|
||||
font-size: clamp(32px, 4vw, 52px);
|
||||
font-weight: 900;
|
||||
color: var(--amber);
|
||||
line-height: 1;
|
||||
letter-spacing: -0.04em;
|
||||
}
|
||||
.cs-kpi-label {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .12em;
|
||||
color: rgba(255,255,255,.45);
|
||||
margin-top: 6px;
|
||||
}
|
||||
.cs-feature-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 24px;
|
||||
margin-top: var(--sp-6);
|
||||
}
|
||||
@media (min-width: 640px) { .cs-feature-grid { grid-template-columns: repeat(2, 1fr); } }
|
||||
@media (min-width: 900px) { .cs-feature-grid { grid-template-columns: repeat(3, 1fr); } }
|
||||
.cs-feature-card {
|
||||
background: var(--white);
|
||||
border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-lg);
|
||||
padding: 24px;
|
||||
box-shadow: var(--shadow-card);
|
||||
}
|
||||
.cs-feature-card h4 { font-size: 15px; margin-bottom: 8px; color: var(--ink); }
|
||||
.cs-feature-card p { font-size: 14px; color: var(--grey-600); line-height: 1.6; margin: 0; }
|
||||
.cs-feature-icon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
background: var(--grey-50);
|
||||
border-radius: var(--r-md);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 14px;
|
||||
font-size: 18px;
|
||||
}
|
||||
.cs-venue-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 10px;
|
||||
margin-top: var(--sp-5);
|
||||
}
|
||||
@media (min-width: 640px) { .cs-venue-grid { grid-template-columns: repeat(3, 1fr); } }
|
||||
@media (min-width: 900px) { .cs-venue-grid { grid-template-columns: repeat(4, 1fr); } }
|
||||
.cs-venue-chip {
|
||||
background: var(--grey-50);
|
||||
border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-md);
|
||||
padding: 10px 14px;
|
||||
font-size: 13px;
|
||||
color: var(--grey-800);
|
||||
font-weight: 500;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.cs-venue-chip span {
|
||||
display: block;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .08em;
|
||||
color: var(--amber);
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
.cs-stack { display: flex; flex-wrap: wrap; gap: 8px; margin-top: var(--sp-4); }
|
||||
.cs-stack-tag {
|
||||
background: var(--grey-50);
|
||||
border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-full);
|
||||
padding: 6px 14px;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--grey-600);
|
||||
}
|
||||
.cs-two-col { display: grid; grid-template-columns: 1fr; gap: var(--sp-8); align-items: start; }
|
||||
@media (min-width: 768px) { .cs-two-col { grid-template-columns: 1fr 1fr; } .cs-two-col--wide { grid-template-columns: 3fr 2fr; } }
|
||||
.cs-quote {
|
||||
border-left: 3px solid var(--amber);
|
||||
padding: var(--sp-4) var(--sp-5);
|
||||
background: rgba(245,158,11,.04);
|
||||
border-radius: 0 var(--r-md) var(--r-md) 0;
|
||||
margin: var(--sp-5) 0;
|
||||
}
|
||||
.cs-quote p { font-size: 17px; line-height: 1.7; color: var(--grey-800); font-style: italic; margin: 0; }
|
||||
.cs-honest {
|
||||
background: var(--grey-50);
|
||||
border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-lg);
|
||||
padding: var(--sp-4) var(--sp-5);
|
||||
margin: var(--sp-5) 0;
|
||||
}
|
||||
.cs-honest-label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .12em; color: var(--grey-400); margin-bottom: 8px; }
|
||||
.cs-honest p { font-size: 14px; color: var(--grey-600); line-height: 1.65; margin: 0; }
|
||||
.cs-divider { height: 1px; background: var(--grey-100); margin: var(--sp-8) 0; }
|
||||
.cs-cta {
|
||||
background: linear-gradient(135deg, var(--ink-mid), var(--ink));
|
||||
border-radius: var(--r-2xl);
|
||||
padding: var(--sp-10) var(--sp-8);
|
||||
text-align: center;
|
||||
}
|
||||
.cs-cta h2 { color: var(--white); margin-bottom: var(--sp-4); }
|
||||
.cs-cta p { color: rgba(255,255,255,.65); max-width: 560px; margin: 0 auto var(--sp-6); font-size: 17px; line-height: 1.7; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<nav class="nav" role="navigation" aria-label="Main navigation">
|
||||
<div class="nav__inner">
|
||||
<a class="nav__logo" href="../index.html" aria-label="HELP4BIS home">
|
||||
<img src="../assets/images/logo-cropped.jpg" alt="HELP4BIS" width="140" height="38">
|
||||
</a>
|
||||
<ul class="nav__links" id="nav-links" role="list">
|
||||
<li class="nav__dropdown">
|
||||
<button class="nav__trigger" aria-haspopup="true" aria-expanded="false">Services <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg></button>
|
||||
<ul class="nav__dropdown-menu" role="menu">
|
||||
<li class="nav__menu-group">WordPress</li>
|
||||
<li><a href="../managed-wordpress.html" role="menuitem">Tailored Website Management</a></li>
|
||||
<li><a href="../care-plans.html" role="menuitem">WP Care Plans <span class="menu-price">from $49/mo</span></a></li>
|
||||
<li><a href="../sos-fix.html" role="menuitem">WP SOS Fix <span class="menu-price">$97 flat</span></a></li>
|
||||
<li><a href="../ai-integration.html" role="menuitem">AI Integration</a></li>
|
||||
<li><a href="../plugin-development.html" role="menuitem">Custom Plugin Development</a></li> </ul>
|
||||
</li>
|
||||
<li><a href="../about.html">About</a></li>
|
||||
<li><a href="../index.html#portfolio">Our Work</a></li>
|
||||
<li><a href="../index.html#pricing">Pricing</a></li>
|
||||
<li><a href="../blog/index.html">Blog</a></li>
|
||||
<li><a href="../your-first-week-with-ai.html">AI Guide</a></li>
|
||||
<li><a href="../contact.html">Contact</a></li>
|
||||
<li class="nav__cta-mobile" aria-hidden="true">
|
||||
<a href="../contact.html" class="btn btn-primary">Get Started</a>
|
||||
<a href="../sos-fix.html" class="btn btn-secondary">SOS Fix, $97</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="nav__cta">
|
||||
<a href="../sos-fix.html" class="btn btn-secondary btn-sm">SOS Fix, $97</a>
|
||||
<a href="../contact.html" class="btn btn-primary btn-sm">Get Started</a>
|
||||
</div>
|
||||
<button class="nav__burger" id="nav-burger" aria-label="Open menu" aria-expanded="false" aria-controls="nav-links">
|
||||
<span></span><span></span><span></span>
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- HERO -->
|
||||
<section class="cs-hero" aria-labelledby="cs-heading">
|
||||
<div class="container">
|
||||
<div class="cs-breadcrumb">
|
||||
<a href="../index.html">Home</a><span>›</span>
|
||||
<a href="../index.html#portfolio">Our Work</a><span>›</span>
|
||||
<span style="color:rgba(255,255,255,.7);">Tawny Trails</span>
|
||||
</div>
|
||||
<p class="eyebrow" style="color:rgba(245,158,11,.9);">Case Study: Tourism & Arts Trail</p>
|
||||
<h1 id="cs-heading">Tawny Trails.<br>A rural arts trail<br>with a proper platform.</h1>
|
||||
<p class="cs-hero-sub">22 venues across the D'Aguilar Range and surrounds (art studios, sculpture gardens, horse riding, ceramics, accommodation, and bush walks) all connected through a REST API I built on WordPress, feeding a Flutter PWA and a curated itinerary system.</p>
|
||||
<div class="cs-hero-actions">
|
||||
<a href="https://tawnytrails.com" target="_blank" rel="noopener" class="btn btn-amber">Visit tawnytrails.com →</a>
|
||||
<a href="https://flutter.tawnytrails.com" target="_blank" rel="noopener" class="btn btn-secondary">Open the app</a>
|
||||
</div>
|
||||
<div class="cs-kpis">
|
||||
<div class="cs-kpi"><div class="cs-kpi-value">22</div><div class="cs-kpi-label">Venues on the Trail</div></div>
|
||||
<div class="cs-kpi"><div class="cs-kpi-value">3</div><div class="cs-kpi-label">Curated Itineraries</div></div>
|
||||
<div class="cs-kpi"><div class="cs-kpi-value">1.7</div><div class="cs-kpi-label">Custom Plugins Built</div></div>
|
||||
<div class="cs-kpi"><div class="cs-kpi-value">6.9 MB</div><div class="cs-kpi-label">Flutter PWA</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- OVERVIEW -->
|
||||
<section class="section" aria-labelledby="overview-heading">
|
||||
<div class="container">
|
||||
<div class="cs-two-col cs-two-col--wide">
|
||||
<div>
|
||||
<p class="eyebrow">Overview</p>
|
||||
<h2 id="overview-heading">What it is</h2>
|
||||
<p class="large">Tawny Trails is a self guided arts and tourism trail covering the D'Aguilar Range, the Dayboro valley, and the surrounding hinterland northwest of Brisbane. 22 venues, from galleries, studios and sculpture parks to horse trail operators, accommodation, and bush walking areas, connected through a single platform that visitors can use on a phone without needing to install anything.</p>
|
||||
<p>The brief I got wasn't just a directory with a map. It needed themed itineraries so a day visitor from Brisbane could plan a route without spending twenty minutes reading. It needed opening hours that were current, and with 22 venues it is important keep those current without me touching them. It needed to work as a Flutter app on the phone, not a website that looks like it was designed for a desktop. And it needed a membership layer so venue operators could manage their own listings.</p>
|
||||
<div class="cs-quote">
|
||||
<p>"The gap between 'a WordPress site with a map plugin' and 'an actual trail platform' is a custom REST API, a Flutter app, and a decent itinerary system. That's what I built."</p>
|
||||
</div>
|
||||
<div class="cs-stack">
|
||||
<span class="cs-stack-tag">WordPress</span>
|
||||
<span class="cs-stack-tag">Flutter Web</span>
|
||||
<span class="cs-stack-tag">Custom REST API</span>
|
||||
<span class="cs-stack-tag">ACF</span>
|
||||
<span class="cs-stack-tag">PMPro Membership</span>
|
||||
<span class="cs-stack-tag">Elementor Pro</span>
|
||||
<span class="cs-stack-tag">Custom CPT</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<img src="../assets/images/tawny-trails.jpg" alt="Tawny Trails arts and tourism trail" style="width:100%;border-radius:var(--r-xl);box-shadow:var(--shadow-lg);" loading="lazy">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- VENUES -->
|
||||
<section class="section section--alt" aria-labelledby="venues-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">The Trail</p>
|
||||
<h2 id="venues-heading">22 venues, all on one platform</h2>
|
||||
<p style="max-width:640px;color:var(--grey-600);font-size:17px;line-height:1.7;">Each venue is a custom post type (<code>tt_venue</code>) with ACF fields for opening hours, GPS coordinates, category, accessibility notes, and contact details. The Flutter app reads all of it from my REST API. There's no hardcoded content in the app itself.</p>
|
||||
|
||||
<div class="cs-venue-grid">
|
||||
<div class="cs-venue-chip"><span>Art Studio</span>Kylie Farrelly Art</div>
|
||||
<div class="cs-venue-chip"><span>Art Studio</span>Ann Russell Art</div>
|
||||
<div class="cs-venue-chip"><span>Art Studio</span>Tatiana Afonina</div>
|
||||
<div class="cs-venue-chip"><span>Art Studio</span>Christa's Art & Gilding</div>
|
||||
<div class="cs-venue-chip"><span>Gallery</span>The Artist Cove</div>
|
||||
<div class="cs-venue-chip"><span>Gallery</span>Dayboro Art Gallery</div>
|
||||
<div class="cs-venue-chip"><span>Gallery</span>Running Duck Studio</div>
|
||||
<div class="cs-venue-chip"><span>Ceramics</span>Woodside Ceramics</div>
|
||||
<div class="cs-venue-chip"><span>Sculpture</span>Phoenix Sculpture Garden</div>
|
||||
<div class="cs-venue-chip"><span>Heritage</span>Silverwood Butter Factory</div>
|
||||
<div class="cs-venue-chip"><span>Workshop</span>The Gantry</div>
|
||||
<div class="cs-venue-chip"><span>Restaurant</span>Rendezvous</div>
|
||||
<div class="cs-venue-chip"><span>Horse Riding</span>Slickers Horse Riding</div>
|
||||
<div class="cs-venue-chip"><span>Bush Walk</span>Maiala Rain Forest</div>
|
||||
<div class="cs-venue-chip"><span>Lookout</span>Dahmongah Lookout Park</div>
|
||||
<div class="cs-venue-chip"><span>Accommodation</span>Maiala Park Lodge</div>
|
||||
<div class="cs-venue-chip"><span>Accommodation</span>Laceys Creek Homestead</div>
|
||||
<div class="cs-venue-chip"><span>Accommodation</span>Cascade Cottage</div>
|
||||
<div class="cs-venue-chip"><span>Accommodation</span>Walkabout Retreat</div>
|
||||
<div class="cs-venue-chip"><span>Accommodation</span>Mercure Clear Mountain</div>
|
||||
<div class="cs-venue-chip"><span>Accommodation</span>Ocean View Estates</div>
|
||||
<div class="cs-venue-chip"><span>Accommodation</span>Oceanview Estates</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- REST API + FLUTTER -->
|
||||
<section class="section" aria-labelledby="api-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Technical Architecture</p>
|
||||
<h2 id="api-heading">A custom API feeding the Flutter app</h2>
|
||||
<p style="max-width:640px;color:var(--grey-600);font-size:17px;line-height:1.7;">The TawnyTrails API plugin (tt-api) is the engine of the whole platform. I wrote it to expose venue data, itineraries, and opening hours logic via a custom REST API. The Flutter app has no hardcoded content. Everything it displays is fetched live from WordPress.</p>
|
||||
|
||||
<div class="cs-feature-grid">
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🔌</div>
|
||||
<h4>TawnyTrails API Plugin (tt-api)</h4>
|
||||
<p>A WordPress plugin I built specifically for this project. It handles venue data storage, custom field management, the REST API layer, and data caching to keep the Flutter app fast without hitting the database on every request.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">📱</div>
|
||||
<h4>Flutter PWA at flutter.tawnytrails.com</h4>
|
||||
<p>A Flutter Web app compiled to JavaScript and deployed as static files. 6.9 MB, runs on Android, iPhone (via Safari Add to Home Screen), and desktop. Reads venues and itineraries from the REST API on load. No App Store account required for iOS users.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🗺️</div>
|
||||
<h4>Live venue map</h4>
|
||||
<p>Every venue has GPS coordinates stored as ACF fields. The Flutter app renders an interactive map from the API data. Visitors can see all 22 stops, filter by category, and get directions from their current location.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🕐</div>
|
||||
<h4>Opening hours logic</h4>
|
||||
<p>Each venue's opening hours are stored as structured data, not free text. The API calculates whether a venue is open right now based on the current time and day. The app shows "Open now" or "Closed, opens at X" without the Flutter app doing any time calculations itself.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🧭</div>
|
||||
<h4>Three curated itineraries</h4>
|
||||
<p>A full day on Tawny Trails, a Brisbane scenic drive and arts highlight, and a creative country walk through Dayboro township. Each itinerary is a custom post type with ordered venue stops, timing estimates, and driving directions between them.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">♿</div>
|
||||
<h4>Accessibility map</h4>
|
||||
<p>A separate view of the trail focused on accessibility, with notes per venue. Flat access, parking proximity, and facility notes for each venue, stored as ACF fields and exposed through the same REST API.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cs-honest">
|
||||
<div class="cs-honest-label">Why not a standard map plugin</div>
|
||||
<p>Standard WordPress map plugins (Google Maps, MapPress, etc.) embed a JavaScript widget on a page. They work fine for a simple business locator. They can't serve a Flutter app, they can't calculate opening hours state, and they can't handle itinerary ordering or accessibility data in a structured way. When a Flutter app needs to consume venue data you need a real REST API, not a plugin that renders HTML. I checked the plugin route first and it doesn't get you there.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- MEMBERSHIP + CONTENT -->
|
||||
<section class="section section--alt" aria-labelledby="membership-heading">
|
||||
<div class="container">
|
||||
<div class="cs-two-col">
|
||||
<div>
|
||||
<p class="eyebrow">Platform Features</p>
|
||||
<h2 id="membership-heading">Membership and content management</h2>
|
||||
<p class="large">Venue operators log in and manage their own listings. Visitors can purchase trail memberships for extended features. The whole thing runs on PMPro, the same membership engine I use across the other platforms we manage.</p>
|
||||
<p>My tt-pmpro-extensions plugin bridges PMPro and the access rules specific to TawnyTrails: which membership level gets access to which itinerary, gift certificate handling, and member discount logic for venue bookings.</p>
|
||||
|
||||
<div class="cs-feature-grid" style="grid-template-columns:1fr 1fr;margin-top:var(--sp-5);">
|
||||
<div class="cs-feature-card">
|
||||
<h4>Tour operator portal</h4>
|
||||
<p>A dedicated page for tour operators listing group experience options, with booking inquiry forms linked to each operator's contact.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<h4>Trail blog</h4>
|
||||
<p>Regular editorial content about venues, seasonal events, new openings, and trail news. Indexed and surfaced in search.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<h4>Gift certificates</h4>
|
||||
<p>Trail membership gift certificates configured in PMPro. Recipients redeem them at checkout for trail access.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<h4>Feature flags</h4>
|
||||
<p>A feature flag system in tt-api lets us enable or disable features for specific membership levels without a code deploy. It's controlled from the WordPress admin.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="background:var(--ink-mid);border-radius:var(--r-xl);padding:var(--sp-6);color:var(--white);">
|
||||
<p class="eyebrow" style="color:rgba(245,158,11,.9);">Custom plugins built</p>
|
||||
<ul style="list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:20px;">
|
||||
<li style="border-bottom:1px solid rgba(255,255,255,.07);padding-bottom:18px;">
|
||||
<strong style="color:var(--white);font-size:14px;display:block;margin-bottom:6px;">tt-api</strong>
|
||||
<p style="font-size:13px;color:rgba(255,255,255,.55);margin:0;line-height:1.5;">Core REST API. Registers CPTs, meta fields, routes, CORS, caching. The Flutter app's entire data layer.</p>
|
||||
</li>
|
||||
<li style="border-bottom:1px solid rgba(255,255,255,.07);padding-bottom:18px;">
|
||||
<strong style="color:var(--white);font-size:14px;display:block;margin-bottom:6px;">tt-pmpro-extensions</strong>
|
||||
<p style="font-size:13px;color:rgba(255,255,255,.55);margin:0;line-height:1.5;">Membership access rules specific to TawnyTrails: itinerary gating, gift certificates, operator dashboard access.</p>
|
||||
</li>
|
||||
<li style="border-bottom:1px solid rgba(255,255,255,.07);padding-bottom:18px;">
|
||||
<strong style="color:var(--white);font-size:14px;display:block;margin-bottom:6px;">tt-event-shortcodes</strong>
|
||||
<p style="font-size:13px;color:rgba(255,255,255,.55);margin:0;line-height:1.5;">Shortcodes for embedding trail events, seasonal listings, and venue availability in standard WordPress pages.</p>
|
||||
</li>
|
||||
<li>
|
||||
<strong style="color:var(--white);font-size:14px;display:block;margin-bottom:6px;">tt-site-tweaks</strong>
|
||||
<p style="font-size:13px;color:rgba(255,255,255,.55);margin:0;line-height:1.5;">Performance and display adjustments specific to the trail theme: header overrides, lazy load tuning, schema output.</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- TECH STACK -->
|
||||
<section class="section" aria-labelledby="stack-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Under the Hood</p>
|
||||
<h2 id="stack-heading">Full technology stack</h2>
|
||||
<div class="cs-stack" style="margin-top:var(--sp-4);">
|
||||
<span class="cs-stack-tag">WordPress 6.x</span>
|
||||
<span class="cs-stack-tag">PHP 8.4</span>
|
||||
<span class="cs-stack-tag">MariaDB</span>
|
||||
<span class="cs-stack-tag">Flutter 3.x</span>
|
||||
<span class="cs-stack-tag">Dart</span>
|
||||
<span class="cs-stack-tag">Flutter Web</span>
|
||||
<span class="cs-stack-tag">REST API (custom)</span>
|
||||
<span class="cs-stack-tag">Advanced Custom Fields</span>
|
||||
<span class="cs-stack-tag">PMPro Membership</span>
|
||||
<span class="cs-stack-tag">Elementor Pro</span>
|
||||
<span class="cs-stack-tag">Custom CPT (tt_venue)</span>
|
||||
<span class="cs-stack-tag">Custom CPT (tt_itinerary)</span>
|
||||
<span class="cs-stack-tag">Redis cache</span>
|
||||
<span class="cs-stack-tag">CleanTalk spam protection</span>
|
||||
<span class="cs-stack-tag">DirectAdmin</span>
|
||||
</div>
|
||||
|
||||
<div class="cs-divider"></div>
|
||||
|
||||
<div class="cs-honest">
|
||||
<div class="cs-honest-label">What is still being built</div>
|
||||
<p>The platform is live and functional. A few pages aren't published yet. Some shortcode driven content sections are still being completed, and the Gift Certificate flow is in draft. The REST API, Flutter app, venue directory, itineraries, and membership system are all fully operational. I'd call this a normal state for a growing platform, not abandoned and not broken.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- CTA -->
|
||||
<section class="section section--dark" aria-labelledby="cta-heading">
|
||||
<div class="container">
|
||||
<div class="cs-cta">
|
||||
<p class="eyebrow" style="color:rgba(245,158,11,.9);justify-content:center;">What I can build for you</p>
|
||||
<h2 id="cta-heading">Got a trail, a precinct, or a cluster of venues?</h2>
|
||||
<p>I can build the same architecture (custom REST API, Flutter PWA, itinerary system, opening hours logic, accessibility map, and membership layer) for any arts trail, tourism precinct, or cluster of venues. The venue count doesn't matter. The complexity doesn't matter. The pattern is proven, because it's already running.</p>
|
||||
<div style="display:flex;gap:12px;justify-content:center;flex-wrap:wrap;">
|
||||
<a href="../contact.html" class="btn btn-primary">Talk to us about your project</a>
|
||||
<a href="../index.html#portfolio" class="btn btn-secondary">See more of our work</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="footer" aria-label="Site footer">
|
||||
<div class="container">
|
||||
<div class="footer__grid">
|
||||
<div class="footer__brand">
|
||||
<img src="../assets/images/logo-cropped.jpg" alt="HELP4BIS" width="140" height="38">
|
||||
<p>Managed WordPress hosting and maintenance for Australian small businesses. Brisbane based, personal service, WordPress specialist.</p>
|
||||
<p style="font-size:13px; color:rgba(255,255,255,.4);">Dutch Digital Dynamics Pty Ltd · ABN 86 081 237 087</p>
|
||||
</div>
|
||||
<div class="footer__col">
|
||||
<h4>Services</h4>
|
||||
<ul class="footer__links">
|
||||
<li><a href="../managed-wordpress.html">Tailored Website Management</a></li>
|
||||
<li><a href="../care-plans.html">WP Care Plans</a></li>
|
||||
<li><a href="../sos-fix.html">WP SOS Fix</a></li>
|
||||
<li><a href="../ai-integration.html">AI Integration</a></li>
|
||||
<li><a href="../plugin-development.html">Plugin Development</a></li> </ul>
|
||||
</div>
|
||||
<div class="footer__col">
|
||||
<h4>Company</h4>
|
||||
<ul class="footer__links">
|
||||
<li><a href="../about.html">About Us</a></li>
|
||||
<li><a href="../index.html#portfolio">Our Work</a></li>
|
||||
<li><a href="../index.html#testimonials">Client Feedback</a></li>
|
||||
<li><a href="../blog/index.html">Blog</a></li>
|
||||
<li><a href="../contact.html">Contact</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer__col">
|
||||
<h4>Contact</h4>
|
||||
<ul class="footer__links">
|
||||
<li><a href="mailto:project@help4bis.com">project@help4bis.com</a></li>
|
||||
<li><a href="../contact.html">Submit a Brief</a></li>
|
||||
<li><a href="../sos-fix.html">Emergency Fix</a></li>
|
||||
</ul>
|
||||
<p style="margin-top:1rem; font-size:13px; color:rgba(255,255,255,.4);">Brisbane, Queensland<br>Response within 24 business hours</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer__bottom">
|
||||
<span>© 2026 HELP4BIS, a trading name of Dutch Digital Dynamics Pty Ltd · ABN 86 081 237 087</span>
|
||||
<span><a href="../privacy.html">Privacy Policy</a> · <a href="../terms.html">Terms</a></span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<button id="back-to-top" aria-label="Back to top" style="position:fixed;bottom:24px;right:24px;width:44px;height:44px;background:var(--red);border:none;border-radius:50%;color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .3s ease;box-shadow:var(--shadow-md);">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="18 15 12 9 6 15"/></svg>
|
||||
</button>
|
||||
<script src="../assets/js/main.js"></script>
|
||||
<script src="../analytics/tracker.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user