<?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>Forem: KitKeen</title>
    <description>The latest articles on Forem by KitKeen (@kitkeen_55).</description>
    <link>https://forem.com/kitkeen_55</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3848864%2F51829748-d666-494f-b67b-f6fd26fe4a3f.png</url>
      <title>Forem: KitKeen</title>
      <link>https://forem.com/kitkeen_55</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/kitkeen_55"/>
    <language>en</language>
    <item>
      <title>We had a bug in production for 16 days. It made more money than most features I've shipped.</title>
      <dc:creator>KitKeen</dc:creator>
      <pubDate>Fri, 03 Apr 2026 12:08:05 +0000</pubDate>
      <link>https://forem.com/kitkeen_55/we-had-a-bug-in-production-for-16-days-it-made-more-money-than-most-features-ive-shipped-2jci</link>
      <guid>https://forem.com/kitkeen_55/we-had-a-bug-in-production-for-16-days-it-made-more-money-than-most-features-ive-shipped-2jci</guid>
      <description>&lt;p&gt;Disclaimer: To keep my lawyers happy and respect my NDA, I’ve "randomized" the actual dollar amounts in this story. While the €350k+ figures are placeholders, the 73% growth and the "accidental" logic behind it are 100% real.&lt;/p&gt;




&lt;p&gt;+70% revenue. Not from a new feature. Not from a redesign. Not from a growth hack some PM spent three quarters planning.&lt;/p&gt;

&lt;p&gt;From a bug. A config error that sat in production for sixteen days, silently funnelling every new user in one of our European markets into the most expensive plan.&lt;/p&gt;

&lt;p&gt;When someone finally noticed, the team wanted a hotfix and a post-mortem. I wanted to see what's in the database.&lt;/p&gt;




&lt;h2&gt;
  
  
  5% vs 43%
&lt;/h2&gt;

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

&lt;p&gt;Before the bug, 5% of new users in that market picked the premium plan. That was the normal baseline. Everyone else scrolled down to the cheapest option and hit Continue.&lt;/p&gt;

&lt;p&gt;During the bug- when premium was the default- &lt;strong&gt;43% kept it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Forty-three percent.&lt;/p&gt;

&lt;p&gt;The onboarding screen wasn't hiding anything. The price was right there. "Change plan" was one click away. Nobody was forced into anything. Almost half the users just looked at the premium plan and thought: yeah, this works for me.&lt;/p&gt;

&lt;p&gt;I didn't believe it at first. Classic survivorship bias, right? They selected it, but did they actually pay?&lt;/p&gt;

&lt;p&gt;They did.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;About 40%&lt;/strong&gt; opened and activated their accounts&lt;/li&gt;
&lt;li&gt;Of those who stayed on the premium default, &lt;strong&gt;nearly half&lt;/strong&gt; made real payments within the first month.&lt;/li&gt;
&lt;li&gt;Only &lt;strong&gt;16%&lt;/strong&gt; downgraded later&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The funnel shape was identical to the control group. Same activation rate, same payment rate. The only thing that changed was how many people entered the premium funnel. And that number was &lt;strong&gt;nearly 9x higher&lt;/strong&gt; because of a bug.&lt;/p&gt;




&lt;h2&gt;
  
  
  The number no one expected
&lt;/h2&gt;

&lt;p&gt;I pulled the revenue numbers for both cohorts over the same period.&lt;/p&gt;

&lt;p&gt;Normal users: &lt;strong&gt;~€340,000/month.&lt;/strong&gt;&lt;br&gt;
Bug users: &lt;strong&gt;~€590,000/month.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Over 70% uplift.&lt;/strong&gt; Same product. The only difference was which plan showed up first.&lt;/p&gt;

&lt;p&gt;Let that sink in. A config error- an actual production defect- generated more incremental revenue than entire features that took months to build.&lt;/p&gt;


&lt;h2&gt;
  
  
  I didn't file a post-mortem. I filed a proposal.
&lt;/h2&gt;

&lt;p&gt;This is where most stories end. Bug found, bug fixed, regression test added, everyone moves on. That's what a responsible engineer does.&lt;/p&gt;

&lt;p&gt;I did the irresponsible thing. I went to the product team and said: don't fix this. Let me turn it into a controlled experiment.&lt;/p&gt;

&lt;p&gt;The bug had accidentally created a perfect A/B test- no controls, no tracking, no consent framework, but a screaming signal. If we could reproduce it properly- with feature flags, per-country segmentation, and real cohort tracking- we'd know whether this was noise or an actual insight about how users make decisions.&lt;/p&gt;

&lt;p&gt;They said yes.&lt;/p&gt;


&lt;h2&gt;
  
  
  The implementation
&lt;/h2&gt;

&lt;p&gt;The whole thing was embarrassingly simple.&lt;/p&gt;

&lt;p&gt;A feature-toggled tariff resolver that runs at registration time. Three conditions checked in sequence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;resolveTariff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;not&lt;/span&gt; &lt;span class="nx"&gt;experiment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isEnabled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;defaultPlan&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;not&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;experiment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;targetSegments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;defaultPlan&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;experiment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;plan&lt;/span&gt;    &lt;span class="c1"&gt;// premium&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If any condition fails- default plan. No impact on anyone outside the experiment. No latency. A few in-memory lookups against cached config.&lt;/p&gt;

&lt;p&gt;Each country had its own toggle. Kill one market without touching another. Add a new country without a deploy- just a config change.&lt;/p&gt;

&lt;p&gt;That's it. That's the whole feature. A senior engineer could review this in ten minutes. A junior could build it in a day.&lt;/p&gt;

&lt;p&gt;The hard part was never the code. The hard part was not fixing the bug.&lt;/p&gt;




&lt;h2&gt;
  
  
  It worked. Again.
&lt;/h2&gt;

&lt;p&gt;The original market went first- we already had the accidental baseline. The experiment ran for a full billing cycle: real payments, not just plan selections.&lt;/p&gt;

&lt;p&gt;The 43% selection rate from the bug period reproduced almost exactly under controlled conditions. Revenue uplift held.&lt;/p&gt;

&lt;p&gt;We expanded to a second European market. Same results.&lt;/p&gt;

&lt;p&gt;The product team's conclusion:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"The experiment was rather successful. We make the premium plan the recommended default during onboarding. We start the A/B experiment in the next market to check whether we'll get the same effect."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The "experiment" became the default. The feature flag stayed- as a kill switch, not an experiment.&lt;/p&gt;




&lt;h2&gt;
  
  
  What this actually taught me
&lt;/h2&gt;

&lt;p&gt;I've shipped features with months of work behind them that moved metrics by low single digits. This one was a three-condition &lt;code&gt;if&lt;/code&gt; statement that moved revenue by more than 70%.&lt;/p&gt;

&lt;p&gt;There's a lesson here that most backend engineers never learn, because we're trained to think our value is in the complexity of what we build. Distributed systems, event sourcing, saga patterns, microservice choreography- that's the hard stuff, and the hard stuff is what matters. Right?&lt;/p&gt;

&lt;p&gt;Wrong. The most impactful thing I did that year was stare at a SQL query for twenty minutes. The code I wrote afterward was trivial. A junior could do it. What a junior couldn't do- and what most seniors don't do- is pause before the fix and ask: &lt;em&gt;what is the bug actually telling us?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Every production incident has a signal in it. Most of the time the signal is: something is broken, fix it. But occasionally- rarely- the signal is: your assumptions about user behaviour are wrong, and the bug just proved it.&lt;/p&gt;

&lt;p&gt;No product manager would have proposed "show every user the most expensive plan by default." It sounds predatory. It sounds like a dark pattern. Except the data shows the opposite- users weren't tricked. They made informed decisions. They just needed better defaults.&lt;/p&gt;




&lt;h2&gt;
  
  
  The uncomfortable takeaway
&lt;/h2&gt;

&lt;p&gt;If you're a backend engineer and you've never looked at the business impact of your code- you're flying blind.&lt;/p&gt;

&lt;p&gt;Not because revenue is your job. It's not. But because understanding what your code &lt;em&gt;does to the business&lt;/em&gt; changes the kind of decisions you make. It's the difference between "I fixed the bug" and "I found a pricing insight worth millions a year."&lt;/p&gt;

&lt;p&gt;I could have closed the ticket in an hour. Instead, I spent a day in the data, wrote a proposal, and changed the default pricing strategy across multiple markets.&lt;/p&gt;

&lt;p&gt;The code was the easiest part. The observation was the whole thing.&lt;/p&gt;

</description>
      <category>fintech</category>
      <category>webdev</category>
      <category>programming</category>
      <category>career</category>
    </item>
    <item>
      <title>Building a KYC questionnaire that knows what the regulator will ask before they ask it</title>
      <dc:creator>KitKeen</dc:creator>
      <pubDate>Sun, 29 Mar 2026 10:06:39 +0000</pubDate>
      <link>https://forem.com/kitkeen_55/building-a-kyc-questionnaire-that-knows-what-the-regulator-will-ask-before-they-ask-it-3bd7</link>
      <guid>https://forem.com/kitkeen_55/building-a-kyc-questionnaire-that-knows-what-the-regulator-will-ask-before-they-ask-it-3bd7</guid>
      <description>&lt;p&gt;If you've never worked in fintech: KYC stands for Know Your Customer. It's the legal requirement for financial institutions to verify who their customers are before providing services. Anti-money laundering, fraud prevention, sanctions screening - all of it starts with KYC. When a business opens an account, the bank needs to understand what that business does, where its money comes from, and whether it poses any compliance risk.&lt;/p&gt;

&lt;p&gt;Before this feature shipped, a new business customer could complete onboarding, submit their application - and then wait for the banking partner's compliance team to start asking questions.&lt;/p&gt;

&lt;p&gt;Our banking partner performs compliance reviews on all new business accounts. As part of that review, their compliance team would send questions about business activity, industry type, international transactions, licensing, certifications. The customer would answer. Sometimes the partner would come back with another round. Multiple rounds of back-and-forth, each round adding days to the timeline.&lt;/p&gt;

&lt;p&gt;The critical detail: these questions weren't random. The compliance team asked them based on the customer's industry. A restaurant got asked about cash handling. A financial intermediary got asked about cross-border transaction volumes. A construction company got asked about subcontractors. An IT consultancy got asked about data processing agreements. The questions were predictable. We just weren't collecting the answers before the partner asked for them.&lt;/p&gt;

&lt;p&gt;The solution was to intercept the question-answer cycle before it started. Collect the compliance questions during onboarding - before the review even begins - so when the application lands at the banking partner, the answers are already there.&lt;/p&gt;




&lt;h2&gt;
  
  
  The problem with "right questions"
&lt;/h2&gt;

&lt;p&gt;Not every business needs to answer the same questions. A software consultancy and a money services company have very different compliance profiles. Asking the same 30 questions to everyone wastes the customer's time and produces noise in the compliance review.&lt;/p&gt;

&lt;p&gt;The questionnaire had to be adaptive. The question set for each customer is determined by their industry classification - in Europe, that's the NACE code. Think of it as a standardised label for what a company does: restaurants, software development, financial services, construction, logistics, etc. Every registered business has one.&lt;/p&gt;

&lt;p&gt;Each industry classification maps to a specific set of question groups. A money transfer business gets questions about transaction monitoring and correspondent banking. A restaurant gets questions about cash revenue ratios. An e-commerce company gets questions about chargebacks and payment providers. One industry might require a dozen groups, another might need half that. The question set is assembled at generation time based on this mapping, not hardcoded per customer.&lt;/p&gt;




&lt;h2&gt;
  
  
  The question hierarchy
&lt;/h2&gt;

&lt;p&gt;Questions aren't flat. Many have sub-questions that only make sense given a specific answer.&lt;/p&gt;

&lt;p&gt;"Does your company conduct business internationally?" has a follow-up question about destination countries - but only if the answer is yes. Asking about destination countries when the answer is no creates noise and confuses customers.&lt;/p&gt;

&lt;p&gt;We model this with decimal question numbers. Question 1 is a parent. Questions 1.1 and 1.2 are its children. The hierarchy is encoded in the decimal, not in a separate parent-child field.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Question 1: Does your company conduct business internationally? (Bool)
  Question 1.1: If yes, which countries? (Text) - Condition: true
  Question 1.2: If no, why not? (Text) - Condition: false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At submission time, the validator prunes the tree. If the customer answers "no" to question 1, question 1.1 is removed from the contract before storage. The customer never sees questions that don't apply to them, and the stored answers form a clean, consistent set.&lt;/p&gt;

&lt;p&gt;Some questions are container nodes - they exist to define the hierarchy but are never shown to the user. Only leaf questions generate actual form inputs. A boolean flag on each question distinguishes containers from visible inputs.&lt;/p&gt;




&lt;h2&gt;
  
  
  One group per step
&lt;/h2&gt;

&lt;p&gt;The questionnaire can span multiple question groups depending on industry. Rather than dumping everything on one screen, each question group is a separate onboarding step.&lt;/p&gt;

&lt;p&gt;A customer sees their progress at the top - "Step 3 of 7" or "Step 5 of 12" depending on the industry. Each step is independently validated and submitted. Answers are stored per-step. The customer can stop mid-questionnaire and resume later without losing progress. Completed steps are marked hidden - the answers are preserved for the compliance audit trail, but the customer can't edit them after submission.&lt;/p&gt;

&lt;p&gt;The routing logic tracks which compliance steps are still pending. When the customer completes a step, it finds the next incomplete one and routes there. When all compliance steps are done, onboarding picks up from where it left off.&lt;/p&gt;




&lt;h2&gt;
  
  
  Preventing duplicates
&lt;/h2&gt;

&lt;p&gt;Question generation runs once per customer. But onboarding flows have concurrent paths - multiple events can trigger at the same time, and we had to ensure we didn't generate duplicate question sets.&lt;/p&gt;

&lt;p&gt;Two layers of protection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────┐
│              Generate questionnaire request              │
└──────────────────────┬──────────────────────────────────┘
                       │
                       ▼
              ┌─────────────────┐     YES
              │  Cache lock set? ├────────────► Drop request
              └────────┬────────┘
                  NO   │
                       ▼
             Set cache lock (short TTL)
                       │
                       ▼
          ┌────────────────────────┐     YES
          │  Completion flag set?  ├────────────► Drop request
          └────────────┬───────────┘
                  NO   │
                       ▼
             Generate questions
                       │
                       ▼
           Set completion flag (persistent)
                       │
                       ▼
                    Done ✓
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, a distributed cache lock with a short TTL using set-if-not-exists semantics. The first request to generate the questionnaire for a given onboarding ID wins. Concurrent requests within the TTL window are dropped.&lt;/p&gt;

&lt;p&gt;Second, a persistent completion flag written to the onboarding metadata after generation completes. Even if the cache expires, the flag prevents re-generation.&lt;/p&gt;




&lt;h2&gt;
  
  
  The rollout
&lt;/h2&gt;

&lt;p&gt;We didn't enable this for all customers at once. The feature was introduced during an ongoing product with existing customers, and asking existing customers to answer compliance questions mid-flight would have been disruptive.&lt;/p&gt;

&lt;p&gt;Two feature toggles controlled the rollout. The first controls eligibility by customer creation date - customers created before the launch date are excluded. Hard boundary, no percentage, no A/B. The second controls traffic within eligible customers - started at 0%, increased gradually as we validated the system in production. The two toggles are independent: scope (who is eligible) and volume (what percentage see it) are controlled separately.&lt;/p&gt;




&lt;h2&gt;
  
  
  The numbers
&lt;/h2&gt;

&lt;p&gt;Thousands of customers completed the questionnaire during the rollout period.&lt;/p&gt;

&lt;p&gt;The banking partner's compliance review started with all required information already in the application. No rounds of questions. No waiting for customer responses. The back-and-forth that previously stretched across days of email exchanges was replaced by a single session during onboarding - at the point where the customer was already engaged and focused on getting their account open.&lt;/p&gt;

&lt;p&gt;The technical work - industry-based question mapping, conditional logic, multi-step navigation, distributed deduplication - existed to serve one outcome: anticipating what the regulator would ask, and collecting those answers before the review even began.&lt;/p&gt;




&lt;h2&gt;
  
  
  What changed in the code
&lt;/h2&gt;

&lt;p&gt;Before this feature, question generation was a static config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Before: same questions for every customer&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;questions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LoadDefaultComplianceQuestions&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nc"&gt;SendToPartner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;application&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;questions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Partner replies: "We also need to know about X, Y, Z"&lt;/span&gt;
&lt;span class="c1"&gt;// Customer gets emailed. Waits. Answers. Waits again.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// After: industry-adaptive generation&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;industry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GetIndustryClassification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;questionGroups&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MapIndustryToQuestionGroups&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;industry&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;tree&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BuildConditionalTree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;questionGroups&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Customer answers during onboarding&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;answers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CollectAnswersDuringOnboarding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tree&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;pruned&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PruneByConditions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tree&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;answers&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nc"&gt;SendToPartner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;application&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pruned&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Partner receives complete data. No follow-up needed.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The difference in flow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BEFORE:
Customer → Submit app → Partner reviews → Questions round 1
→ Customer replies (days) → More questions → Customer replies (days)
→ Approved
Total: days to weeks of back-and-forth

AFTER:
Customer → Answer compliance questions during onboarding → Submit app
→ Partner reviews (answers already attached) → Approved
Total: single onboarding session
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No new infrastructure. No external dependencies. Just a question mapping layer, a conditional tree, and a deduplication guard - inserted into the existing onboarding pipeline.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>fintech</category>
      <category>architecture</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
