<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Acoruss]]></title><description><![CDATA[We help businesses harness software, AI, and strategic technology — without the heavy costs of building from scratch. ]]></description><link>https://acoruss.substack.com</link><image><url>https://substackcdn.com/image/fetch/$s_!JkDI!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e8530b5-cfc5-457e-95ab-eb51be6f4f33_383x383.png</url><title>Acoruss</title><link>https://acoruss.substack.com</link></image><generator>Substack</generator><lastBuildDate>Fri, 17 Apr 2026 14:40:36 GMT</lastBuildDate><atom:link href="https://acoruss.substack.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Acoruss]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[acoruss@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[acoruss@substack.com]]></itunes:email><itunes:name><![CDATA[Acoruss]]></itunes:name></itunes:owner><itunes:author><![CDATA[Acoruss]]></itunes:author><googleplay:owner><![CDATA[acoruss@substack.com]]></googleplay:owner><googleplay:email><![CDATA[acoruss@substack.com]]></googleplay:email><googleplay:author><![CDATA[Acoruss]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[How We Handle Payments for Multiple Services with One Provider - Paystack]]></title><description><![CDATA[At Acoruss, we build and run several products and services - from event platforms to custom software for clients. All of them need to accept payments. Here&#8217;s how we handle that using a single payment]]></description><link>https://acoruss.substack.com/p/how-we-handle-payments-for-multiple</link><guid isPermaLink="false">https://acoruss.substack.com/p/how-we-handle-payments-for-multiple</guid><dc:creator><![CDATA[Acoruss]]></dc:creator><pubDate>Tue, 17 Mar 2026 15:43:05 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!tD4e!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe17847e-28f9-476f-b9c8-30ff8fbd9804_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="image-gallery-embed" data-attrs="{&quot;gallery&quot;:{&quot;images&quot;:[{&quot;type&quot;:&quot;image/png&quot;,&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/be17847e-28f9-476f-b9c8-30ff8fbd9804_1024x1024.png&quot;}],&quot;caption&quot;:&quot;&quot;,&quot;alt&quot;:&quot;&quot;,&quot;staticGalleryImage&quot;:{&quot;type&quot;:&quot;image/png&quot;,&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/be17847e-28f9-476f-b9c8-30ff8fbd9804_1024x1024.png&quot;}},&quot;isEditorNode&quot;:true}"></div><h2><strong>The Problem</strong></h2><p>When you&#8217;re running multiple products and services, payments get complicated fast. Each product might need:</p><ul><li><p>Its own payment flow</p></li><li><p>Different currencies (a client in Nigeria pays in NGN, one in the US pays in USD)</p></li><li><p>Separate webhook notifications</p></li><li><p>Isolated transaction records so one product&#8217;s data never leaks into another&#8217;s</p></li></ul><p>The tempting answer is: use a different payment provider for each product. But that means managing multiple dashboards, multiple integrations, and multiple headaches. We chose a different path.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://acoruss.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2><strong>Why Paystack</strong></h2><p><a href="https://paystack.com/">Paystack</a> is a solid payments infrastructure provider with strong support for African markets and international cards. For us, the decision came down to:</p><ul><li><p><strong>Reliable APIs</strong> - Clean REST endpoints for initializing transactions, verifying payments, and handling refunds.</p></li><li><p><strong>Webhook support</strong> - Real-time event notifications when payments succeed, fail, or get refunded.</p></li><li><p><strong>Multi-currency acceptance</strong> - Customers can pay in their local currency.</p></li><li><p><strong>Settlement flexibility</strong> - We receive all payouts in a single settlement currency, which simplifies our accounting.</p></li></ul><p>One Paystack account. Multiple products. Full isolation between them.</p><h2><strong>The Architecture (High Level)</strong></h2><p>Instead of connecting each product directly to Paystack, we built a <strong>payment layer</strong> that sits between our products and the provider.</p><pre><code><code>&#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;    &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;    &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
&#9474;  Product A  &#9474;    &#9474;  Product B  &#9474;    &#9474;  Product C  &#9474;
&#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;    &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;    &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
       &#9474;                  &#9474;                  &#9474;
       &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                          &#9474;
                   &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9660;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
                   &#9474;   Payment   &#9474;
                   &#9474;    Layer    &#9474;
                   &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                          &#9474;
                   &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9660;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
                   &#9474;   Paystack  &#9474;
                   &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
</code></code></pre><p>Each product registers once with our payment layer and gets its own credentials. From there, the flow is simple:</p><ol><li><p><strong>Product requests a payment</strong> - sends amount, currency, customer email, and any metadata it needs back later.</p></li><li><p><strong>Currency conversion</strong> - if the customer&#8217;s currency differs from our settlement currency, we convert it transparently using live exchange rates.</p></li><li><p><strong>Paystack checkout</strong> - the customer is redirected to a secure Paystack-hosted payment page.</p></li><li><p><strong>Webhook relay</strong> - when Paystack confirms payment, we update our records and forward the event to the originating product&#8217;s own webhook URL.</p></li><li><p><strong>Verification</strong> - the product can also query payment status directly via our API, rather than relying solely on webhooks.</p></li></ol><h2><strong>Key Design Decisions</strong></h2><h3><strong>1. Service Isolation</strong></h3><p>Every product that uses our payment layer is fully isolated:</p><ul><li><p><strong>Separate credentials</strong> - each product authenticates independently. Product A cannot see or modify Product B&#8217;s transactions.</p></li><li><p><strong>Scoped queries</strong> - when a product asks &#8220;show me my payments,&#8221; it only sees its own.</p></li><li><p><strong>Independent webhooks</strong> - each product receives payment events at its own endpoint, signed with its own secret.</p></li></ul><p>This means adding a new product is just a registration step. No new Paystack integration, no new provider account.</p><h3><strong>2. Currency Conversion as a First-Class Feature</strong></h3><p>Our clients are spread across multiple countries. A customer in Kenya pays in KES, someone in the US pays in USD, and a client in the UK pays in GBP. Rather than forcing everyone into one currency, we:</p><ul><li><p>Accept the payment in the <strong>customer&#8217;s currency</strong></p></li><li><p>Convert to our <strong>settlement currency</strong> using live rates from a reliable data source</p></li><li><p>Store the original amount, the converted amount, and the exchange rate used</p></li></ul><p>This way, the customer sees familiar numbers, and our books stay clean.</p><h3><strong>3. Webhook Reliability</strong></h3><p>Webhooks are the backbone of async payment processing, but they&#8217;re unreliable by nature - networks fail, servers go down. We handle this with:</p><ul><li><p><strong>Signature verification</strong> on every incoming Paystack webhook (HMAC validation - never trust unsigned events)</p></li><li><p><strong>Signed outbound webhooks</strong> to our products, so they can verify the event came from us</p></li><li><p><strong>Retry logic with backoff</strong> - if a product&#8217;s webhook endpoint is down, we retry with increasing delays</p></li><li><p><strong>Full delivery logging</strong> - every delivery attempt is recorded with status codes and response details</p></li></ul><h3><strong>4. Idempotency</strong></h3><p>Duplicate payment requests happen - a user double-clicks, a network retry fires, a webhook is delivered twice. We handle this by accepting an idempotency key with each payment request. If we&#8217;ve already processed that key for a given product, we return the existing payment instead of creating a new one. No double charges.</p><h3><strong>5. Refund Support</strong></h3><p>Refunds flow through the same layer. A product requests a refund (full or partial), we process it through Paystack, and the product gets a webhook when it&#8217;s complete. The original payment record tracks refund status, amounts, and history.</p><h2><strong>What This Looks Like in Practice</strong></h2><p>Here&#8217;s a simplified example of how a product initiates a payment:</p><pre><code><code>POST /api/v1/payments/initiate/
Authorization: Bearer &lt;product_api_key&gt;

{
  "email": "customer@example.com",
  "amount": 25.00,
  "currency": "USD",
  "description": "Monthly subscription",
  "callback_url": "https://myproduct.com/payment/complete",
  "metadata": {
    "plan": "standard",
    "user_id": "usr_12345"
  }
}
</code></code></pre><p>The response includes a checkout URL for the customer and a reference to track the payment. When the customer pays, the product gets a webhook:</p><pre><code><code>{
  "event": "payment.success",
  "reference": "acoruss-abc123",
  "amount": 25.0,
  "currency": "USD",
  "settlement_amount": 3237.5,
  "settlement_currency": "KES",
  "metadata": {
    "plan": "standard",
    "user_id": "usr_12345"
  }
}
</code></code></pre><p>The metadata round-trips back - whatever the product sent in, it gets back. This means the product can reconcile the payment with its own records without any additional lookups.</p><h2><strong>Lessons Learned</strong></h2><p><strong>Don&#8217;t multiply providers unnecessarily.</strong> If one provider covers your needs, build an abstraction layer instead of fragmenting across multiple integrations. You&#8217;ll save on maintenance, onboarding, and debugging.</p><p><strong>Treat currency conversion as data, not a side effect.</strong> Store everything - original amount, rate, converted amount. When a customer disputes a charge six months later, you&#8217;ll want that trail.</p><p><strong>Never trust the redirect.</strong> When a customer is redirected back to your site after payment, the URL parameters are informational only. Always verify payment status via webhook or API call. URLs can be tampered with.</p><p><strong>Webhooks will fail. Plan for it.</strong> Retries, logging, and idempotent handlers aren&#8217;t optional. They&#8217;re the difference between &#8220;payments work&#8221; and &#8220;payments work reliably.&#8221;</p><p><strong>Isolate early.</strong> Even if you only have one product today, building with multi-service isolation from the start means you won&#8217;t have to retrofit it later when product number two comes along.</p><div><hr></div><p><em>At Acoruss, we help businesses set up exactly this kind of infrastructure - payment systems, integrations, and the operational tooli<a href="https://acoruss.com">Acoruss</a>ng around them. If you&#8217;re dealing with payment complexity and want a cleaner path forward, <a href="https://acoruss.com/contact">get in touch</a>.</em></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://acoruss.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Building Full-Stack Apps with Google Sheets, Apps Script, Clasp, and Vite]]></title><description><![CDATA[A practical guide to rapid prototyping with a spreadsheet-powered backend]]></description><link>https://acoruss.substack.com/p/building-full-stack-apps-with-google</link><guid isPermaLink="false">https://acoruss.substack.com/p/building-full-stack-apps-with-google</guid><dc:creator><![CDATA[Acoruss]]></dc:creator><pubDate>Fri, 13 Mar 2026 09:15:45 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!edwi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9aa6e7d-5e14-430d-acfe-b6935b90de30_678x302.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>What if your next backend was&#8230; a spreadsheet?</p><p>It sounds absurd at first, but Google Sheets paired with Google Apps Script is one of the most underrated stacks for building internal tools, MVPs, and lightweight data-driven applications. When you layer in <strong>Clasp</strong> for local development, <strong>Vite</strong> for a modern frontend, and <strong>Google Social Auth</strong> for identity - you get a surprisingly capable full-stack architecture that can go from idea to deployed app in hours, not weeks.</p><p>In this post, we&#8217;ll walk through the entire architecture: how it works, why you&#8217;d use it, what to watch out for, and where it shines.</p><h2>The idea in 30 seconds</h2><p>Here&#8217;s the stack:</p><ul><li><p><strong>Google Sheets</strong> as the database</p></li><li><p><strong>Google Apps Script</strong> as the backend (serverless functions that talk to Sheets natively)</p></li><li><p><strong>Clasp</strong> for local development (write your backend in VS Code, push to Google from the terminal)</p></li><li><p><strong>Vite</strong> for the frontend (vanilla JS, fast builds, hot reload)</p></li><li><p><strong>Google Sign-In</strong> for authentication (OAuth 2.0 - the real deal)</p></li></ul><p>The user opens your app, signs in with Google, and the frontend talks to an Apps Script endpoint over plain HTTP. The endpoint reads from and writes to a Google Sheet. That&#8217;s it. That&#8217;s the whole backend.</p><p>No servers. No databases. No Docker. No AWS. No monthly bill.</p><h2>Wait, Apps Script can do that?</h2><p>Yeah! This is the part that surprises most people.</p><p>Google Apps Script is a JavaScript runtime that lives on Google&#8217;s servers. It has native access to Sheets, Drive, Gmail, Calendar - the whole Google ecosystem. And crucially, you can deploy any script as a <strong>Web App</strong>, which gives you a URL that responds to <code>GET</code> and <code>POST</code> requests.</p><p>So you write two functions:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;javascript&quot;,&quot;nodeId&quot;:&quot;c42bfe66-e7fb-42ff-8047-6b6c75519c93&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-javascript">function doGet(e) {
  // Handle GET requests &#8212; read data from Sheets
  const action = e.parameter.action;
  
  if (action === 'getData') {
    const data = getSheetData('Data');
    return ContentService
      .createTextOutput(JSON.stringify(data))
      .setMimeType(ContentService.MimeType.JSON);
  }
}

function doPost(e) {
  // Handle POST requests &#8212; write data to Sheets
  const payload = JSON.parse(e.postData.contents);
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Data');
  
  sheet.appendRow([payload.name, payload.value, new Date()]);
  
  return ContentService
    .createTextOutput(JSON.stringify({ status: 'success' }))
    .setMimeType(ContentService.MimeType.JSON);
}</code></pre></div><p>Deploy it, and you&#8217;ve got an API. Your frontend just does <code>fetch(&#8217;https://script.google.com/macros/s/YOUR_ID/exec&#8217;)</code> and gets JSON back. It works exactly like any other REST endpoint - except the data lives in a spreadsheet.</p><p>Reading from Sheets is beautifully simple. The spreadsheet is just a 2D array. You grab the first row as headers, map the rest into objects, and return JSON:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;javascript&quot;,&quot;nodeId&quot;:&quot;827a6ec2-dfdc-4a4b-be57-fbc8633d43bf&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-javascript">function getSheetData(sheetName) {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
  const data = sheet.getDataRange().getValues();
  const headers = data[0];

  return data.slice(1).map(row =&gt; {
    const obj = {};
    headers.forEach((header, i) =&gt; obj[header] = row[i]);
    return obj;
  });
}</code></pre></div><p>That&#8217;s your ORM. That&#8217;s your database driver. Seven lines.</p><p>Clasp makes this actually pleasant</p><p>Now, I wouldn&#8217;t recommend this stack if you had to write all your code in Google&#8217;s browser-based script editor. It&#8217;s&#8230; fine for small scripts, but it&#8217;s no place to build an app.</p><p>That&#8217;s where <strong>Clasp</strong> comes in. It&#8217;s a CLI tool from Google that lets you develop Apps Script locally:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:&quot;4b1ffddd-5368-4bd1-aa15-eabacdd24ec2&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">npm install -g @google/clasp
clasp login
clasp clone &lt;your-script-id&gt;</code></pre></div><p>Now your Apps Script code is just <code>.js</code> files on your machine. Edit them in VS Code. Use Git. Run a linter. Then:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:&quot;d9d27ffa-c9c0-4e20-95f5-5d1f290a6011&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">cd backend
clasp push                              # sends code to Google
clasp deploy --description "v2 roles"   # deploys a new Web App version</code></pre></div><p>Your backend code lives right next to your frontend code in the same repo. It feels normal. It <strong>is</strong> normal - it&#8217;s just JavaScript files that happen to run on Google&#8217;s servers instead of yours.</p><h2>Authentication that doesn&#8217;t make you cry</h2><p>Here&#8217;s my favorite part of this whole setup: <strong>authentication is basically free.</strong></p><p>You add Google Sign-In to your frontend with their Identity Services library. The user clicks &#8220;Sign in with Google,&#8221; and you get back a JWT token containing their verified email, name, and profile picture. Google handles the OAuth flow, the token verification, the session management - all of it.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;javascript&quot;,&quot;nodeId&quot;:&quot;e282c23b-a264-4d59-8e1c-9de31fdbfd42&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-javascript">function handleAuth(response) {
  const payload = decodeJwtPayload(response.credential);
  const email = payload.email;
  // That's it. You have a verified email address.
}</code></pre></div><p>No passwords to hash. No forgot-password flow. No session tokens to manage. No auth middleware. Google just tells you who the user is, and you trust that because it&#8217;s Google.</p><p>But here&#8217;s where it gets <strong>really</strong> elegant.</p><h2>Your user table is a spreadsheet tab</h2><p>Instead of building a user management system, you create a <strong>Users</strong> tab in your Google Sheet:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!edwi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9aa6e7d-5e14-430d-acfe-b6935b90de30_678x302.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!edwi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9aa6e7d-5e14-430d-acfe-b6935b90de30_678x302.png 424w, https://substackcdn.com/image/fetch/$s_!edwi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9aa6e7d-5e14-430d-acfe-b6935b90de30_678x302.png 848w, https://substackcdn.com/image/fetch/$s_!edwi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9aa6e7d-5e14-430d-acfe-b6935b90de30_678x302.png 1272w, https://substackcdn.com/image/fetch/$s_!edwi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9aa6e7d-5e14-430d-acfe-b6935b90de30_678x302.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!edwi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9aa6e7d-5e14-430d-acfe-b6935b90de30_678x302.png" width="678" height="302" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c9aa6e7d-5e14-430d-acfe-b6935b90de30_678x302.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:302,&quot;width&quot;:678,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:41661,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://acoruss.substack.com/i/190814018?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9aa6e7d-5e14-430d-acfe-b6935b90de30_678x302.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!edwi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9aa6e7d-5e14-430d-acfe-b6935b90de30_678x302.png 424w, https://substackcdn.com/image/fetch/$s_!edwi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9aa6e7d-5e14-430d-acfe-b6935b90de30_678x302.png 848w, https://substackcdn.com/image/fetch/$s_!edwi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9aa6e7d-5e14-430d-acfe-b6935b90de30_678x302.png 1272w, https://substackcdn.com/image/fetch/$s_!edwi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9aa6e7d-5e14-430d-acfe-b6935b90de30_678x302.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Your backend checks the authenticated email against this list:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;javascript&quot;,&quot;nodeId&quot;:&quot;d42252e9-4e74-42d3-bf54-7c2f486e2336&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-javascript">function isAuthorized(email) {
  const users = getSheetData('Users');
  return users.find(u =&gt; 
    u.Email.toLowerCase() === email.toLowerCase() &amp;&amp; u.Status === 'active'
  ) || null;
}</code></pre></div><p>Want to add a new user? Add a row to the spreadsheet. Want to revoke access? Change their status to &#8220;inactive.&#8221; Want to promote someone to admin? Edit their role cell.</p><p>No migration. No deployment. No admin panel to build. Your project manager can manage users from the same Google Sheet they&#8217;re already staring at all day.</p><p>Role-based access works the same way. Your backend just checks the role before allowing an operation:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;javascript&quot;,&quot;nodeId&quot;:&quot;26bfffac-24f1-4098-b3a4-ff1a6a41360b&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-javascript">if (payload.action === 'deleteRecord' &amp;&amp; user.Role !== 'admin') {
  return jsonResponse({ error: 'Nope, admins only' });
}</code></pre></div><p>It&#8217;s crude compared to a real RBAC system, but for a team of 5-50 people? It&#8217;s more than enough.</p><h2>The frontend: fast and simple</h2><p>On the other side, <strong>Vite</strong> gives you a modern dev experience - hot module replacement, ES modules, optimized builds - without the ceremony of React or Next.js.</p><p>Your project structure looks something like:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:&quot;92d6dd26-0352-4179-bfe8-5a91e95fecb1&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">src/
&#9500;&#9472;&#9472; main.js        # Entry point
&#9500;&#9472;&#9472; auth.js        # Google Sign-In
&#9500;&#9472;&#9472; api.js         # fetch() calls to your Apps Script endpoint
&#9500;&#9472;&#9472; dashboard.js   # UI rendering
&#9500;&#9472;&#9472; config.js      # API URLs, client IDs
&#9492;&#9472;&#9472; style.css      # Tailwind + DaisyUI</code></pre></div><p>The API layer is just <code>fetch()</code> with a wrapper:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;javascript&quot;,&quot;nodeId&quot;:&quot;4e4a1949-8093-4fcb-8d54-eb4b2c2fbe69&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-javascript">export async function fetchData(action, email) {
  const url = `${API_URL}?action=${encodeURIComponent(action)}&amp;email=${encodeURICoponent(email)}`;
  const response = await fetch(url);
  return response.json();
}</code></pre></div><p>And with Tailwind CSS + DaisyUI, you can make it look good without writing much (or any) custom CSS. Tables, cards, buttons, modals - it&#8217;s all just class names.</p><p>The whole frontend can be deployed to GitHub Pages, Netlify, or Vercel for free. Combined with the free Apps Script hosting, your total infrastructure cost is <strong>$0</strong>.</p><h2>When does this actually make sense?</h2><p>This isn&#8217;t a stack for everything. But it&#8217;s <strong>great</strong> for:</p><p><strong>Internal tools</strong>. Your team already lives in Google Workspace. The data&#8217;s already in Sheets. Just put a nicer UI on top of it.</p><p><strong>MVPs and prototypes</strong>. You need to validate an idea by Friday. Skip the database, skip the deployment pipeline, skip the DevOps. Ship something real, with real data persistence, in a day.</p><p><strong>Client portals</strong>. Small agencies that manage client data in spreadsheets (most of them) can build lightweight portals backed by the same data.</p><p><strong>Approval workflows</strong>. Expense approvals, content reviews, onboarding checklists. The spreadsheet is both the database and the admin interface.</p><p><strong>Financial tracking</strong>. Budgets, invoices, fund overviews - data that&#8217;s inherently tabular and that stakeholders want to access in spreadsheet form anyway.</p><p><strong>Event management</strong>. Registration, attendee tracking, check-in systems. Organizers get real-time access to the data without needing a login to your app.</p><h2>The risks (let&#8217;s be honest)</h2><p>I&#8217;d be doing you a disservice if I didn&#8217;t talk about the sharp edges. There are real ones.</p><h3>Security</h3><p>Google Sheets is not a database. There&#8217;s no row-level security, no encryption at the field level, and no query parameterization. If someone has edit access to the Sheet, they see everything. Don&#8217;t store passwords, secrets, or sensitive PII here.</p><p>Your Apps Script Web App URL is also a public endpoint. If you deploy it with &#8220;Anyone&#8221; access, the <strong>only</strong> thing protecting your data is the auth check in your code. Make sure you&#8217;re validating identity server-side in every <code>doGet()</code> and <code>doPost()</code> handler.</p><p>And there&#8217;s an attack vector most people don&#8217;t think about: <strong>formula injection</strong>. If a user submits <code>=IMPORTRANGE(...)</code> as input and you write it to a cell, it&#8217;ll execute in the Sheet context. Sanitize your inputs. Prefix user-generated text with a single quote to force Sheets to treat it as plain text.</p><h3>Scale limits</h3><p>Apps Script has hard quotas. Consumer accounts get 90 minutes of total execution time per day, with a 6-minute cap per execution. You get 20,000 URL fetch calls per day. Sheets performance degrades noticeably past ~10,000 rows. And there are no transactional guarantees - two simultaneous writes can conflict.</p><p>You can mitigate some of this with <code>CacheService</code> (Apps Script&#8217;s built-in caching) and <strong>LockService</strong> (for serializing writes), but fundamentally, this stack wasn&#8217;t built for high concurrency or large datasets.</p><h3>CORS quirks</h3><p>Apps Script Web Apps have unusual redirect behavior that can trip up <code>fetch()</code> calls. You&#8217;ll want <code>redirect: &#8216;follow&#8217;</code> in your fetch options, and you should test deployments carefully - each new deployment can get a different URL if you don&#8217;t pass the <code>&#8212;id YOUR_ID</code> when deploying with Clasp.</p><h3>Vendor lock-in</h3><p>Your entire backend runs on Google&#8217;s platform. If Google changes quotas, deprecates a feature, or has an outage, you&#8217;re down. Keep your code version-controlled with Clasp, and keep the business logic separable from the platform bindings so you can port it if needed.</p><h3>No real audit trail</h3><p>Sheets tracks edit history, but bulk writes from Apps Script may not show granular changes. If you need accountability, build your own audit log - write every operation to a dedicated &#8220;Audit&#8221; tab with timestamps and user emails.</p><h3>The gains (and they&#8217;re real)</h3><p>So why bother with all those caveats?</p><p>Because the upside is enormous for the right use case.</p><p><strong>Speed</strong>. You go from idea to working app faster than with any traditional stack. No database setup, no ORM, no migrations, no server provisioning, no CI/CD pipeline. The backend is a spreadsheet and some functions.</p><p><strong>Cost</strong>. $0 infrastructure. Google Apps Script is free within quotas. The frontend can be hosted free on any static platform. You&#8217;re not paying for anything until you outgrow the stack.</p><p><strong>Accessibility</strong>. Your non-technical stakeholders can view, edit, and manage data directly in Google Sheets. They don&#8217;t need an admin panel - the spreadsheet <strong>is</strong> the admin panel. Everyone knows how to use a spreadsheet.</p><p><strong>Collaboration built in</strong>. Real-time editing, comments, version history, sharing controls. These are features you&#8217;d spend weeks building in a traditional app. Sheets gives them to you for free.</p><p><strong>The Google ecosystem</strong>. Need to send a notification email? <code>GmailApp.sendEmail().</code> Generate a PDF? <code>DriveApp.createFile().</code> Schedule a task? Use a time-driven trigger. It&#8217;s all one function call away.</p><p><strong>Production-grade auth for free</strong>. Google Sign-In gives you OAuth 2.0, JWT tokens, and MFA is enterprise-grade identity without building or maintaining any of it.</p><p><strong>Git-friendly</strong>. With Clasp, your entire application - frontend and backend - lives in one Git repo. Code reviews, branching, CI/CD will all works like any other project.</p><h2>When to graduate</h2><p>This stack won&#8217;t scale forever. Here are the signals that it&#8217;s time to move to a real backend:</p><ul><li><p>You&#8217;re hitting quota limits regularly</p></li><li><p>You need JOINs, aggregations, or complex queries</p></li><li><p>You&#8217;ve got more than ~10,000 rows of data</p></li><li><p>You need transactional integrity for financial or compliance operations</p></li><li><p>You have more than ~50 concurrent users</p></li><li><p>You need sub-second response times</p></li></ul><p>But here&#8217;s the thing: <strong>that&#8217;s fine</strong>. The point of this stack isn&#8217;t to build the final version of your product. It&#8217;s to build the <strong>first</strong> version which is the one that proves the idea works, gathers real user feedback, and tells you exactly what the final version needs to do.</p><p>When you outgrow the spreadsheet, you&#8217;ll have a working app and real usage data to guide your migration. That&#8217;s infinitely better than spending months building infrastructure for a product nobody wanted.</p><h2>The deployment flow</h2><p>For the curious, here&#8217;s the full loop:</p><ol><li><p>Write your frontend in Vite (vanilla JS + Tailwind)</p></li><li><p>Write your backend in Apps Script (locally, via Clasp)</p></li><li><p><code>clasp push</code> - sends backend code to Google</p></li><li><p><code>clasp deploy</code> - generates a Web App URL</p></li><li><p>Put that URL in your frontend config</p></li><li><p><code>npm run build</code> - produces optimized static assets</p></li><li><p>Deploy the frontend to any static host</p></li><li><p>Users sign in with Google and get a verified email</p></li><li><p>Frontend fetches data from the Apps Script endpoint</p></li><li><p>Apps Script reads/writes Google Sheets</p></li><li><p>Data flows back to the browser</p></li></ol><p>That&#8217;s it. No servers, no databases, no DevOps team. Just a spreadsheet, some JavaScript, and a URL.</p><h2>Final thought</h2><p>The best architecture for your project isn&#8217;t always the most sophisticated one. Sometimes the best database is the one your stakeholders already have open in another browser tab.</p><p>Give this stack a try next time you need to build something fast. You might be surprised how far a spreadsheet can take you.</p><div class="pullquote"><p><em>If you&#8217;ve built anything with Apps Script and Google Sheets or if you tried and hit a wall, I&#8217;d love to hear about it. Reply to this email or drop a comment below. What worked? What didn&#8217;t? When did you know it was time to move on?</em></p></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://acoruss.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Hello, www]]></title><description><![CDATA[Acoruss is here to simplify how businesses harness software and AI. In this first post, we share our vision of making technology more accessible, secure, and cost-effective &#8212; helping organizations innovate without the heavy costs of building from scratch.]]></description><link>https://acoruss.substack.com/p/hello-www</link><guid isPermaLink="false">https://acoruss.substack.com/p/hello-www</guid><dc:creator><![CDATA[Acoruss]]></dc:creator><pubDate>Mon, 18 Aug 2025 18:25:13 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/8d2ddbe6-223a-403c-9ef1-654398d3837c_500x500.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>At <a href="https://acoruss.com">Acoruss</a>, we believe that technology should empower, not overwhelm. Too often, businesses face a choice between expensive, complex solutions and falling behind in a fast-changing digital world. We exist to change that.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!PXCE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf613f61-e727-4b74-a60f-a2207261d7a6_500x500.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!PXCE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf613f61-e727-4b74-a60f-a2207261d7a6_500x500.png 424w, https://substackcdn.com/image/fetch/$s_!PXCE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf613f61-e727-4b74-a60f-a2207261d7a6_500x500.png 848w, https://substackcdn.com/image/fetch/$s_!PXCE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf613f61-e727-4b74-a60f-a2207261d7a6_500x500.png 1272w, https://substackcdn.com/image/fetch/$s_!PXCE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf613f61-e727-4b74-a60f-a2207261d7a6_500x500.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!PXCE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf613f61-e727-4b74-a60f-a2207261d7a6_500x500.png" width="500" height="500" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/af613f61-e727-4b74-a60f-a2207261d7a6_500x500.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:500,&quot;width&quot;:500,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:24566,&quot;alt&quot;:&quot;Acoruss logo&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://acoruss.substack.com/i/171299335?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf613f61-e727-4b74-a60f-a2207261d7a6_500x500.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Acoruss logo" title="Acoruss logo" srcset="https://substackcdn.com/image/fetch/$s_!PXCE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf613f61-e727-4b74-a60f-a2207261d7a6_500x500.png 424w, https://substackcdn.com/image/fetch/$s_!PXCE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf613f61-e727-4b74-a60f-a2207261d7a6_500x500.png 848w, https://substackcdn.com/image/fetch/$s_!PXCE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf613f61-e727-4b74-a60f-a2207261d7a6_500x500.png 1272w, https://substackcdn.com/image/fetch/$s_!PXCE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf613f61-e727-4b74-a60f-a2207261d7a6_500x500.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Our mission is simple: <strong>help organizations and individuals harness software, AI, and strategic technology adoption&#8212;without the heavy costs of building from scratch.</strong> From advisory to implementation, we make technology accessible, practical, and growth-focused.</p><h3>What We Do</h3><p>We specialize in:</p><ul><li><p><strong>Custom Software Development</strong> &#8211; delivering tailored solutions that simplify operations and unlock new opportunities.</p></li><li><p><strong>AI &amp; Automation</strong> &#8211; enabling businesses to leverage AI tools and workflows that drive efficiency and insight.</p></li><li><p><strong>Process Optimization &amp; Cost Reduction</strong> &#8211; auditing current systems to cut waste and improve performance.</p></li><li><p><strong>Security &amp; Trust Engineering</strong> &#8211; ensuring the technologies you rely on are safe, resilient, and future-ready.</p></li></ul><h3>Why This Substack?</h3><p>This publication will be your window into how Acoruss and the expert partners think, build, and innovates. Expect insights on:</p><ul><li><p>Emerging trends in software and AI adoption</p></li><li><p>Lessons from real-world implementations</p></li><li><p>Practical guides for optimizing business processes with tech</p></li><li><p>Updates from our products and open-source projects</p></li></ul><p>We&#8217;re excited to share our journey and invite you to be part of it. Whether you&#8217;re a business leader, developer, or simply curious about the future of technology, Acoruss is here to help you harness it with confidence.</p><p><strong>Thank you for subscribing &#8212; the journey starts here.<br></strong></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://acoruss.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://acoruss.substack.com/subscribe?"><span>Subscribe now</span></a></p>]]></content:encoded></item></channel></rss>