What Building CS Projects Actually Taught Me

I'm starting my masters in AI soon, which means I will become an llm model I think, well I hope so. I wanted to write a post about the different types of cs applications I've built, trying to make a technical post to larp my way into becoming the cto of Nvidia.
My projects have different technical approaches, flaws, design choices and even collaborators. So I grouped them together as these projects have similarities.
1) FullStack Builds: ExamEngine, QBA Recruiting System
ExamEngine is something I worked on with 6 other full stack engineers to help my school Northeastern university help schedule final exams for current undergrad and masters students as well as instructors.
If you want a more detailed explanation please read this post: SWE Consulting
The Algorithm
The ExamEngine system employs the DSATUR (Degree of Saturation) graph coloring algorithm as its core scheduling engine to solve the NP-hard exam scheduling problem by modeling it as a constrained graph coloring task. In this approach, exam courses are represented as vertices in a conflict graph, edges connect courses with shared students (representing scheduling conflicts), and colors represent available time slots across a configurable exam period. DSATUR is a sophisticated greedy algorithm that iteratively selects the uncolored vertex with the highest saturation degree - the count of distinct colors already assigned to neighboring vertices - breaking ties by choosing the vertex with the largest overall degree, ensuring that courses with the most constraint interdependencies are scheduled first.
The algorithm then assigns each selected course the lowest available color that satisfies hard constraints such as no student conflicts, room capacity requirements, and available time slot limits, while dynamically updating saturation degrees of adjacent vertices to guide subsequent selections.
With a time complexity of O(V² log V), DSATUR achieves an optimal balance between computational efficiency and solution quality compared to simpler greedy approaches or more computationally expensive techniques like tabu search, making it ideal for real-time scheduling at scale. The implementation integrates seamlessly with the project's constraint evaluation system, which enforces hard constraints (student/instructor conflicts, room capacity, time slot availability) during graph construction and assignment, while also tracking soft constraint violations (back-to-back exams, maximum exams per day, large course scheduling preferences) as penalties to guide the optimization process.
Through forced edge connections between merged course sections, support for configurable parameters like maximum days and per-student exam limits, and intelligent handling of courses requiring multiple rooms when they exceed maximum capacity, the DSATUR implementation provides a production-grade scheduling solution that reliably generates conflict-free exam schedules within minutes, even for large institutions like Northeastern University.
Here is the very brief pseudo code of the algorithm:

AWS
ExamEngine uses AWS to run a scalable, production-grade exam scheduling system for Northeastern University. The frontend Next.js app and backend FastAPI scheduling engine are containerized and deployed on AWS ECS Fargate, with Docker images stored in ECR and built through a GitHub Actions CI/CD pipeline. An Application Load Balancer routes HTTPS traffic to the frontend and backend services, while security groups restrict access so ECS tasks only receive traffic from the ALB and the PostgreSQL database only accepts connections from ECS.
The system uses AWS RDS PostgreSQL to store courses, students, room assignments, generated schedules, conflict analyses, and scheduling runs. Amazon S3 manages uploaded CSV datasets, including course data, student enrollment files, and room capacity information. The backend uses boto3 to upload, download, process, and clean up these files.
AWS IAM handles service permissions, giving ECS tasks access only to the resources they need, while CloudWatch centralizes logs from both frontend and backend services for monitoring and debugging. All infrastructure is managed with Terraform, including ECS, ALB, RDS, S3, IAM, security groups, and environment-specific configuration.
Overall, the AWS architecture provides a secure, scalable, and cost-efficient cloud platform for running the DSATUR scheduling algorithm, storing uploaded datasets, persisting scheduling results, and supporting reliable production deployment through both automated CI/CD and manual deployment workflows.
Consulting
This project was built for clients, not ourselves so we frequently used an Agile methodology, had weekly standups, communicated in discord and met with our clients on a regular basis. Our clients were non technical so we had to explain AWS, DSATUR and design choices. The agile methodology heavily depends on sprints. Sprints is where the team decides to make a feature in a short amount of time, so for example make the main dashboard in a week, and then implement it, then move on to the next sprint. A bunch of small sprints will invariably create the final product. This approach helped us deliver small components to our clients so they can see if we are making a product to their liking. If we never met with them in between and developed something not to their liking, that wouldn't end well.
UI Demo
The QBA Recruiting System is an AI-driven recruitment platform built to streamline candidate sourcing, screening, and engagement. The system follows a modern full-stack architecture, with a FastAPI backend serving a React frontend through REST APIs, JWT-based authentication, and role-based access control. The backend is organized into modular components for API routing, database models, persistence, authentication, and business operations. The frontend is a single-page application built with React, Tailwind CSS, and shadcn/ui, using Context API for state management and Axios for backend communication. This separation allows the frontend and backend to be developed, tested, and deployed independently while maintaining a clear flow of data across users, jobs, applications, and related recruitment entities.
The system uses a layered architecture with clear separation between API routing, business logic, data access, and authentication. FastAPI dependency injection manages token verification and database sessions, which helps keep requests secure and efficient. SQLAlchemy models define core entities such as users, jobs, and applications, while Pydantic schemas handle validation and response formatting. The routing layer exposes endpoints for jobs, applications, user management, resume parsing, and machine learning inference, with each area separated by domain. CORS middleware enables secure communication with the frontend, and the database layer supports PostgreSQL-backed persistence. This structure keeps the system maintainable while supporting features such as filtering, pagination, candidate tracking, and future workflow expansion.
The system automates major recruitment workflows to reduce manual work for recruiters. Resume parsing extracts structured information from PDF resumes, including candidate names, skills, experience, and contact information. Email automation supports account confirmations, application updates, and recruiter-candidate communication. The platform also supports dynamic application forms, allowing jobs to include custom questions and structured application requirements without manual form setup each time. Application statuses can move through stages such as not reviewed, accepted, or rejected, with timestamps that help create an audit trail. These automation features reduce repetitive recruiter tasks, limit manual data-entry errors, and create a more consistent candidate experience.
The system integrates a BERT-based machine learning model to help classify, score, and evaluate job applications and resume content. The model uses transformer-based natural language processing to process text input and return predicted labels or confidence scores, helping recruiters identify stronger candidate-job matches. Because real recruitment data can be limited or sensitive, the model uses synthetic training data that simulates realistic job descriptions, resumes, and application responses. This allows the system to capture common recruiting patterns without relying entirely on private candidate data. The model can support semantic matching between job requirements and candidate profiles, helping recruiters prioritize applications, improve hiring decisions, and reduce time spent manually reviewing resumes.
2) Speed Builds: LoopBack, Only66, OffFeed
I think one of the best things about AI is that it lowers the cost of testing ideas. A product idea used to sit in my notes app for months because I would overthink the frontend, backend, database, design, auth, and every possible feature before building anything. Speed Building is my attempt to avoid that. The goal is simple: take an idea, build the smallest useful MVP, deploy it, and see if the idea actually holds up.
My current framework is straightforward. I use OpenAI to plan the product, break down the architecture, think through data models, and debug implementation decisions. I use Lovable when I want to move fast on frontend and get a real interface quickly. Most of the apps are built with React, TypeScript, Tailwind, and Vercel. For storage, I choose based on the scale of the project. If the app is local-first and personal, localStorage is enough. If the app needs accounts, saved user data, or cross-device persistence, Supabase makes more sense. The point is not to pick the perfect stack. The point is to pick the fastest stack that lets the core product loop exist.
A speed build starts with the loop, not the features. Only66's loop was: pick a habit, survive 66 days, keep the streak alive. LoopBack's loop was: add a contact, save the context, set a cadence, follow up before the connection goes cold. OffFeed's loop is: choose your interests, get three short daily papers, read everything in under ten minutes, then leave. If the loop is not clear, the product becomes fake complexity. You start adding dashboards, settings, automations, and AI features before proving whether the main idea is useful.
Only66 was my first speed build. It is a gamified habit tracker built around the idea that habits should feel like survival, not another boring checklist. Technically, it is not the most complex app, but that was the point. The challenge was more about emotional design than engineering difficulty. A habit tracker only works if the user feels some pressure to return. The 66-day grid, streak system, survival language, and arcade-like feeling made the app more interesting than a normal productivity tool.
LoopBack was more technical because it had a real data problem. I built it because my networking system was basically LinkedIn tabs, memory, and anxiety. The app stores contacts, roles, companies, LinkedIn URLs, relationship types, relationship strength, cadence, notes, profile text, conversation history, and interaction logs. The first version is local-first, so the data is stored in the browser instead of a backend. That made the MVP faster to ship, but it also forced me to deal with browser storage limits. At one point, pasted profile pictures were being saved as base64 inside localStorage, and copied LinkedIn profiles were massive. The app looked like it saved contacts, but after reload, some disappeared because storage had silently failed. I fixed that by compressing images, cleaning pasted LinkedIn text, adding storage error handling, and creating a fallback that removes oversized blobs when needed.

The more interesting part of LoopBack is the parsing and conversation logic. Users can paste LinkedIn profile text or conversation history, and the app tries to extract useful structure from messy text. It can infer names, roles, companies, relationship types, and conversation context. Then a rules-based analyzer looks at the conversation and decides whether I am waiting on them, they are waiting on me, I need to say thank you, a referral was submitted, the relationship is stale, or I should keep the person warm. From there, it suggests a next action and drafts a follow-up message. That made LoopBack feel less like a contact list and more like a small networking assistant.
OffFeed is the speed build I am making now. The idea is a daily newspaper for people who deleted social media but still want to stay informed. The product is not supposed to be another infinite feed. Users choose categories like AI, coding, sports, gaming, tech, startups, or culture, and the app gives them three short daily papers. No ads. No doomscrolling. No reason to keep refreshing. The technical challenge is building a backend that can pull current events from RSS feeds, APIs, and trusted source lists, convert them into source packets, and then use OpenAI credits to generate articles in my writing style.
For OffFeed, the model should not invent the news. That would be stupid. The backend needs to separate source collection from article generation. First, it collects the title, source, URL, publish date, summary, and key facts. Then the AI writes from that source packet only. The model acts more like an editor than a reporter. It takes verified information and turns it into a 1,250-word article that is direct, casual, readable, and skeptical of hype. A second pass should check the article against the source packet for unsupported claims. That part matters because AI-generated current events can become garbage fast if the system is not grounded.
The flaw with speed building is that it can create fake progress. Shipping a beta does not mean people want the product. It only proves that I could build a version of it. The code can also get messy because speed usually means tradeoffs. localStorage is fast, but it is not a real database. Local auth is fine for a prototype, but not production. Lovable can generate useful UI quickly, but it can also produce generic design and structure that needs cleanup. AI can speed up development, but it can also make you feel like something is more complete than it actually is.
That is why I think the success of a speed build comes down to the problem, the loop, and the constraint. Only66 worked because the loop was simple and emotional. LoopBack worked because the pain was specific and real. OffFeed has potential because the enemy is clear: the infinite feed. A good speed build does not need to be huge. It just needs to remove one repeated source of friction from your life, get deployed, and give you enough signal to decide whether it is worth expanding.
Only66: only66.site
LoopBack: loop-back-rho.vercel.app
More speed builds: shuklashreyas.com/speed-building
3) ML Builds: Soccer Scouting Bot, Emotion Recognition, Brain Alzheimer's Detection, Exercise Classifier
A lot of machine learning projects look good when you only talk about the model. You say you used a CNN, an SVM, PCA, K-means, Bayesian regression, or some deep learning architecture, and it sounds impressive. But after building a few of these systems, I realized the model is only one part of the project.
The harder part is usually everything around the model.
How is the data prepared? Is the split actually fair? Are the results real, or did the model accidentally see the same kind of sample during training and validation? Can the model be used in an actual application? Does the frontend make the result understandable? Does the evaluation actually measure generalization, or is it just making the project look better than it is?
That's what these projects taught me.

The Emotion Recognition project was an end-to-end speech classification system that predicted six emotional states from WAV audio: anger, disgust, fear, happiness, neutral, and sadness. The architecture was modular, with separate layers for data, utilities, models, training, saved models, testing, and the frontend. Audio processing and feature extraction were handled in the utility layer, while each model had its own training pipeline. The final trained models were used inside a Streamlit app that allowed users to upload audio or record directly from a microphone.
The dataset came from CREMA-D, which contains 7,442 unique recordings from 91 actors. The audio was converted to mono, resampled to 48 kHz, and represented using either normalized log-Mel spectrograms or MFCC sequences. The CNN, SVM, and KNN pipelines used Mel-spectrograms, while the MLP used MFCCs from audio padded or truncated to three seconds. This made the project a useful comparison between deep learning approaches and more classical machine learning techniques.
The CNN was a compact PyTorch model with two convolutional layers, ReLU activations, max pooling, and a fully connected output layer. The SVM used flattened spectrograms, standardized the data, reduced the feature space with PCA, and then applied an RBF kernel. On paper, the results looked strong, with the CNN reporting 98% validation accuracy and the SVM reporting 96%.
But the more important lesson was that good numbers do not always mean good evaluation. The label CSV had duplicate audio paths, meaning the same recording could appear in both training and validation splits. That can inflate validation accuracy because the model may be recognizing repeated samples instead of generalizing to truly unseen voices. A stronger evaluation would deduplicate recordings and split by actor, making sure the model is tested on voices it has never heard before. That one issue completely changes how you interpret the results.
The Soccer Scouting Bot was less about predicting one correct answer and more about building an interpretable analytics system. Instead of saying, "This player will succeed," the goal was to help users search, compare, and understand football players through data.
The system used scraping modules to collect FBref and transfer data, preprocessing modules to clean and normalize player statistics, modeling modules to create embeddings and clusters, and a Streamlit app to present the final results. The architecture made the project feel more like a real analytics tool than a one-off machine learning notebook.
The cleaned dataset included players across the Premier League, La Liga, Bundesliga, Serie A, and Ligue 1. Player statistics were converted to per-90 values where needed and standardized so players could be compared more fairly across different leagues, positions, and playing time. The core representation compressed player performance into six dimensions: shooting, dribbling, passing, chance creation, carrying, and defending.
The main machine learning component used standardized features, PCA, and K-means clustering to group players into role archetypes. Similar players were retrieved using cosine similarity between embeddings, while position overlap acted as a filter. The nice part about this project was that it stayed explainable. Instead of giving users a mysterious similarity score, the system could point back to shared strengths, percentile rankings, and positive z-scores.

The biggest limitation was evaluation. Since this was an unsupervised system, there was no simple "accuracy" number unless there was ground truth from scouts or expert role labels. A better evaluation would include cluster stability, silhouette score, and scout-rated Precision@K for similar-player recommendations. This project taught me that not every ML system needs to be a classifier, but every ML system still needs a serious way to evaluate whether it is useful.
Brain Scanning and Alzheimer's Detection
The Brain Scanning project explored Alzheimer's-related impairment classification using MRI images. It combined multiple approaches: a manual CNN built from scratch in NumPy, a deeper TensorFlow CNN, handcrafted ROI features, and Bayesian models for uncertainty-aware reasoning. This made the project interesting because it was not just about building one model. It compared different ways of thinking about the same problem.
The manual CNN was built directly in NumPy, with convolution, ReLU, max pooling, dense layers, softmax, cross-entropy, and backpropagation implemented as separate components. That made it useful from an educational perspective because it forced me to understand what the model was actually doing under the hood. The TensorFlow model was more production-style, using multiple convolution blocks, batch normalization, dropout, and data augmentation.
The raw CNN results were not strong. The downstream dataset contained 1,279 test predictions, but the class distribution was heavily imbalanced. The largest class alone made up about half the dataset, and the CNN achieved roughly 50% accuracy, which suggested majority-class collapse rather than meaningful four-class classification. In a medical-style project, that matters a lot. Accuracy alone is not enough. You need balanced accuracy, macro-F1, per-class sensitivity, and confusion matrices to understand whether the model is actually detecting impairment or just guessing the dominant class.
The Bayesian pipeline was more promising because it used the CNN's class probabilities as inputs for binary and ordinal models. The reported binary metrics were much stronger, but even there, the confusion matrix needed to be checked carefully. This project taught me that medical ML cannot be judged by flashy architecture. Evaluation design, class balance, interpretability, and uncertainty matter more than just saying "I trained a CNN."
The Gym Exercise Recognition project was a lightweight computer vision prototype that classified exercise videos into ten categories, including push-ups, squats, lunges, jumping jacks, planks, sit-ups, burpees, high knees, mountain climbers, and side planks. The system had a clean three-stage architecture: extract frames from labeled videos, train a TensorFlow CNN, and serve predictions through a Flask API.
The dataset contained 3,979 extracted frames, with some class imbalance between exercises. Images were resized to 64×64, normalized, and passed through a CNN with three convolutional stages followed by a dense layer and a ten-class softmax output. The saved model was lightweight, around 7.9 MB, which made it practical for a simple server-side prototype.
The issue was not the architecture. The issue was the evaluation setup. The training and validation frames came from the same source videos, meaning near-identical frames could appear on both sides of the split. Even if the model got high validation accuracy, that would not prove it could generalize to a new person, camera angle, gym, lighting condition, or workout session. A better evaluation would split by source video or participant before extracting frames.
The project also exposed a limitation of frame-by-frame classification. Returning a label for every single frame can be noisy and redundant because exercises are movements, not isolated images. A better version would aggregate frame predictions using majority voting, temporal smoothing, or a sequence model like a CNN-LSTM. This project taught me that video classification needs temporal understanding, not just image classification repeated many times.
Final Takeaway
Each project I built has its unique takeaway. I’m glad that I am able to make extensive projects with peers and friends to solve real world problems. Making a Recruiting system taught me why AI might need more context when evaluating candidates, The speedbuilds allow me to make fast demos so I can see if I'm interested in pursuing it further and the ML projects taught about getting trusted and accurate data.
The Stoic Stack, in your inbox.
Get notified when I drop a new post. Software, AI, sports, philosophy, and life — unsubscribe anytime.
More Blogs Like This
I’ma Focus… After One More Reel
The reels are the easiest escape. But what if the real problem is a goal built on fear, rather than something you actually want?
Token Culture
When you have tokens, you’re the Flash. When they run out, you’re Barry Allen. On AI dependency and the pressure to keep shipping.
Subagents Might Cook Us
AI’s speed isn’t what concerns me. It’s getting better at delegation and efficiency. So what happens when one agent can manage a whole team?
