<?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: Ahad Nawaz</title>
    <description>The latest articles on DEV Community by Ahad Nawaz (@ahadnawaz).</description>
    <link>https://dev.to/ahadnawaz</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%2F3957161%2F58d923a4-3602-4a23-ad42-bfc2f543b6ce.png</url>
      <title>DEV Community: Ahad Nawaz</title>
      <link>https://dev.to/ahadnawaz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ahadnawaz"/>
    <language>en</language>
    <item>
      <title>Running a Software Company While Finishing a CS Degree: What Actually Works</title>
      <dc:creator>Ahad Nawaz</dc:creator>
      <pubDate>Thu, 28 May 2026 19:04:41 +0000</pubDate>
      <link>https://dev.to/ahadnawaz/running-a-software-company-while-finishing-a-cs-degree-what-actually-works-jn3</link>
      <guid>https://dev.to/ahadnawaz/running-a-software-company-while-finishing-a-cs-degree-what-actually-works-jn3</guid>
      <description>&lt;p&gt;I have a client call at 9am. A university exam at 11am. A sprint review at 3pm.&lt;/p&gt;

&lt;p&gt;This is a regular Tuesday for me.&lt;/p&gt;

&lt;p&gt;I am a final year CS student at Lahore Garrison University and the Founder and CEO of REIVEX Technologies. I have shipped 20 plus products across those two tracks, for 15 plus companies, while sitting in the same lectures everyone else is sitting in.&lt;/p&gt;

&lt;p&gt;People ask me how I manage both. Here is the honest answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  You Do Not Manage It. You Choose What to Sacrifice.
&lt;/h2&gt;

&lt;p&gt;There is no productivity system that makes running a company and finishing a degree feel easy. Anyone telling you otherwise is either not doing both seriously or not being honest with you.&lt;/p&gt;

&lt;p&gt;What you can do is be deliberate about what you are willing to deprioritize. Social events get cut first. Perfect assignment scores get traded for good enough. Sleep gets protected because without it, both work and study quality collapse.&lt;/p&gt;

&lt;p&gt;The choice is not whether to sacrifice something. The choice is what to sacrifice and whether you are okay with that.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Practical Reality of the Calendar
&lt;/h2&gt;

&lt;p&gt;I treat my calendar as a single unified system, not as two separate systems for uni and work. Every commitment, exam, deadline, client call, and sprint goes into one place.&lt;/p&gt;

&lt;p&gt;When a client asks for a meeting, I look at my actual calendar before I agree. If there is an exam that week, I tell them I can meet after. Most professional clients respect this once you are transparent about it.&lt;/p&gt;

&lt;p&gt;The mistake most student founders make is double booking themselves and then failing to deliver on one side. Transparency about constraints is not weakness. It is professionalism.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lectures as Forced Context Switching
&lt;/h2&gt;

&lt;p&gt;I used to see lectures as interruptions. Then I realized they are scheduled context switching, which is actually useful.&lt;/p&gt;

&lt;p&gt;A 90 minute lecture forces you to step away from the code, sit with a completely different problem, and engage a different part of your brain. I come back from lectures with fresh eyes on things I was stuck on before.&lt;/p&gt;

&lt;p&gt;The academic content also matters more than I expected. Data structures and algorithms directly improved how I think about query optimization in my ERPs. Operating systems concepts improved how I think about concurrency in Node.js applications. The theory connects to the practice more than it seems in the moment.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Handle Client Expectations
&lt;/h2&gt;

&lt;p&gt;Every new client conversation I have starts with me being explicit about my situation. I am a student who also runs a company. I work differently from an agency. I am available at specific hours. My response time has a floor and a ceiling that I can tell them up front.&lt;/p&gt;

&lt;p&gt;This filters out clients who want someone available 24 hours a day and retains clients who want someone who delivers. The filtering is good. I do not want the clients I filter out.&lt;/p&gt;

&lt;p&gt;I also charge appropriately. Undercharging to compensate for constraints is a trap. It attracts more demanding clients, creates more stress, and builds a business you will not want to continue after you graduate.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Technical Edge of Being Both a Student and a Builder
&lt;/h2&gt;

&lt;p&gt;There is a real advantage to learning theory and practice simultaneously. When a professor explains database normalization, I have a live production database in my head where those rules apply or are being violated. The theory becomes immediately meaningful.&lt;/p&gt;

&lt;p&gt;When I hit a production problem, I have access to faculty and peers who can engage with it at a conceptual level. Not as consultants, but as sounding boards.&lt;/p&gt;

&lt;p&gt;This combination is temporary. After graduation, you either become a full time practitioner who reads papers occasionally, or a researcher who writes code occasionally. Right now I am both at once. I am trying to get as much out of it as possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Would Tell Someone Starting This Path
&lt;/h2&gt;

&lt;p&gt;Build your first real project in your first year, not after you graduate. Wait and you will keep waiting. The right time to start building is when you have enough knowledge to be dangerous, which comes earlier than you think.&lt;/p&gt;

&lt;p&gt;Pick clients carefully. One client who respects your time is worth five who do not. The damage a bad client does to your ability to study and ship quality work is not worth the revenue.&lt;/p&gt;

&lt;p&gt;Do not let either track become a performance. Some students do the startup as a resume item without really building anything. Some founders keep enrolling without really engaging with the degree. Both are wasted opportunities. If you are going to do both, do both for real.&lt;/p&gt;

&lt;p&gt;Keep your code quality high even when you are under pressure. Technical debt accumulated during busy weeks compounds into systems that are hard to maintain and embarrassing to show. Future you will need to extend what present you is building.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Part Nobody Talks About
&lt;/h2&gt;

&lt;p&gt;There are weeks where it is genuinely hard. Where a production system breaks at the same time as a group project is due and you have to make a call about which one gets your full attention that evening.&lt;/p&gt;

&lt;p&gt;You will make calls you are not happy with. You will apologize to clients. You will hand in assignments that are not your best work. That is the reality.&lt;/p&gt;

&lt;p&gt;But there are also weeks where you ship something real, present it to a client, and then walk into an exam on the underlying theory of how it works. That feeling of applied competence is something you cannot manufacture after the fact.&lt;/p&gt;

&lt;p&gt;Most people do not start building until after they graduate. I started during. That head start does not disappear when the degree ends.&lt;/p&gt;




&lt;p&gt;I am Ahad, Founder of REIVEX Technologies and a final year CS student. If you are in a similar situation or want to talk about building software companies early, find me at ahadnawaz.dev.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>NestJS Architecture Patterns I Use in Every Production Backend</title>
      <dc:creator>Ahad Nawaz</dc:creator>
      <pubDate>Thu, 28 May 2026 18:54:55 +0000</pubDate>
      <link>https://dev.to/ahadnawaz/nestjs-architecture-patterns-i-use-in-every-production-backend-40h2</link>
      <guid>https://dev.to/ahadnawaz/nestjs-architecture-patterns-i-use-in-every-production-backend-40h2</guid>
      <description>&lt;p&gt;I have built production backends for ERP platforms, AI tools, real estate applications, e-commerce systems, and online marketplaces. They run on different infrastructure, serve different users, and solve different problems.&lt;/p&gt;

&lt;p&gt;They all share the same architectural patterns.&lt;/p&gt;

&lt;p&gt;Not because I am inflexible. Because these patterns solve the problems that every production backend eventually faces. Here is what I use and why.&lt;/p&gt;

&lt;h2&gt;
  
  
  Global Exception Filter
&lt;/h2&gt;

&lt;p&gt;The first thing I add to every NestJS project is a global exception filter. Every unhandled error in the application flows through it.&lt;/p&gt;

&lt;p&gt;It does three things: logs the full error with context, maps the error to an appropriate HTTP status code, and returns a consistent error response structure to the client.&lt;/p&gt;

&lt;p&gt;Why this matters: without a global exception filter, error responses are inconsistent. Some endpoints return stack traces in development. Some return empty 500s in production. Frontend engineers cannot write reliable error handling code because the shape of the error response varies by endpoint.&lt;/p&gt;

&lt;p&gt;A consistent error structure like { success: false, message: string, code: string } across every endpoint makes the entire API predictable and makes frontend error handling trivial.&lt;/p&gt;

&lt;h2&gt;
  
  
  Request Logging Interceptor
&lt;/h2&gt;

&lt;p&gt;Every incoming request and outgoing response gets logged with: timestamp, method, path, status code, duration, and user ID if the request is authenticated.&lt;/p&gt;

&lt;p&gt;This is not optional for a production system. When something goes wrong in production, the first question is always what did the user do and what did the system respond. Without request logs you are guessing.&lt;/p&gt;

&lt;p&gt;I use a NestJS interceptor for this, not middleware, because interceptors have access to the response after it has been processed, which lets you log the status code and duration alongside the request details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Repository Pattern for Data Access
&lt;/h2&gt;

&lt;p&gt;I do not put database queries directly in service classes. Every entity has a repository class that owns all database interactions for that entity.&lt;/p&gt;

&lt;p&gt;The service layer calls the repository. The controller calls the service. The controller knows nothing about the database. The service knows nothing about the HTTP layer.&lt;/p&gt;

&lt;p&gt;This separation matters for three reasons. It makes unit testing possible without spinning up a real database. It makes it easy to swap out the underlying ORM or query builder without touching business logic. And it forces you to think about data access patterns explicitly rather than scattering ad hoc queries throughout the codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  DTOs and Class Validator for Every Input
&lt;/h2&gt;

&lt;p&gt;Every endpoint that accepts input has a DTO class decorated with class-validator constraints. Validation runs before the handler ever executes.&lt;/p&gt;

&lt;p&gt;This is not just about security, though it is that too. It is about trust. If your handler receives a DTO, you know it is valid. You do not need to check if email is a valid email address inside your service. That check already happened.&lt;/p&gt;

&lt;p&gt;I use class-transformer alongside class-validator to automatically strip unknown properties from incoming requests. Users cannot send extra fields that your DTO does not define. This prevents a class of injection bugs that are otherwise easy to miss.&lt;/p&gt;

&lt;h2&gt;
  
  
  Standardized API Response Wrapper
&lt;/h2&gt;

&lt;p&gt;All successful API responses follow the same structure: { success: true, data: T, meta?: PaginationMeta }.&lt;/p&gt;

&lt;p&gt;I implement this with a response interceptor that wraps the handler return value automatically. Controllers return plain objects or arrays. The interceptor wraps them.&lt;/p&gt;

&lt;p&gt;The meta field carries pagination information for list endpoints: total count, page number, page size, and total pages. This is always calculated server side and always included when returning a list, even if the list is not paginated. It makes adding pagination later a non breaking change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authentication and Authorization Architecture
&lt;/h2&gt;

&lt;p&gt;Authentication is handled by a JWT guard that validates the token, decodes the payload, and attaches the user to the request object.&lt;/p&gt;

&lt;p&gt;Authorization is handled separately through a roles guard and a permissions guard. The roles guard checks coarse grained access: is this user an admin, a manager, a standard user. The permissions guard checks fine grained access: does this user have permission to perform this specific action on this specific resource.&lt;/p&gt;

&lt;p&gt;Separating authentication from authorization like this keeps the code clean and makes it possible to update the authorization logic without touching authentication, and vice versa.&lt;/p&gt;

&lt;p&gt;I decorate routes with both the required role and the required permission. If either check fails, the request gets a 403. If authentication fails, it gets a 401. The HTTP status codes are semantically correct, which matters for frontend error handling.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuration Module
&lt;/h2&gt;

&lt;p&gt;All configuration comes from environment variables, validated at startup using a schema. If a required environment variable is missing or malformed, the application refuses to start.&lt;/p&gt;

&lt;p&gt;This is a forcing function for good deployment hygiene. You cannot accidentally deploy to production with a missing database URL because the application will not start without one. Every configuration error surfaces at startup, not at the moment a user triggers the code path that needs it.&lt;/p&gt;

&lt;p&gt;I use NestJS ConfigModule with a Joi validation schema. The schema documents exactly what environment variables the application requires, which is also useful onboarding documentation for new engineers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Health Check Endpoint
&lt;/h2&gt;

&lt;p&gt;Every backend I ship has a /health endpoint that returns the status of the application and its critical dependencies: database connectivity, cache connectivity, and any external APIs that the application depends on.&lt;/p&gt;

&lt;p&gt;This is used by load balancers and uptime monitoring. It is also the first place to look when something is wrong. If the database check fails on the health endpoint, you know where to look before you start digging through logs.&lt;/p&gt;

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

&lt;p&gt;All schema changes go through migration files, never direct database modifications. Migrations run automatically on deployment before the new application code starts.&lt;/p&gt;

&lt;p&gt;Every migration is written to be reversible where possible. I test rollbacks before shipping to production. This means that if a deployment causes issues, you can roll back the code and roll back the schema change without manual intervention.&lt;/p&gt;

&lt;p&gt;For large tables, I use additive migrations first: add the new column, deploy the code that handles both old and new states, then run the migration to drop the old column. This avoids locking production tables on write heavy systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why These Patterns and Not Others
&lt;/h2&gt;

&lt;p&gt;These are not the only valid patterns. They are the ones that have consistently made my codebases easier to maintain, debug, and extend across multiple projects and multiple engineers.&lt;/p&gt;

&lt;p&gt;The common thread is explicitness. Each pattern makes something explicit that would otherwise be implicit: what errors can happen, what inputs are valid, who has access to what, what the application requires to run. Explicit systems are easier to reason about and easier to fix when something goes wrong.&lt;/p&gt;

&lt;p&gt;Start with the global exception filter and the request logger. Add the rest as your application grows. These are investments in maintainability that pay back quickly.&lt;/p&gt;




&lt;p&gt;I am Ahad, Founder of REIVEX Technologies. I write about backend architecture, full stack engineering, and shipping production software fast. Find me at ahadnawaz.dev.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Integrate AI and LLMs into Production Web Apps (Lessons from the Field)</title>
      <dc:creator>Ahad Nawaz</dc:creator>
      <pubDate>Thu, 28 May 2026 18:42:55 +0000</pubDate>
      <link>https://dev.to/ahadnawaz/how-to-integrate-ai-and-llms-into-production-web-apps-lessons-from-the-field-4nj5</link>
      <guid>https://dev.to/ahadnawaz/how-to-integrate-ai-and-llms-into-production-web-apps-lessons-from-the-field-4nj5</guid>
      <description>&lt;p&gt;Everyone is adding AI to their product right now. Most of them are doing it wrong.&lt;/p&gt;

&lt;p&gt;Not because they chose the wrong model. Not because they used the wrong library. But because they treated AI integration like a regular feature and skipped all the engineering discipline that production systems require.&lt;/p&gt;

&lt;p&gt;I have integrated LLMs into multiple production applications. This is what I wish I had known before I started.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Mental Model Shift You Need First
&lt;/h2&gt;

&lt;p&gt;A traditional API call is deterministic. You send a request, you get a predictable response. You can write tests against it. You can cache it. You can reason about it.&lt;/p&gt;

&lt;p&gt;An LLM call is not deterministic. The same input can produce different outputs on different runs. The model can refuse, hallucinate, or return output in a format you did not expect. Your system needs to be designed around this reality, not in spite of it.&lt;/p&gt;

&lt;p&gt;This means defensive parsing, fallback logic, output validation, and graceful degradation are not optional extras. They are the core of the feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing the Right Model for the Right Job
&lt;/h2&gt;

&lt;p&gt;The biggest LLMs are not always the right choice. I learned this building EditDeck Pro, an AI creative platform for music.&lt;/p&gt;

&lt;p&gt;Some tasks needed a large frontier model for nuanced creative output. Others needed a fast, cheap model that could run many times per session without accumulating significant latency or cost.&lt;/p&gt;

&lt;p&gt;The pattern that works:&lt;/p&gt;

&lt;p&gt;Use a lighter model for classification, extraction, and short structured outputs. Use a larger model for generation tasks where quality matters more than speed. Route dynamically between them based on the task type.&lt;/p&gt;

&lt;p&gt;This can reduce your inference costs by 60 to 80 percent on workloads that mix simple and complex tasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prompt Engineering Is Software Engineering
&lt;/h2&gt;

&lt;p&gt;Prompts are code. They should be versioned, tested, and reviewed like code.&lt;/p&gt;

&lt;p&gt;I store prompts in a dedicated module with version numbers. When I change a prompt I run it against a fixed evaluation set of inputs and compare the outputs to the previous version. If the quality drops on any test case, the change does not ship.&lt;/p&gt;

&lt;p&gt;This sounds like overhead. It is not. Prompts drift over time as you iterate. Without a system to track changes, you will introduce regressions you cannot diagnose because you do not know what changed.&lt;/p&gt;

&lt;p&gt;A practical prompt structure that works well across most tasks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Role and context definition&lt;/li&gt;
&lt;li&gt;Task description with explicit constraints&lt;/li&gt;
&lt;li&gt;Output format specification&lt;/li&gt;
&lt;li&gt;One or two examples if the task is complex&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Keep prompts short and explicit. Long prompts with conflicting instructions produce inconsistent outputs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling Async LLM Calls in Node.js
&lt;/h2&gt;

&lt;p&gt;LLM calls are slow. A typical generation can take two to ten seconds. You cannot make users wait for a synchronous response on most interactions.&lt;/p&gt;

&lt;p&gt;The architecture that works best for most production use cases:&lt;/p&gt;

&lt;p&gt;When the user triggers an AI action, the API immediately returns a job ID and sets the status to processing. A background worker handles the actual LLM call. The frontend polls for status or receives an update over WebSocket when the job completes.&lt;/p&gt;

&lt;p&gt;This keeps your API response times predictable, lets you retry failed jobs, and gives you visibility into queue depth and processing time.&lt;/p&gt;

&lt;p&gt;For streaming responses where you want to show output in real time as the model generates it, use Server Sent Events. They are simpler than WebSockets for unidirectional streaming and well supported in Node.js with NestJS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Output Validation Is Non Negotiable
&lt;/h2&gt;

&lt;p&gt;If you ask an LLM to return JSON, it will sometimes return malformed JSON. If you ask it to follow a schema, it will occasionally miss a required field. If you ask it to stay within a character limit, it will sometimes exceed it.&lt;/p&gt;

&lt;p&gt;Every LLM response in a production system should go through a validation layer before it reaches the user or gets stored in the database.&lt;/p&gt;

&lt;p&gt;I use Zod for schema validation in TypeScript. The pattern looks like this: parse the model output, validate it against the expected schema, and if validation fails, either retry the call with the validation error included in the prompt or return a graceful fallback response to the user.&lt;/p&gt;

&lt;p&gt;Never pass raw LLM output directly to your frontend or database without validation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rate Limiting and Cost Controls
&lt;/h2&gt;

&lt;p&gt;LLM API costs can escalate quickly. A single user making many requests in a session can generate significant spend if you do not have controls in place.&lt;/p&gt;

&lt;p&gt;In every AI feature I build I implement:&lt;/p&gt;

&lt;p&gt;Per user rate limits at the API gateway level. Daily and monthly spend limits per workspace or account. Usage logging so you can analyze which features are generating the most cost. Automatic fallback to a cheaper model when the primary model is rate limited or slow.&lt;/p&gt;

&lt;p&gt;Set hard cost limits in your provider dashboard as a safety net. You do not want to discover a runaway process or an abuse pattern through your invoice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Caching LLM Responses Intelligently
&lt;/h2&gt;

&lt;p&gt;Not all LLM calls need to go to the model on every request. For any task where the same input reliably produces equivalent output, caching can dramatically reduce both latency and cost.&lt;/p&gt;

&lt;p&gt;Semantic caching is particularly useful here. Instead of exact match caching, you embed the input and cache the response against a vector. When a similar input comes in, you retrieve the cached response if the similarity is above a threshold.&lt;/p&gt;

&lt;p&gt;This works well for FAQ style features, content suggestions based on category, and any task where slight variations in input should produce the same response.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to Monitor in Production
&lt;/h2&gt;

&lt;p&gt;Standard application monitoring is not enough for AI features. You need to track:&lt;/p&gt;

&lt;p&gt;Latency per model and per task type. Token usage per request broken down by input and output. Validation failure rates, which indicate prompt quality issues. User level engagement with AI generated content, which tells you whether the outputs are actually useful.&lt;/p&gt;

&lt;p&gt;A feature that generates outputs users never interact with is not a working feature regardless of whether the API calls succeed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Biggest Mistake Teams Make
&lt;/h2&gt;

&lt;p&gt;Shipping an AI feature without a way to turn it off.&lt;/p&gt;

&lt;p&gt;Model quality changes when providers update their models. API reliability has incidents. Your prompt may suddenly produce bad outputs for a class of inputs you did not anticipate.&lt;/p&gt;

&lt;p&gt;Every AI feature should have a feature flag that lets you disable it instantly without a code deployment. The fallback should be a non AI version of the same functionality where possible.&lt;/p&gt;

&lt;p&gt;This is not pessimism. It is the same defensive engineering you apply to any external dependency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to Start
&lt;/h2&gt;

&lt;p&gt;If you are adding your first LLM integration to a production application, start with a low stakes, read only feature. Summaries, suggestions, and search enhancements are good first candidates. They add value without being in the critical path, which gives you space to learn how the model behaves in your specific context before you build anything that writes data or makes decisions.&lt;/p&gt;

&lt;p&gt;Get the infrastructure right first. Async handling, output validation, rate limiting, monitoring. Then expand.&lt;/p&gt;

&lt;p&gt;AI is powerful software. It rewards the same engineering discipline that all powerful software requires.&lt;/p&gt;




&lt;p&gt;I am Ahad, Founder of REIVEX Technologies. I build AI platforms and production web systems for clients across the US, Middle East, and South Asia. See more at ahadnawaz.dev.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>llm</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Building a Cloud ERP from Zero: What I Learned Shipping to 15 Companies</title>
      <dc:creator>Ahad Nawaz</dc:creator>
      <pubDate>Thu, 28 May 2026 18:41:30 +0000</pubDate>
      <link>https://dev.to/ahadnawaz/building-a-cloud-erp-from-zero-what-i-learned-shipping-to-15-companies-1f9i</link>
      <guid>https://dev.to/ahadnawaz/building-a-cloud-erp-from-zero-what-i-learned-shipping-to-15-companies-1f9i</guid>
      <description>&lt;p&gt;When I started building UPVC Cloud, I had no idea it would end up processing billions in transactions across 15 companies.&lt;/p&gt;

&lt;p&gt;I thought it was a standard enterprise project. It turned out to be a two year lesson in what actually makes production software survive real business conditions.&lt;/p&gt;

&lt;p&gt;This is that lesson.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is UPVC Cloud
&lt;/h2&gt;

&lt;p&gt;UPVC Cloud is a full scale cloud ERP built specifically for Pakistan's UPVC manufacturing and construction industry. It handles inventory, production orders, sales pipelines, customer management, invoicing, financial reporting, and HR workflows, all in one system.&lt;/p&gt;

&lt;p&gt;I built it from scratch at BuildSpark starting in late 2023. It is now live across 15 plus companies and processing a volume of financial transactions that I could not have predicted when I wrote the first line of code.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Stack and Why It Works
&lt;/h2&gt;

&lt;p&gt;The tech stack is Angular on the frontend and Node.js with NestJS on the backend, backed by PostgreSQL. Everything runs containerized on AWS.&lt;/p&gt;

&lt;p&gt;Angular gets criticism online but for an ERP with dozens of complex forms, data tables, nested workflows, and role based access, its structure is an asset not a liability. You do not want a flexible framework when you are building something this large. You want opinions.&lt;/p&gt;

&lt;p&gt;NestJS gives you the same thing on the backend. Modules, guards, interceptors, dependency injection. It reads like a Spring application but runs on Node. For enterprise software with strict separation of concerns, it is the right tool.&lt;/p&gt;

&lt;p&gt;PostgreSQL was never a question. ERP data is relational by nature. Inventory levels depend on production orders which depend on raw material purchases which connect to supplier accounts. You need a relational database with proper constraints, transactions, and joins. NoSQL would have been a disaster here.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Mistakes I Made in Month One
&lt;/h2&gt;

&lt;p&gt;I underestimated the domain complexity.&lt;/p&gt;

&lt;p&gt;ERP systems look simple from the outside. You read requirements, you build forms, you store data. But the relationships between modules run deep. A change in how inventory is tracked ripples through production planning, which changes how invoices get generated, which affects financial reports.&lt;/p&gt;

&lt;p&gt;I built the inventory module first, got it working, then started the production module and realized my data model was wrong. I had to refactor two weeks of work because I had not mapped out the full entity relationship diagram before writing code.&lt;/p&gt;

&lt;p&gt;The lesson: for any system with more than five interconnected modules, spend a full week on data modeling before you touch code. The ERD is not documentation. It is architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi Tenant Architecture From Day One
&lt;/h2&gt;

&lt;p&gt;One of the best decisions I made early was designing for multi tenancy from the start. Each company on the platform has its own data namespace, its own user roles, its own configuration. They share the same codebase and infrastructure but are completely isolated from each other.&lt;/p&gt;

&lt;p&gt;This is how you build SaaS. You do not build a single company system and then try to retrofit multi tenancy later. That retrofit will cost you more time than building it right the first time.&lt;/p&gt;

&lt;p&gt;In practice this meant every database query is scoped by a tenant ID. Every API route goes through a tenant resolution middleware. Every user session carries tenant context. It adds some initial complexity but removes an enormous amount of pain later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Role Based Access Control at Scale
&lt;/h2&gt;

&lt;p&gt;UPVC Cloud has five distinct user roles: super admin, company admin, sales manager, production staff, and viewer. Each role has different access to different modules, different permissions within those modules, and different views of the same data.&lt;/p&gt;

&lt;p&gt;I implemented RBAC using a permissions matrix stored in the database, not hardcoded in the application. This means adding a new role or adjusting permissions for an existing one is a configuration change, not a code deployment.&lt;/p&gt;

&lt;p&gt;If you are building any enterprise application, build your permission system this way from day one. Hardcoded role checks in your route handlers will eventually create a maintenance nightmare.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Performance Problems That Hit in Production
&lt;/h2&gt;

&lt;p&gt;Three months after launch, one company started generating significantly more data than the others. Suddenly reports that loaded in under a second were timing out.&lt;/p&gt;

&lt;p&gt;The culprit was a financial summary query that joined six tables without proper indexes. In development with small datasets it was fine. In production with hundreds of thousands of records across two years of operations, it was catastrophic.&lt;/p&gt;

&lt;p&gt;The fix required adding composite indexes on the most common join and filter columns, rewriting two queries to use CTEs instead of nested subqueries, and adding a caching layer for reports that did not need real time data.&lt;/p&gt;

&lt;p&gt;The deeper lesson: always seed your development database with realistic data volumes before you call a feature production ready. Testing with ten rows tells you nothing about how it behaves with a hundred thousand.&lt;/p&gt;

&lt;h2&gt;
  
  
  What 15 Live Deployments Actually Means
&lt;/h2&gt;

&lt;p&gt;Getting your software into one company is a milestone. Getting it into fifteen means you have solved a different set of problems.&lt;/p&gt;

&lt;p&gt;You have solved onboarding. Each new company needs to import their existing data, configure their chart of accounts, set up their users, and get trained. I built an admin onboarding flow that guides this process and reduced the average time from signup to first active use from three days to four hours.&lt;/p&gt;

&lt;p&gt;You have solved support. When something breaks in production you need to be able to diagnose it quickly without accessing sensitive company data. I built a logging and audit trail system that captures every state change in the system with timestamps and user attribution. Most support tickets get resolved in under fifteen minutes because the answer is in the logs.&lt;/p&gt;

&lt;p&gt;You have solved update management. Deploying a new version cannot break existing companies. I run database migrations with rollback support and use feature flags to roll out changes incrementally.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Things I Would Do Differently
&lt;/h2&gt;

&lt;p&gt;I would write integration tests for the cross module workflows earlier. Unit tests are not enough for an ERP. The bugs that matter are the ones where module A and module B interact in an unexpected way. Those only surface with integration tests.&lt;/p&gt;

&lt;p&gt;I would invest in better developer tooling from the start. Seeding scripts, local environment parity with production, and a proper staging environment would have caught several issues before they reached live users.&lt;/p&gt;

&lt;p&gt;I would document the data model as I built it, not after. The ERD exists now but it took effort to reconstruct it accurately because I did not maintain it during active development.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Project Taught Me About Building Software
&lt;/h2&gt;

&lt;p&gt;Enterprise software is not glamorous. It does not get on Product Hunt. Nobody writes Twitter threads about ERP systems. But it is the category of software that businesses depend on daily, that processes real money, and that has zero tolerance for errors.&lt;/p&gt;

&lt;p&gt;Building it well is a craft. And shipping it to fifteen companies that trust it to run their businesses is more validating than any launch tweet.&lt;/p&gt;

&lt;p&gt;If you are building something in this space, focus on data integrity above everything else. An ERP that loses data or corrupts records is not just broken software. It is a destroyed business relationship.&lt;/p&gt;




&lt;p&gt;I am Ahad, Founder of REIVEX Technologies and a full stack engineer with 5 plus years shipping production systems. Visit ahadnawaz.dev to see more of what I have built.&lt;/p&gt;

</description>
      <category>node</category>
      <category>angular</category>
      <category>architecture</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How I Shipped a Production-Ready MVP in 35 Days (Without Cutting Corners)</title>
      <dc:creator>Ahad Nawaz</dc:creator>
      <pubDate>Thu, 28 May 2026 18:37:40 +0000</pubDate>
      <link>https://dev.to/ahadnawaz/how-i-shipped-a-production-ready-mvp-in-35-days-without-cutting-corners-33d4</link>
      <guid>https://dev.to/ahadnawaz/how-i-shipped-a-production-ready-mvp-in-35-days-without-cutting-corners-33d4</guid>
      <description>&lt;p&gt;35 days. That was the deadline.&lt;/p&gt;

&lt;p&gt;A US real estate client needed a full-featured property management platform — lead tracking, document workflows, agent dashboards, and a public-facing listing portal. Not a prototype. Not a "we'll add features later" sketch. A production-ready system.&lt;/p&gt;

&lt;p&gt;Most engineers would have pushed back. I shipped it.&lt;/p&gt;

&lt;p&gt;This is the exact approach I used — and what I've refined over 20+ products and 4 years of building for clients across the US, Middle East, and South Asia.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Speed Matters More Than You Think
&lt;/h2&gt;

&lt;p&gt;There's a myth in software development that speed and quality are opposites. They're not. In my experience, the slowest teams are often the ones who over-plan, over-architect, and over-discuss before a single line of code is written.&lt;/p&gt;

&lt;p&gt;Speed is a forcing function. When you have 35 days, you can't afford to bikeshed. Every decision has to be intentional. And that discipline — that constraint — actually produces better code than an open-ended timeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Stack I Reached For (And Why)
&lt;/h2&gt;

&lt;p&gt;For PowerSell, I used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Node.js + NestJS&lt;/strong&gt; on the backend — modular by design, easy to scale, and I know it cold&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Angular&lt;/strong&gt; on the frontend — opinionated structure that prevents architecture debates&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PostgreSQL&lt;/strong&gt; for relational data (real estate data is relational — don't fight it)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS + Docker&lt;/strong&gt; for deployment — containerized from day one&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This wasn't a new stack I was learning. It was my production stack. The fastest way to build is to stop switching tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Day 1–5: Architecture Before Code
&lt;/h2&gt;

&lt;p&gt;The biggest mistake junior engineers make is opening VS Code before they've answered three questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What are the actual data entities and their relationships?&lt;/li&gt;
&lt;li&gt;What are the five core workflows the user will do daily?&lt;/li&gt;
&lt;li&gt;What does "done" look like for each feature?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I spent the first five days on an ERD, a feature map, and a brutally honest scope document. The client thought I was slow. By day 10, I was moving faster than any team they'd worked with before.&lt;/p&gt;

&lt;p&gt;A clear architecture isn't overhead — it's the rails your speed runs on.&lt;/p&gt;

&lt;h2&gt;
  
  
  The "Thin Slice" Deployment Strategy
&lt;/h2&gt;

&lt;p&gt;By day 7, something was deployed to a real server. Not everything. Not even most things. But the core authentication, database migrations, and one working feature — end to end.&lt;/p&gt;

&lt;p&gt;Why? Because deployment surprises kill timelines. The longer you wait to deploy, the more unknowns stack up. I've seen teams spend 3 weeks building and then a full week untangling deployment issues.&lt;/p&gt;

&lt;p&gt;Deploy early. Deploy often. Real infrastructure from day one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Feature Prioritization: The 80/20 of an MVP
&lt;/h2&gt;

&lt;p&gt;Not everything on the requirements list is equally important. For PowerSell, I mapped every feature to one question: &lt;em&gt;Does the core user workflow break without this?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If yes — P0. Build it first, build it right.&lt;br&gt;
If no — it goes in a later sprint or becomes a nice-to-have.&lt;/p&gt;

&lt;p&gt;Clients and stakeholders often conflate "would be nice" with "is necessary." Part of shipping fast is having the conversation that separates the two.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code Quality Under a Deadline
&lt;/h2&gt;

&lt;p&gt;What I don't compromise on, even under time pressure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TypeScript strict mode — always&lt;/li&gt;
&lt;li&gt;Consistent error handling — no bare catch blocks that swallow errors silently&lt;/li&gt;
&lt;li&gt;Environment-based config from the start (no hardcoded values)&lt;/li&gt;
&lt;li&gt;Automated database migrations, not manual SQL&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And what I do defer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Comprehensive test coverage (I write critical path tests, not 100% coverage)&lt;/li&gt;
&lt;li&gt;Perfect UI polish (functional first, pixel-perfect second)&lt;/li&gt;
&lt;li&gt;Advanced caching (premature optimization is still a sin)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Technical debt you accumulate deliberately is manageable. Technical debt that surprises you is what kills projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Communication as a Speed Multiplier
&lt;/h2&gt;

&lt;p&gt;The most underrated thing I did during the 35 days: daily async updates to the client. A short Loom or text summary every evening — what shipped, what's next, what decisions I need from them.&lt;/p&gt;

&lt;p&gt;This does two things. It keeps the client confident, so they don't schedule anxiety calls that interrupt your flow. And it surfaces blockers early, before they become timeline-killers.&lt;/p&gt;

&lt;p&gt;Clear communication isn't soft skills. It's engineering efficiency.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Shipped on Day 35
&lt;/h2&gt;

&lt;p&gt;A fully deployed platform with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multi-role auth (admin, agent, client)&lt;/li&gt;
&lt;li&gt;Lead capture and CRM pipeline&lt;/li&gt;
&lt;li&gt;Property listing management with media uploads&lt;/li&gt;
&lt;li&gt;Document signing workflow&lt;/li&gt;
&lt;li&gt;Agent performance dashboards&lt;/li&gt;
&lt;li&gt;Public-facing listing portal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The client launched it to their agents the same week.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Lesson
&lt;/h2&gt;

&lt;p&gt;Speed isn't about typing faster. It's about making fewer wrong decisions, deferring the right things, and building the infrastructure to move confidently.&lt;/p&gt;

&lt;p&gt;The engineers who ship fast aren't cutting corners. They've just gotten very good at knowing which corners can wait.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I'm Ahad — Founder of REIVEX Technologies and a full-stack engineer with 5+ years shipping production systems across ERP, AI platforms, real estate, and e-commerce. Visit &lt;a href="https://ahadnawaz.dev" rel="noopener noreferrer"&gt;ahadnawaz.dev&lt;/a&gt; to see what we're building.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
