how i created custom logic

Custom Logic 🌐

Welcome to Custom Logic, a sleek, single-file web platform designed to deliver a full SaaS experience without the usual bloat. This project is proof that you can create a modern, responsive, and highly interactive website all in one source file, while leveraging the power of the cloud.

---

🚀 Project Overview

Custom Logic is the web presence for the company custom-logic.co.za. It handles:

  • User feedback collection
  • Service orders and requests
  • Clean, single-page interface
  • SEO-ready architecture, fully crawlable

All of this is delivered in a single HTML/JS/CSS source file, powered by the serverless cloud.

---

💻 Tech Stack

This project isn’t your average SPA. Here’s what makes it tick:

| Layer | Technology | Notes | |-------|------------|-------| | Hosting | Cloudflare Pages | Single-page static hosting with lightning-fast global distribution. | | Serverless | Cloudflare Workers | Handles dynamic actions like feedback forms, service order submissions, and virtual endpoints (/sitemap.xml, /robots.txt). | | Database | GitHub as a database | All persistent storage is managed via GitHub commits + API. This means no traditional DB required — just raw CSV stored in repos. | | Frontend | Vanilla JS + HTML + CSS | Everything lives in a single source file. Modular enough to maintain sanity, yet compact for lightning performance. | | SEO | Pre-rendered meta tags + JSON-LD | Single-page doesn’t mean invisible to search engines. SEO-ready structured data, Open Graph tags, and dynamic sitemap are served via Workers. |

---

🔧 Architecture

Here’s the brain behind the simplicity:

1. Single-File SPA - All HTML, CSS, and JS live in one file. - Interactive sections are powered by vanilla JS. - SEO sections pre-rendered to ensure crawlability.

2. Serverless Dynamic Layer - Cloudflare Workers intercept requests for dynamic endpoints: - /sitemap.xml → serves automatically generated sitemap. - /robots.txt → search engine instructions. - /feedback and /orders → handles multi-form submissions. - Each submission is validated, processed, and stored in CSV files on GitHub.

3. GitHub as a Backend - Workers push data to a dedicated repository branch. - Each submission creates a commit, providing version history and audit trail. - No database server required.

4. SEO & Metadata - Structured data (JSON-LD) embedded directly in the SPA. - Open Graph meta tags included in for social previews. - Cloudflare Workers allow dynamic injection of per-section </code> and <code><meta></code> if needed.</p> <p>---</p> <h2>⚡ Features</h2> <ul><li><strong>Single-source SPA</strong> – lightning fast, minimal dependencies. </li> <li><strong>Serverless feedback & order system</strong> – no backend servers. </li> <li><strong>Multi-form handling</strong> – different solutions are routed to separate CSV files (<code>unicenta-pos</code>, <code>funeral-manager</code>, <code>jobfinders</code>, <code>custom-development</code>). </li> <li><strong>CORS-secured</strong> – allows requests only from approved domains. </li> <li><strong>SEO ready</strong> – sitemap, robots.txt, structured data, and pre-rendered content. </li> <li><strong>Cloud-native</strong> – leverages Cloudflare Pages + Workers for full-stack functionality. </li> <li><strong>GitHub as a “database”</strong> – versioned, persistent, and auditable. </li></ul> <p>---</p> <h2>🛠 Cloudflare Worker – Multi-Form Submission</h2> <p>The Worker handles:</p> <p>1. <strong>CORS setup</strong> for requests from <code>custom-logic.co.za</code>. 2. <strong>POST-only submissions</strong>, with preflight OPTIONS support. 3. <strong>Payload validation</strong> for required fields (<code>fullName</code>, <code>email</code>, <code>solution</code>). 4. <strong>Dynamic CSV routing</strong> per solution: - <code>unicenta-pos</code> → <code>unicenta_pos_leads.csv</code> - <code>funeral-manager</code> → <code>funeral_manager_leads.csv</code> - <code>jobfinders</code> → <code>jobfinders_leads.csv</code> - <code>custom-development</code> → <code>custom_development_leads.csv</code> 5. <strong>GitHub storage</strong>: - Fetch existing CSV or create a new one with headers. - Append new submission row. - Commit changes using GitHub REST API. 6. <strong>Unique submission IDs</strong> and timestamps for tracking. 7. <strong>Error handling</strong> for invalid payloads, GitHub errors, or misconfigured environment variables.</p> <blockquote>This setup allows <strong>scalable form handling</strong> without adding backend servers, fully integrating with GitHub for persistent storage and auditing.</blockquote> <p>---</p> <h2>🌐 Deployment</h2> <p>1. <strong>Cloudflare Pages</strong> - Deploy the single source HTML. - Automatic global CDN distribution.</p> <p>2. <strong>Cloudflare Workers</strong> - Script intercepts dynamic routes (<code>/sitemap.xml</code>, <code>/robots.txt</code>, <code>/feedback</code>, <code>/orders</code>). - Integrates with GitHub API to persist user submissions.</p> <p>3. <strong>GitHub Integration</strong> - Workers push data to a dedicated repository branch. - Data is versioned and auditable.</p> <p>---</p> <h2>🔍 SEO Strategy</h2> <p>Even with a single-file SPA:</p> <ul><li>Pre-rendered <code><title></code> and <code><meta></code> tags for main sections. </li> <li>JSON-LD structured data for organization info. </li> <li><code>/sitemap.xml</code> and <code>/robots.txt</code> dynamically served via Workers. </li> <li>Anchor links for in-page sections help Google crawl content.</li></ul> <p>---</p> <h2>💡 Philosophy</h2> <p>Custom Logic is a <strong>love letter to minimalism</strong> in web development:</p> <ul><li>One file, one source of truth. </li> <li>Serverless logic for everything dynamic. </li> <li>GitHub as a versioned database. </li> <li>Optimized for speed, SEO, and maintainability. </li></ul> <p>If you’re a coder who likes <strong>clever, compact, cloud-first architectures</strong>, this project is a playground of ideas.</p> <p>---</p> <h2>📜 License</h2> <p>MIT License — go ahead, explore, fork, or remix this single-file marvel.</p> <p>---</p> <p><strong>Written by a coder who genuinely enjoys building clever, minimalist, cloud-native apps.</strong></p> <p></p> </div> <footer class="article-footer"> <div class="article-actions"> <a href="/" class="back-link">← Back to Innovation Hub</a> <a href="/api/menu" class="category-link">View All Categories</a> </div> <div class="article-share"> <p>Found this useful? Share your feedback with our team!</p> <a href="https://custom-logic.co.za/contact" class="cta-button">Get In Touch</a> </div> </footer> </article> </div> </main> <footer class="footer"> <div class="footer-content"> <div class="footer-brand">Custom Logic SA</div> <p class="footer-description"> Enterprise software solutions designed for the unique needs of South African markets. </p> <div class="footer-links"> <a href="https://custom-logic.co.za" class="footer-link">Main Website</a> <a href="https://custom-logic.co.za/solutions" class="footer-link">Solutions</a> <a href="https://custom-logic.co.za/contact" class="footer-link">Contact</a> </div> <div class="footer-bottom"> <p>© 2025 Custom Logic SA (Pty) Ltd. All rights reserved.</p> </div> </div> </footer> <script> class ArticlePage { constructor() { this.init(); } async init() { this.setupMobileMenu(); this.setupStickyNavbar(); await this.loadNavData(); await this.checkHealth(); } setupMobileMenu() { const toggle = document.getElementById('mobileToggle'); const menu = document.getElementById('navMenu'); toggle.addEventListener('click', () => { menu.classList.toggle('active'); toggle.textContent = menu.classList.contains('active') ? '✕' : '☰'; }); } setupStickyNavbar() { const navbar = document.getElementById('navbar'); window.addEventListener('scroll', () => { if (window.scrollY > 50) { navbar.classList.add('scrolled'); } else { navbar.classList.remove('scrolled'); } }); } async loadNavData() { try { const response = await fetch('/api/menu'); const data = await response.json(); if (data.menu) { this.updateNavDropdown(data.menu); } } catch (error) { console.error('Error loading navigation data:', error); } } updateNavDropdown(categories) { const dropdown = document.getElementById('categoriesDropdown'); dropdown.innerHTML = categories.map(category => ` <a href="/api/articles/${category.slug}" class="dropdown-item"> ${category.category} (${category.count}) </a> `).join('') + `<a href="/api/menu" class="dropdown-item"><strong>View All Categories</strong></a>`; } async checkHealth() { const healthDot = document.getElementById('healthDot'); const healthStatus = document.getElementById('healthStatus'); try { const response = await fetch('/api/health'); const data = await response.json(); if (data.status === 'healthy') { healthDot.classList.remove('error'); healthStatus.textContent = 'Online'; } else { healthDot.classList.add('error'); healthStatus.textContent = 'Issues'; } } catch (error) { healthDot.classList.add('error'); healthStatus.textContent = 'Offline'; } } } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => new ArticlePage()); } else { new ArticlePage(); } </script> <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/highlight.min.js"></script> <script> document.querySelectorAll('pre code').forEach((block) => { hljs.highlightElement(block); }); </script> </body> </html>