AI 资讯
How I stopped hardcoding business rules in PHP - and built a rule engine to fix it
Every PHP developer knows this situation: a client calls and says "I want free shipping for VIP customers on weekends, but only if the cart total is above €100." You open your code. You find the shipping module. You add an if. You deploy. Three weeks later: "Actually, make it €80. And also for the 'Premium' group." You open your code again. This loop : client request -> find logic in code -> modify -> deploy, was costing me a lot of time. And it's not just shipping. I build custom ecommerce solutions: payment modules, synchronization systems, pricing calculators. Business rules are everywhere, and they change constantly. The obvious solution I didn't want Symfony's ExpressionLanguage exists and it's impressive. But it pulls in dependencies, it can traverse objects and call methods (which is a security concern when rules are authored by users), and when something goes wrong, it doesn't tell you why. It's a black box. I needed something smaller, stricter, and transparent. So I built php-ruler I started with the classic pipeline: Lexer → AST → Evaluator. Strict typing from the start — 1 = '1' is a type error, not true. No silent coercion. Then I added features one real problem at a time. Problem: when something fails, why? -> I built an explain mode that returns the full evaluation tree: which sub-conditions passed, which failed, which were short-circuited, and why a variable was missing. Problem: in production, the context is sometimes incomplete -> I built a safe mode that doesn't throw on missing variables — it collects them all and lets you decide what to do. Problem: customer.group.name is not user-friendly -> I built an alias resolver. As a developer, I expose what I want: $resolver = ( new AliasResolver ()) -> add ( 'customer.group' , 'customer group' ) -> add ( 'cart.total' , 'cart amount' ); Now a non-developer can write: customer group = 'VIP' AND cart amount > 100 And I control exactly what variables are available to them. A real example Here's the shipping
AI 资讯
[FOR HIRE] Front-End Developer | 4.5+ Years Experience | Next.js /React / TypeScript / JavaScript | Open to Full-Time/PartTime Remote Positions
Hey everyone! I'm a Front-End developer with over 4.5 years of hands-on experience building scalable, performant web applications. I'm currently looking for a full-time remote opportunity. i could make modern web applications using Next.js or React.js & fueled by a passion for solving complex problems, diving into intricate challenges, and crafting clean, scalable solutions that deliver seamless user experiences. 🛠 Tech Stack: React.js & Next.js (SSR, SSG, App Router) TypeScript & JavaScript (ES6+) - Node.js - Express.js REST APIs & state management (Zustand, React Query) CSS/Tailwind/Styled Components , many Animation packages Git, CI/CD basics, Docker performance-optimization & SEO friendly Application Time Management – Responsible – Open mind – Team work – Attention to detail Commitment to work – Continuous learning 💼 What I bring: 4.5+ years building production-grade UIs Strong focus on performance, accessibility, and clean code Experience working in agile, remote-friendly teams Good communication and ability to work independently across time zones 🌍 Availability: Full-time/Part-time remote | Open to companies worldwide 🌐 My Portfolio ⬇️⬇️ https://pouyaazhkan.vercel.app/ 👨🏻💻My GitHub ⬇️⬇️ https://github.com/PouyaAzhkan 📩 Email Me ⬇️⬇️ codpoya.azhkan@gmail.com Feel free to DM me or drop a comment — happy to share my portfolio and discuss further! forhire #frontend #react #nextjs #typescript #remotework #webdeveloper #developer #Front_End #hiredeveloper #hire
AI 资讯
How I Built an AI Invoice Generator with Groq, AWS DynamoDB, and Vercel v0
I built InvoiceAI an AI powered invoice generator that lets you describe what you want to invoice in plain English and get a fully formatted invoice in seconds, complete with PDF download and a real payment link. Here's how I built it for the #H0Hackathon. The Problem Freelancers and small businesses waste time manually creating invoices. You know what you did, who you did it for, and how much it costs you shouldn't have to fill out a form to capture that. The Stack - Vercel v0 — scaffolded the entire UI in one prompt Next.js 16 — framework Groq (Llama 3.3 70B) — AI natural language to invoice fields AWS DynamoDB — stores every generated invoice Paystack — generates real payment links jsPDF — client-side PDF generation Vercel — deployment How It Works User types: "50 hours of mobile app development at $80/hr for TechLagos Ltd, 7.5% VAT" Groq parses the text and extracts structured invoice data Live preview updates instantly User downloads PDF — invoice is saved to DynamoDB automatically One click generates a real Paystack payment link to send to the client Building the UI with v0 I used Vercel v0 to scaffold the entire UI in one prompt. It generated a production-ready Next.js component with a split-panel layout form on the left, live invoice preview on the right. I just had to wire up the AI and database logic. Connecting AWS DynamoDB Using the AWS SDK v3, I connected DynamoDB directly from Next.js server actions. Every time a user downloads an invoice, it's saved to DynamoDB with the client details, line items, tax rate, and timestamp. This gives the app a real data foundation that scales from day one. await dynamo . send ( new PutCommand ({ TableName : ' invoices ' , Item : { invoiceId : data . invoiceNumber , clientName : data . clientName , clientEmail : data . clientEmail , items : data . items , createdAt : new Date (). toISOString (), }, })) The Result AI generates invoice from plain English in under 2 seconds Real PDF download (no print dialog) Real Paystack
科技前沿
Web Technology Sessions at WWDC26
submitted by /u/feross [link] [留言]
AI 资讯
Recently found a GDPR gap in our LLM traces
Alright, first, for context, we’re a small early-stage startup (3 engineers total) and we closed our first round of funding 3 months ago. Second, not a lawyer or a GDPR expert. Obviously, I know GDPR is something we’d need to comply with, but we were so focused on rolling out the product to our customers that signed LOIs that it was just never a main focus. Anyways, we were about 2 weeks away from rolling out the product with our first customer based in Germany and we were rigorously testing our platform to make sure there weren’t any major hiccups during our launch. For the most part things were solid, no major bugs (a few tickets in Linear for styling issues), and we were getting good responses. We had Sentry set up for error tracking and PostHog for analytics. For tracing, we're using Braintrust, and thankfully all the data there is being hosted in the EU, so we didn't have to worry about that. But I did notice an issue we had missed. We’ve been logging everything. I’m talking about all the inputs, outputs, and conversation history, which sounds fine and helped us with debugging and building out the product. But our logs also contained a ton of PII. Names users typed into prompts, email addresses that showed up in completions, the occasional address or phone number. It just never crossed our mind that this was user data storage (in retrospect, duh) andd we had zero controls in place. No retention policy, no documented deletion path, no way to respond to an access request. When I flagged it, our CTO was freaking pissed. He didn't want to delay the launch, but going live while logging all that PII was an instant no-go. Which I totally get, not just because of GDPR, but I also think that there was no real reason to hoard that much data in the first place. What we ended up doing was, I think, a clean fix by treating the eval platform itself as the control point. I.e. being intentional about what fields get captured, setting actual retention policies, and making sure
开源项目
GitHub Copilot seems to have become much more expensive and limited - have you switched to something else?
I use GitHub CoPilot in VS Code in my small webdev business, and today I just found out that I burned through my usage quota in two working days, using it the same way as I always have. I know they changed how the plan worked on June 1, but seriously? Previously I rarely hit the ceiling during an entire month of work - and now, in two days of pretty typical use, I hit the limit. I want to unsubscribe from this crap but am not too familiar with the alternatives. What do you recommend based on my use case? Or is it the same with all the CoPilot-like services now? submitted by /u/legable [link] [留言]
AI 资讯
What platform would you use if you had to manage 50 sites tomorrow?
Hello everyone! I'm looking for some advice from anyone who's managed a big portfolio of websites. We run about 50 dental practice sites and are finally thinking about consolidating them onto one platform. Nothing fancy, these are pretty simple sites where the main conversions are phone calls, contact forms, and appointment links to third-party booking systems. No e-commerce needed. What we're after: Easy multi-location management Simple content/copy updates Solid/SEO-friendly Clean, modern design Fast and secure I've been looking at WordPress & Webflow , but before I commit I'd love to hear from someone who's actually been in the trenches with 20–50+ sites. If you were starting over today, what platform would you choose and why? Also, if you've gone through a large website migration, what mistakes should I avoid? Appreciate any advice. Thank you SO much! submitted by /u/wallybonanza [link] [留言]
开发者
Learning about Truthy and Falsy Values in JavaScript
In JavaScript, truthy and falsy values are concepts related to boolean evaluation. Every value in JavaScript has an inherent boolean "truthiness" or "falsiness," which means they can be implicitly evaluated to true or false in boolean contexts, such as in conditional statements or logical operations. What Are Truthy Values? Truthy values are values that are evaluated to be true when used in a Boolean context. Simply put, any value that is not explicitly falsy is considered truthy. These are some truthy values Non-zero numbers: 42, -1, 3.14 Non-empty strings: "hello", "0", " " Objects and arrays: {}, [] Functions: function() {} Dates: new Date() Symbols: Symbol() BigInt values other than 0n: 10n if ( 42 ) console . log ( " This is truthy! " ); if ( " hello " ) console . log ( " Non-empty strings are truthy! " ); if ({}) console . log ( " Objects are truthy! " ); Output This is truthy ! Non - empty strings are truthy ! Objects are truthy ! What Are Falsy Values? Falsy values are values that evaluate to false when used in a Boolean. JavaScript has a fixed list of falsy values false 0 (and -0) 0n (BigInt zero) "" (empty string) null undefined NaN document.all (used for backward compatibility) if (0) console.log("This won't run because 0 is falsy."); if ("") console.log("This won't run because an empty string is falsy."); if (null) console.log("This won't run because null is falsy."); Truthy vs. Falsy Evaluation in JavaScript Whenever JavaScript evaluates an expression in a Boolean (e.g., in an if statement, a logical operator, or a loop condition), it implicitly converts the value into true or false based on whether it is truthy or falsy. With if Statement let s = " JavaScript " ; if ( s ) { console . log ( " Truthy! " ); } else { console . log ( " Falsy! " ); } Output Truthy ! Logical Operators with Truthy and Falsy Logical operators like && (AND) and || (OR) work with truthy and falsy values && (AND): Returns the first falsy operand or the last operand if all are tr
开发者
Conditional Statements in JavaScript
JAVASCRIPT CONDITIONAL STATEMENTS JavaScript conditional statements are used to make decisions in a program based on given conditions. They control the flow of execution by running different code blocks depending on whether a condition is true or false. Conditions are evaluated using comparison and logical operators. They help in building dynamic and interactive applications by responding to different inputs. Types of Conditional Statements 1. if Statement The if statement checks a condition written inside parentheses. If the condition evaluates to true, the code inside {} is executed; otherwise, it is skipped. Executes code only when a specified condition is true. Useful for making simple decisions in a program. Syntax : if ( condition ) { // code runs if condition is true } let x = 20 ; if ( x % 2 === 0 ) { console . log ( " Even " ); } if ( x % 2 !== 0 ) { console . log ( " Odd " ); }; Output Even 2. if-else Statement The if-else statement executes one block of code if a condition is true and another block if it is false. It ensures that exactly one of the two code blocks runs. Used when there are two possible outcomes. The else block runs when the if condition is not satisfied. let age = 25 ; if ( age >= 18 ) { console . log ( " Adult " ) } else { console . log ( " Not an Adult " ) }; Output Adult 3. else if Statement The else if statement is used to test multiple conditions in sequence. It executes the first block whose condition evaluates to true. Allows checking more than two conditions. Evaluated from top to bottom until a true condition is found. const x = 0 ; if ( x > 0 ) { console . log ( " Positive. " ); } else if ( x < 0 ) { console . log ( " Negative. " ); } else { console . log ( " Zero. " ); }; Output Zero . 4. Using Switch Statement (JavaScript Switch Case) The switch statement evaluates an expression and executes the matching case block based on its value. It provides a clean and readable way to handle multiple conditions for a single varia
AI 资讯
The Top Golang Mocking Libraries in 2026: A Practical Comparison
Hello, I'm Shrijith Venkatramana. I'm building git-lrc, an AI code reviewer that runs on every commit. Star Us to help devs discover the project. Do give it a try and share your feedback for improving the product. A few years ago, choosing a Go mocking framework was mostly a matter of personal preference. Today, things are different. Most Go developers have at least one AI coding assistant generating tests alongside them. Some teams even generate the majority of their unit tests automatically. Yet one area remains surprisingly messy: mocks. Ask an LLM to write a test for the same interface and you'll often get completely different results depending on whether your project uses GoMock, Mockery, MockIO, Minimock, Moq, or hand-written test doubles. The problem isn't that the models are bad. The problem is that mocking libraries represent very different philosophies: Strict vs flexible Generated vs runtime-created DSL-heavy vs idiomatic Go Feature-rich vs minimalist In this article we'll compare the most popular Go mocking libraries in 2026, examine their strengths and weaknesses, and discuss which one may be the best fit for your project. What Makes a Good Mocking Library? Before comparing tools, it's worth defining what matters. A good mocking library should ideally provide: Easy mock generation Clear test failures Minimal boilerplate Strong refactoring support Good IDE experience Readable tests Reliable call verification Different libraries optimize for different parts of this list. That's why there is no universally correct answer. 1. GoMock: The Enterprise Workhorse GoMock remains one of the most widely used mocking frameworks in the Go ecosystem. Originally created by Google and now actively maintained by Uber, it has become the standard choice for many large organizations. Its philosophy is straightforward: define expectations explicitly and verify them rigorously. Example func TestUserService ( t * testing . T ) { ctrl := gomock . NewController ( t ) repo := New
AI 资讯
CRM for appointments
A client of mine is starting a business and needs a CRM. Core functionality is to manage different professionals and assign customers to professionals to make appointments and manage agenda for each professional. I will assist this business on the software side and I am fully capable of developing a custom CRM on my own but it’s not convenient for time/money constraints. I have looked for open source CRMs I can extend so I don’t waste time on UI and common features. Are there products which can save development time? I wanted to evaluate Calendly and integrate it in the final solution, do you have any experience with this product? I would also evaluate existing products but open source I can fork would be best submitted by /u/Umberto_Fontanazza [link] [留言]
AI 资讯
Wispr flow frozen my VS code this week switching to something else
I know I'm not the only one dealing with this because . l've seen other complaints. wispr flow on windows has been freezing my editor. I'll be mid-dictation and the whole thing locks up. not just wispr, but VS Code freezes too. have to force quit both. happened twice this week and one of those times I lost unsaved work because VS Code didn't recover the session properly. the app is electron based and it's eating 800MB of RAM while just sitting in the background doing nothing. my fans spin up when it's idle. for a dictation app. that's absurd. The mac version was fine when I used it on my MacBook but I'm primarily on a windows desktop and the experience there is clearly an afterthought. I've seen people on reddit call it a "mac app with a windows port" and that's generous. also the startup takes like 8-10 seconds. I'll hit my hotkey to start dictating and then wait. and wait. by the time it's ready I could have typed the message. I've been trying willow voice and so far no freezes, no RAM issues, starts instantly. comparable accuracy. anyone else on windows having these issues with wispr? submitted by /u/Ill_Accident_1116 [link] [留言]
产品设计
New to QR Code generation. How can I create a code that doesn't expire and can have the destination URL updated in the future?
New to QR Code generation. How can I create a code that doesn't expire and can have the destination URL updated in the future? Does this require a fee-based service? If so any recommendations? submitted by /u/tk2old [link] [留言]
AI 资讯
Made 30+ dev/marketing tools that run 100% in the browser - no backend, no tracking, no login
Quick share of something I built recently. I've been working on a SaaS product and along the way kept needing small utilities for myself: QR codes, UTM links, OG tag previews, schema markup, robots.txt, sitemap, base64/URL encoders, etc. Every site I found for these either required an account, was buried in ads, or made me wonder where my data was going. So I built clean versions and put them at reslug.com/tools . All free. No account. The interesting bit: every tool runs entirely client-side. The QR code generator never sends your WiFi password to a server. The UTM builder never logs your URLs. The schema generator outputs locally. The redirect checker is the only exception, since CORS forces a server proxy for that one (and it doesn't log the URLs it checks). Stack for the free tools: React 19 + Vite + TypeScript + Tailwind, qrcode library for QR generation, all rendered as pure components. Main product behind it is .NET 9 + Postgres but you'd never hit that from /tools. Why I'm posting: curious what's missing. I've got about 27 more tools planned but I'd rather build what people actually need. Also genuinely interested if anyone has feedback on the UI/UX - I rebuilt the hero last week and I'm not 100% sure it's better. https://reslug.com/tools submitted by /u/ervistrupja [link] [留言]
AI 资讯
I built a GitHub Action that reviews AI API costs on every PR — here's what it found in our own codebase
Been building an AI-heavy app for a few months. No visibility into what our AI API calls were actually costing until the Anthropic bill arrived. So I built a GitHub Action that scans for AI usage on every PR and posts a cost analysis comment automatically. First thing it caught in our own codebase: server/services/divergence-detector.js was using claude-sonnet-4-6 with max_tokens=150 to generate 2-sentence explanations. Sonnet costs $15/M output tokens. Haiku costs $4/M. For a 2-sentence output there is zero quality difference. We were paying 3.75x more on every single call and nobody noticed. What it posts on every PR: 💰 Cost delta vs base branch ( "this PR adds +$44/month" ) ⚠️ Warnings for expensive model misuse with specific fix recommendations 🔁 Duplicate AI call patterns that should share a service layer 🔄 Missing retry/backoff logic that will crash under rate limits 💡 Prompt caching opportunities (up to 90% input cost reduction) Supports: Languages: JS, TS, JSX, TSX Providers: Anthropic · OpenAI · Google Gemini · AWS Bedrock · LangChain Zero dependencies · Free Add it to any repo in 2 minutes: - uses: kavyarani7/ai-arch-scanner@v1 with: github_token: ${{ secrets.GITHUB_TOKEN }} threshold: '500' 🔗 GitHub Marketplace 🔗 Repo Happy to answer questions about how it works or what patterns it detects. submitted by /u/Upbeat_Will_3342 [link] [留言]
AI 资讯
Stop Hardcoding Roles: A Practical Guide to Roles, Permissions, and Scalable Authorization
We've all been there. Your first encounter with authorization looks something like this: if ( user . role === " ADMIN " ) { // allow access } It works. It's simple. It ships fast. And then, three months later, your application has grown, requirements have shifted, and you're staring at a codebase where authorization logic is scattered everywhere—APIs, services, UI components—like a puzzle that nobody remembers how to solve. The truth is: this approach doesn't scale. Not because it's inherently flawed, but because it conflates two very different concepts that should never be mixed. The Core Mistake: Confusing Identity with Capability Here's the problem we're actually trying to solve. As your application grows, you inevitably end up writing code like this: if ( user . role === " BRANCH_MANAGER " || user . role === " SYSTEM_ADMIN " ) { // allow access } Then a stakeholder asks: Can we create a hybrid role? Or: We need Auditors who can export reports but not edit records. And suddenly your role logic explodes into an unmaintainable mess. The fix isn't adding more conditions. The fix is understanding that roles and permissions answer fundamentally different questions. Roles Define Identity Roles are categories of users. Examples: SYSTEM_ADMIN CLIENT BRANCH_MANAGER AUDITOR Roles answer: Who is this user? They establish high-level authorization boundaries. Examples: Staff Portal vs Customer Portal Internal Admin Area vs Public Application Employee Features vs Client Features Think of roles as identity labels . Permissions Define Capability Permissions represent atomic actions. Examples: LOAN_APPROVE USER_DELETE REPORT_EXPORT ACCOUNT_EDIT Permissions answer: What can this user actually do? Your application should not constantly ask: What role are you? Instead, it should ask: Do you have permission to perform this action? Because: Users have Roles Roles contain Permissions Code checks Permissions That distinction changes everything. Always Decouple Identity from Capability T
开发者
How do I connect a Spring Boot API to a vanilla HTML/CSS/JS frontend
I’m learning Spring Boot and want to understand how to connect my backend API to a frontend using only vanilla HTML, CSS, and JavaScript first. What would be a good learning path and where can i start? submitted by /u/ThenParamedic4021 [link] [留言]
AI 资讯
Locators & Web-First Assertions (Playwright + TypeScript, Ch.3)
In Chapter 2 we wrote our first tests and hit two bugs. Before we add more, we need the one skill everything else rests on: finding elements reliably . Get this right and your tests survive redesigns; get it wrong and they break every sprint. Code for this chapter is tagged ch-03 in the repo: https://github.com/aktibaba/playwright-qa-course — see src/tests/ui/locators.spec.ts . Locate the way a user perceives The brittle instinct is to grab elements by their structure — CSS classes, nth-child , XPath. All of that changes the moment a developer touches the markup. Playwright's recommended locators instead target what a user (and a screen reader) perceives: the role, the label, the visible text. Use them in this order of preference: getByRole — the role + accessible name (covers the vast majority of cases) getByLabel — form fields by their <label> getByPlaceholder — inputs without a label getByText — non-interactive content getByTestId — a deliberate data-testid , only when nothing semantic fits Here's the top of the priority list, live against Inkwell's home page: import { test , expect } from " @playwright/test " ; test ( " prefer role-based locators over CSS " , async ({ page }) => { await page . goto ( " / " ); await expect ( page . getByRole ( " button " , { name : " Global Feed " })). toBeVisible (); await expect ( page . getByRole ( " link " , { name : " Sign up " })). toBeVisible (); await expect ( page . getByRole ( " heading " , { name : " inkwell " })). toBeVisible (); }); getByRole("button", { name: "Global Feed" }) asserts two things at once — that an element with the button role exists and that its accessible name is "Global Feed". If a dev swaps the <div class="feed-btn"> for a real <button> , this locator keeps working; a CSS selector wouldn't. Strict mode is your friend Playwright locators are strict : if a locator matches more than one element, the action throws instead of silently picking the first. That catches ambiguous tests before they pick the
AI 资讯
Setup & Your First UI + API Tests (Playwright + TypeScript, Ch.2)
In Chapter 1 we argued that automation fails from a lack of structure , not a lack of tooling — and we met Inkwell , the dockerized app we test against. Now we install Playwright + TypeScript and write our first UI and API tests, deliberately simple. We'll also hit two real bugs along the way. I'm leaving them in on purpose — they're the exact problems the framework we build later is designed to prevent. Code for this chapter is tagged ch-02 in the repo: https://github.com/aktibaba/playwright-qa-course Before you start Make sure Inkwell is running (from Chapter 1): cd sut docker compose up -d --build --wait # web :3000, api :3001/api Install Playwright + TypeScript From the repo root: npm install -D @playwright/test typescript @types/node npx playwright install chromium That's it — Playwright bundles its own test runner, assertion library, and TypeScript support. No extra config to make .ts test files work. A minimal config — not a framework yet Two small files keep us honest from day one. First, never hard-code URLs in tests — put them in one place: // src/utils/env.ts export const env = { /** Inkwell SPA (nginx) — the UI base URL. */ webURL : process . env . WEB_URL ?? " http://localhost:3000 " , /** Inkwell API base, including the /api prefix. */ apiURL : process . env . API_URL ?? " http://localhost:3001/api " , } as const ; Then the Playwright config. We split tests into two projects — a fast api project and a Chromium ui project — because API tests need no browser and should run in milliseconds: // playwright.config.ts import { defineConfig , devices } from " @playwright/test " ; import { env } from " ./src/utils/env " ; export default defineConfig ({ testDir : " ./src/tests " , fullyParallel : true , reporter : " list " , use : { trace : " on-first-retry " , screenshot : " only-on-failure " }, projects : [ { name : " api " , testDir : " ./src/tests/api " , use : { baseURL : env . apiURL } }, { name : " ui " , testDir : " ./src/tests/ui " , use : { baseURL : e
AI 资讯
How I Built a Free SEO Audit Tool with Next.js, Supabase, and Stripe in 1 Week
Last weekend I started building SiteGrade — a free instant SEO audit tool that gives any website an A–F letter grade and the top fixes ranked by impact. I just launched it. This post is the build log: the architecture decisions that worked, the ones that didn't, and the gotchas you'd save time knowing about. If you're considering building a similar audit/scanner tool, or just want to see what a 2026 Next.js + Supabase + Stripe stack looks like in practice, this should be useful. Why I built it I got tired of family and friends asking me "how's the SEO on my website?" and not having a good answer to send back. Every existing tool I tried either cost $99+/month (Ahrefs, Semrush) or threw 200 metrics at people who just wanted to know if their site was OK. The wedge I built around: one letter grade, three top fixes, plain English, no signup. The paid tier ($29/mo) re-audits weekly and emails the report so non-technical users can track improvements as their developer makes them. The stack Nothing exotic. Everything is the obvious choice for a 2026 indie SaaS, which is the whole point — boring stack means I spent zero time fighting infrastructure and 100% of my time on the actual audit logic. Next.js 14 App Router — frontend + API routes in one repo Supabase — Postgres + auth + RLS + file storage, EU-hosted for GDPR Stripe — subscriptions + Billing Portal + webhooks Resend — transactional email (audit reports, weekly reports, Supabase auth via Custom SMTP) Vercel — hosting + cron jobs for the weekly re-audit cheerio — HTML parsing for the audit checks Google PageSpeed Insights API — Core Web Vitals + mobile performance Total monthly infrastructure cost at zero traffic: ~$0 (everyone on free tiers). At 100 paying customers it'd still be under $30/mo. The audit logic — what 15 checks look like in code Each audit runs 15 checks and produces a score from 0-100, then maps that to a letter grade (A: 90+, B: 75+, C: 60+, D: 45+, F: below 45). The checks are structured as pure fu