<?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: John Ughiovhe</title>
    <description>The latest articles on DEV Community by John Ughiovhe (@johnughiovhe).</description>
    <link>https://dev.to/johnughiovhe</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%2F3978145%2F7934388c-e53b-4f4b-b5ae-1fcc09ae2468.jpeg</url>
      <title>DEV Community: John Ughiovhe</title>
      <link>https://dev.to/johnughiovhe</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/johnughiovhe"/>
    <language>en</language>
    <item>
      <title>The 16-Day System and the 3-Day Feature: Two Internship Tasks That Changed How I Think About Backend Engineering</title>
      <dc:creator>John Ughiovhe</dc:creator>
      <pubDate>Fri, 12 Jun 2026 02:25:46 +0000</pubDate>
      <link>https://dev.to/johnughiovhe/the-16-day-system-and-the-3-day-feature-two-internship-tasks-that-changed-how-i-think-about-1nn5</link>
      <guid>https://dev.to/johnughiovhe/the-16-day-system-and-the-3-day-feature-two-internship-tasks-that-changed-how-i-think-about-1nn5</guid>
      <description>&lt;p&gt;A reflection on two backend engineering internship projects that shaped my understanding of system design, API architecture, and working within existing codebases.&lt;/p&gt;

&lt;p&gt;When people ask what I worked on during my internship, the easiest answer is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I built APIs, authentication systems, and backend services."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Technically, that is true.&lt;/p&gt;

&lt;p&gt;But that answer misses the most important part.&lt;/p&gt;

&lt;p&gt;The most valuable lessons I learned didn't come from writing code. They came from dealing with complexity, making architectural decisions, and solving problems that were much bigger than they first appeared.&lt;/p&gt;

&lt;p&gt;Looking back, two tasks stand out more than any others.&lt;/p&gt;

&lt;p&gt;The first was &lt;strong&gt;Insighta Labs+&lt;/strong&gt;, a backend platform that took about &lt;strong&gt;16 days of active engineering effort across three progressive stages&lt;/strong&gt; and pushed me deeper into system design than anything I had worked on before.&lt;/p&gt;

&lt;p&gt;The second was building &lt;strong&gt;Funnel Display APIs for SEIL&lt;/strong&gt;, a feature that took about &lt;strong&gt;3 days of focused implementation&lt;/strong&gt; and taught me another important side of backend engineering: how to extend an existing system without breaking its foundation.&lt;/p&gt;

&lt;p&gt;One taught me how to build systems.&lt;/p&gt;

&lt;p&gt;The other taught me how to build within systems.&lt;/p&gt;

&lt;p&gt;Both changed how I approach backend engineering.&lt;/p&gt;




&lt;h2&gt;
  
  
  Task 1: Insighta Labs+ — Building One Backend for Multiple Interfaces
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Why I Picked This Project
&lt;/h2&gt;

&lt;p&gt;If I had to choose the project that stretched me the most during the internship, it would be Insighta Labs+.&lt;/p&gt;

&lt;p&gt;Not because it was simply a large project.&lt;/p&gt;

&lt;p&gt;Not because it used unfamiliar technologies.&lt;/p&gt;

&lt;p&gt;But because it forced me to think beyond individual endpoints.&lt;/p&gt;

&lt;p&gt;Across three stages and about &lt;strong&gt;16 active days of implementation&lt;/strong&gt;, I wasn't just building an API.&lt;/p&gt;

&lt;p&gt;I was building a backend platform that needed to support:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A web application&lt;/li&gt;
&lt;li&gt;A command-line interface (CLI)&lt;/li&gt;
&lt;li&gt;Multiple user roles&lt;/li&gt;
&lt;li&gt;Authentication and authorization&lt;/li&gt;
&lt;li&gt;Search workflows&lt;/li&gt;
&lt;li&gt;Data ingestion pipelines&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each stage built on the previous one.&lt;/p&gt;

&lt;p&gt;This meant early architectural decisions became foundations for everything that came after.&lt;/p&gt;

&lt;p&gt;The breaks between stages also gave time to review what was already built, identify weaknesses, and approach the next stage with a clearer understanding of the system.&lt;/p&gt;

&lt;p&gt;This was where I started seeing the difference between writing backend code and engineering backend systems.&lt;/p&gt;




&lt;h2&gt;
  
  
  What It Was
&lt;/h2&gt;

&lt;p&gt;Insighta Labs+ is a profile intelligence platform built around a shared backend architecture.&lt;/p&gt;

&lt;p&gt;The platform supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub OAuth authentication&lt;/li&gt;
&lt;li&gt;Profile intelligence workflows&lt;/li&gt;
&lt;li&gt;Role-based access control&lt;/li&gt;
&lt;li&gt;CSV profile uploads&lt;/li&gt;
&lt;li&gt;Search and filtering&lt;/li&gt;
&lt;li&gt;Data export&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The interesting part was not any single feature.&lt;/p&gt;

&lt;p&gt;The challenge was ensuring every interface depended on the same backend rules.&lt;/p&gt;

&lt;p&gt;A browser user and a CLI user should receive the same:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authentication behavior&lt;/li&gt;
&lt;li&gt;Authorization decisions&lt;/li&gt;
&lt;li&gt;Data consistency&lt;/li&gt;
&lt;li&gt;API responses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The backend had to become the single source of truth.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem It Was Solving
&lt;/h2&gt;

&lt;p&gt;One common problem in software systems is allowing different clients to slowly become different products.&lt;/p&gt;

&lt;p&gt;The web application starts implementing its own logic.&lt;/p&gt;

&lt;p&gt;The CLI starts duplicating behavior.&lt;/p&gt;

&lt;p&gt;Authentication rules become inconsistent.&lt;/p&gt;

&lt;p&gt;Eventually, nobody can confidently explain how the system actually works.&lt;/p&gt;

&lt;p&gt;The goal with Insighta Labs+ was to prevent that.&lt;/p&gt;

&lt;p&gt;The backend needed to own:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Business logic&lt;/li&gt;
&lt;li&gt;Authentication&lt;/li&gt;
&lt;li&gt;Authorization&lt;/li&gt;
&lt;li&gt;Search behavior&lt;/li&gt;
&lt;li&gt;Data access rules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every client should consume the backend instead of recreating it.&lt;/p&gt;




&lt;h2&gt;
  
  
  How I Approached It
&lt;/h2&gt;

&lt;p&gt;My approach was guided by one principle:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Every client should depend on the backend, not the other way around.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This affected every major decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authentication Across Web and CLI
&lt;/h2&gt;

&lt;p&gt;Supporting browser authentication was straightforward.&lt;/p&gt;

&lt;p&gt;Supporting CLI authentication was more interesting.&lt;/p&gt;

&lt;p&gt;The browser flow used traditional GitHub OAuth.&lt;/p&gt;

&lt;p&gt;The CLI flow required PKCE (Proof Key for Code Exchange), allowing secure authentication without exposing client secrets.&lt;/p&gt;

&lt;p&gt;The backend had to manage:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OAuth state&lt;/li&gt;
&lt;li&gt;PKCE verification&lt;/li&gt;
&lt;li&gt;Authorization code exchange&lt;/li&gt;
&lt;li&gt;Callback validation&lt;/li&gt;
&lt;li&gt;Session creation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A simple login feature became a system of interacting parts.&lt;/p&gt;




&lt;h2&gt;
  
  
  Secure Token Handling
&lt;/h2&gt;

&lt;p&gt;I avoided storing raw tokens directly.&lt;/p&gt;

&lt;p&gt;The system used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Opaque access tokens&lt;/li&gt;
&lt;li&gt;Refresh token rotation&lt;/li&gt;
&lt;li&gt;Token hashing&lt;/li&gt;
&lt;li&gt;Session lifecycle management&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal was to make authentication secure while keeping the developer experience predictable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Role-Based Authorization
&lt;/h2&gt;

&lt;p&gt;The platform supported different user roles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Analysts&lt;/li&gt;
&lt;li&gt;Administrators&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of scattering permission checks throughout the application, authorization was handled centrally.&lt;/p&gt;

&lt;p&gt;This made the system easier to maintain and reduced the chance of inconsistent access rules.&lt;/p&gt;




&lt;h2&gt;
  
  
  Natural Language Search
&lt;/h2&gt;

&lt;p&gt;One of the most interesting parts was building deterministic search.&lt;/p&gt;

&lt;p&gt;Instead of using AI models, I built a parser that could understand queries like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"young males from Nigeria"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and convert them into structured filters.&lt;/p&gt;

&lt;p&gt;The parser handled:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gender detection&lt;/li&gt;
&lt;li&gt;Age ranges&lt;/li&gt;
&lt;li&gt;Country extraction&lt;/li&gt;
&lt;li&gt;Validation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal wasn't to understand every possible sentence.&lt;/p&gt;

&lt;p&gt;The goal was to understand expected user intent reliably.&lt;/p&gt;




&lt;h2&gt;
  
  
  Performance Improvements
&lt;/h2&gt;

&lt;p&gt;As the system grew, repeated queries became expensive.&lt;/p&gt;

&lt;p&gt;To improve efficiency, I introduced:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Query normalization&lt;/li&gt;
&lt;li&gt;Cache key standardization&lt;/li&gt;
&lt;li&gt;Response caching&lt;/li&gt;
&lt;li&gt;Cache invalidation after updates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The challenge was not only making things faster.&lt;/p&gt;

&lt;p&gt;It was making them faster without serving outdated information.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Broke
&lt;/h2&gt;

&lt;p&gt;A lot.&lt;/p&gt;

&lt;p&gt;And that was where the real learning happened.&lt;/p&gt;

&lt;h2&gt;
  
  
  OAuth Complexity
&lt;/h2&gt;

&lt;p&gt;OAuth becomes significantly harder when supporting multiple clients.&lt;/p&gt;

&lt;p&gt;The browser flow and CLI flow introduced different requirements.&lt;/p&gt;

&lt;p&gt;Small mistakes in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Redirect URLs&lt;/li&gt;
&lt;li&gt;State validation&lt;/li&gt;
&lt;li&gt;Token exchange&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;could completely break authentication.&lt;/p&gt;




&lt;h2&gt;
  
  
  Search Edge Cases
&lt;/h2&gt;

&lt;p&gt;Users rarely search exactly how developers expect.&lt;/p&gt;

&lt;p&gt;Some queries created conflicting filters.&lt;/p&gt;

&lt;p&gt;Others were ambiguous.&lt;/p&gt;

&lt;p&gt;Instead of guessing, I made the parser fail clearly and predictably.&lt;/p&gt;




&lt;h2&gt;
  
  
  Cache Consistency
&lt;/h2&gt;

&lt;p&gt;Caching solved performance issues.&lt;/p&gt;

&lt;p&gt;But it introduced a new problem:&lt;/p&gt;

&lt;p&gt;How do you know when cached data is no longer correct?&lt;/p&gt;

&lt;p&gt;The solution was automatic cache invalidation after data mutations.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Took Away
&lt;/h2&gt;

&lt;p&gt;Insighta Labs+ changed my mindset.&lt;/p&gt;

&lt;p&gt;Before this project, I thought mainly in terms of features.&lt;/p&gt;

&lt;p&gt;After it, I started thinking in terms of systems.&lt;/p&gt;

&lt;p&gt;I learned:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authentication is a system, not just a login endpoint.&lt;/li&gt;
&lt;li&gt;Authorization is an architecture decision.&lt;/li&gt;
&lt;li&gt;Caching is a consistency problem.&lt;/li&gt;
&lt;li&gt;APIs become products when multiple clients depend on them.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Task 2: Funnel Display APIs — Building Features That Fit Existing Systems
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Why I Picked This Project
&lt;/h2&gt;

&lt;p&gt;Compared to Insighta Labs+, this task was smaller in scope and took about &lt;strong&gt;3 days of focused implementation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;But it represented another important side of backend engineering.&lt;/p&gt;

&lt;p&gt;In real-world teams, you rarely build everything from scratch.&lt;/p&gt;

&lt;p&gt;Most of the time, you are extending an existing codebase.&lt;/p&gt;

&lt;p&gt;The challenge is not just making your feature work.&lt;/p&gt;

&lt;p&gt;The challenge is making it belong.&lt;/p&gt;

&lt;p&gt;That is why I picked this project.&lt;/p&gt;




&lt;h2&gt;
  
  
  What It Was
&lt;/h2&gt;

&lt;p&gt;The Funnel Display API was a backend feature built for SEIL to expose funnel and stage information required by the frontend.&lt;/p&gt;

&lt;p&gt;The implementation introduced four authenticated endpoints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Retrieve available funnels&lt;/li&gt;
&lt;li&gt;Retrieve full funnel details&lt;/li&gt;
&lt;li&gt;Retrieve stages for a funnel&lt;/li&gt;
&lt;li&gt;Retrieve a specific stage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The work also included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Database migration&lt;/li&gt;
&lt;li&gt;Service logic&lt;/li&gt;
&lt;li&gt;Controller implementation&lt;/li&gt;
&lt;li&gt;Unit test updates&lt;/li&gt;
&lt;li&gt;Swagger documentation&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Problem It Was Solving
&lt;/h2&gt;

&lt;p&gt;The frontend needed a clean way to display funnel information.&lt;/p&gt;

&lt;p&gt;Instead of exposing database structures directly, the backend needed to provide meaningful product-level data.&lt;/p&gt;

&lt;p&gt;The API needed to answer questions like:&lt;/p&gt;

&lt;p&gt;"Show this user's funnel."&lt;/p&gt;

&lt;p&gt;"Show the stages inside this funnel."&lt;/p&gt;

&lt;p&gt;"Show details about this specific stage."&lt;/p&gt;

&lt;p&gt;The backend became the bridge between stored data and the user experience.&lt;/p&gt;




&lt;h2&gt;
  
  
  How I Approached It
&lt;/h2&gt;

&lt;p&gt;Before writing code, I studied the existing architecture.&lt;/p&gt;

&lt;p&gt;SEIL already had:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;NestJS&lt;/li&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;li&gt;PostgreSQL&lt;/li&gt;
&lt;li&gt;JWT authentication&lt;/li&gt;
&lt;li&gt;Repository-based data access&lt;/li&gt;
&lt;li&gt;Swagger documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal wasn't to introduce a new style.&lt;/p&gt;

&lt;p&gt;The goal was to follow the existing one.&lt;/p&gt;




&lt;h2&gt;
  
  
  Database Migration
&lt;/h2&gt;

&lt;p&gt;The first step was adding the required database structures.&lt;/p&gt;

&lt;p&gt;Instead of manually modifying the database, I created a migration.&lt;/p&gt;

&lt;p&gt;This made schema changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repeatable&lt;/li&gt;
&lt;li&gt;Version controlled&lt;/li&gt;
&lt;li&gt;Safe across environments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A database change is not just a database change.&lt;/p&gt;

&lt;p&gt;It becomes part of the application lifecycle.&lt;/p&gt;




&lt;h2&gt;
  
  
  API Design
&lt;/h2&gt;

&lt;p&gt;The endpoints were designed around frontend needs.&lt;/p&gt;

&lt;p&gt;A frontend does not think:&lt;/p&gt;

&lt;p&gt;"Return rows from the funnel table."&lt;/p&gt;

&lt;p&gt;It thinks:&lt;/p&gt;

&lt;p&gt;"Display this funnel and its progress."&lt;/p&gt;

&lt;p&gt;That difference influenced the API structure.&lt;/p&gt;

&lt;p&gt;The routes focused on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User ownership&lt;/li&gt;
&lt;li&gt;Authentication&lt;/li&gt;
&lt;li&gt;Meaningful responses&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Service Layer Design
&lt;/h2&gt;

&lt;p&gt;I kept responsibilities separated.&lt;/p&gt;

&lt;p&gt;Controllers handled:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Request handling&lt;/li&gt;
&lt;li&gt;Validation&lt;/li&gt;
&lt;li&gt;Responses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Services handled:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Business logic&lt;/li&gt;
&lt;li&gt;Data retrieval&lt;/li&gt;
&lt;li&gt;Rules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This made the feature easier to test and maintain.&lt;/p&gt;




&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;I updated unit tests to verify funnel service behavior.&lt;/p&gt;

&lt;p&gt;I also manually tested the endpoints through Swagger:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start the development server&lt;/li&gt;
&lt;li&gt;Authenticate with a JWT&lt;/li&gt;
&lt;li&gt;Call each endpoint&lt;/li&gt;
&lt;li&gt;Verify responses and status codes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The result was a frontend-ready API surface.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Broke
&lt;/h2&gt;

&lt;p&gt;The biggest challenge wasn't a failed build.&lt;/p&gt;

&lt;p&gt;It was ensuring the feature matched the existing system.&lt;/p&gt;

&lt;p&gt;A backend feature is not successful just because it works.&lt;/p&gt;

&lt;p&gt;It should feel like it was always part of the application.&lt;/p&gt;

&lt;p&gt;That meant paying attention to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Existing patterns&lt;/li&gt;
&lt;li&gt;Response formats&lt;/li&gt;
&lt;li&gt;Error handling&lt;/li&gt;
&lt;li&gt;Authentication rules&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What I Took Away
&lt;/h2&gt;

&lt;p&gt;This task taught me that backend engineering is also about integration.&lt;/p&gt;

&lt;p&gt;I learned:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Migrations are part of feature development.&lt;/li&gt;
&lt;li&gt;API design should reflect user actions.&lt;/li&gt;
&lt;li&gt;Existing architecture deserves respect.&lt;/li&gt;
&lt;li&gt;Good features fit naturally into systems.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;These two projects represented two different sides of backend engineering.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Insighta Labs+&lt;/strong&gt; taught me how to build systems that evolve across multiple stages, interfaces, and requirements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Funnel Display APIs&lt;/strong&gt; taught me how to contribute to an existing system and extend it safely.&lt;/p&gt;

&lt;p&gt;One required creating foundations that could support future growth.&lt;/p&gt;

&lt;p&gt;The other required understanding an existing foundation and building on top of it.&lt;/p&gt;

&lt;p&gt;Together, they reinforced a lesson I will carry forward:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A good backend engineer doesn't just write code. They understand the system they are changing and make that system better.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>backend</category>
      <category>softwareengineering</category>
      <category>internship</category>
    </item>
  </channel>
</rss>
