THREE PRODUCTS IN PRODUCTIONCARRIVSTUDYLUMINASANADE--:--:--MONTRÉAL · UTC-5
AVAILABLE · INTERNSHIP 2027MONTRÉAL · UTC-5B.ENG · DEC. 2027

HoussamNadir.

the model generates, the code decides. three products in production, solo. an untested invariant does not exist. from the prompt to the payment webhook

Computer engineering student at Polytechnique Montréal. I ship complete products on my own: structured-output LLM pipelines, deterministic scoring, race-free transactional accounting, cloud security. Three platforms in production, from the bilingual landing page to the signed payment webhook.

3
PRODUCTS IN PRODUCTION
110k+
LINES OF TYPESCRIPT
941
TEST CASES · SANADE
3.65
GPA · WINTER 2026
01 · ./PRINCIPLES --APPLIED

My engineering thesis

Trois principes, tenus dans les trois produits. Ce ne sont pas des slogans : chacun est vérifié par du code.

PRINCIPLE I

The model extracts, the code decides

An LLM is excellent at rephrasing and classifying, disastrous at producing a number that is meant to be reproducible. Every figure shown to a user comes out of a pure function.

Carrivdeterministic ATS scoreStudyLuminaERS, a pure function of ~850 linesSanadezero trained models
PRINCIPLE II

An untested invariant does not exist

Product rules come down to the test level: they fail CI instead of living in a document nobody rereads.

Ratchetany types never creep backThresholdsclient ≡ server, verifiedArchitecturefacts ⇸ projectionsColoursno hardcoded literals
PRINCIPLE III

A runtime constraint is a design constraint

Serverless, a provider's rate limit, the death of a Lambda: architecture parameters, not accidents to absorb in production.

Timeout90 s < Lambda lifetimeCreditreserved before the callRate limitin the database, not in memory
THE BUG THAT CREATED A RULE

Eight copies of one palette hardcoded the light-theme values: the best possible score rendered at 1.59:1 contrast on the dark theme, invisible. After moving to tokens: 9.95:1. Since then, a test forbids colour literals in components.

WHAT I REFUSE TO SHIP

An experience invented by a model, a score that regresses for no explainable reason, a credit charged for a generation never received, a PDF that looks good but is unreadable by an ATS. Each of these four refusals produced a line of architecture.

02 · FOUR CASES, NOTHING HIDDEN

Case studies

CASE 01Carriv
ROLEDesign & engineering, soloPERIOD2026STATUSIn productionVIEW LIVE ↗

Carriv: tailoring a résumé to a posting without inventing anything

Applying properly costs 30 to 45 minutes per posting; asking a chatbot to "write the résumé" produces invented experience that collapses in the interview. Carriv adapts a master profile to a given posting under a zero-fabrication rule written into every prompt.

Carriv screenshot: tailored résumé and ATS score
AUTOMATIC PREVIEW OF CARRIV.COM · CAPTURED AFTER SETTLING
WHAT THIS CHANGES FOR THE CANDIDATE
01

30 to 45 minutes of work per application, down to about thirty seconds.

02

Nothing invented: everything on the résumé holds up in an interview.

03

The PDF clears ATS filters instead of being rejected on layout.

04

The credit is refunded automatically if generation fails. Never paid for nothing.

THE PROBLEM

The model may reorder, select, rephrase and omit, but never fabricate an experience, a date, an employer, a diploma or a number. Translation is the only permitted transformation, with strict fidelity to the degree level.

THE CENTRAL DECISION

The ATS score is not produced by the model. A real ATS is a keyword-matching engine, not a judge: the LLM extracts and ranks the gaps, the score is a deterministic function. Re-scoring always returns the same number, and applying a rewrite can only add a keyword, so it can never lower the score.

POST /api/generate · THE PIPELINE
resolveApiUser session or personal token (extension) enforceRateLimit 30 generations / h / user getProfile scoped to userId: never a cross read reserveCredit atomic findOneAndUpdate { credits: { $gte: 1 } } → 402 analyzeJob Structured Outputs · primary model adaptCVAndLetter Structured Outputs · primary model scoreATS deterministic matching, weighted must=2 / nice=1 createApplication catch → refundCredit + alert
~30 s
GENERATION
10
PDF TEMPLATES
30/h
RATE CAP
2
CURRENCIES
GUARANTEED REFUND

The OpenAI client is capped at 90 s with a single retry, instead of 10 minutes and 2 retries. On Vercel, a hung request has to fail while the Lambda is still alive, otherwise the catch block that issues the refund never runs and the user pays for a generation they never received.

THE ATS WALL

The application has a deliberate visual identity; the PDFs stay strictly ATS-safe: one column, typography only, no colour and no ornament. That is exactly where most generators fail.

PAYMENT SECURITY

The Stripe amount is never trusted from the client: the credit count comes from a server-side table indexed by Price ID, with a signature-verified webhook. Extension tokens are stored as SHA-256 only. An explicit 30-page cap guards against PDF decompression bombs.

SvelteKit 2Svelte 5 runesTypeScript strictMongoDBbetter-authOpenAI Structured OutputsStripepuppeteer-coreVercelVitest
CASE 02StudyLumina
ROLEDesign & engineering, soloPERIOD2026STATUSIn productionVIEW LIVE ↗

StudyLumina: measuring real readiness for an exam

AI study tools stop at generating content. StudyLumina measures actual readiness, chapter by chapter, and says what to do today. No grade is ever produced by an LLM.

AUTOMATIC PREVIEW OF APP.STUDYLUMINA.COM · CAPTURED AFTER SETTLING
WHAT THIS CHANGES FOR THE STUDENT
01

An answer to the only question that matters: am I ready, on which chapter, and what should I do today.

02

Every answer is cited (document and page), so it can be checked rather than believed.

03

The score exposes itself to contradiction: the mean error against real grades is displayed.

04

Drop a PDF and keep working: summary, flashcards and quizzes arrive in the background.

THE PROBLEM

A summary does not tell a student whether they are ready. Without binding a document to a chapter, a quiz answer cannot be attributed to a subject, so nothing can be measured beyond a worthless global average.

THE CENTRAL DECISION

Course → Chapter → Document is mandatory: an orphan document does not exist. It is the precondition for the entire product. The Exam Readiness Score is a pure function of about 850 lines, with no network and no LLM, and the retention factor is gated: a chapter with no reviewed flashcard scores strictly the same as before, proven by test.

ASYNCHRONOUS INGESTION · 6 BULLMQ QUEUES
upload → ingestion PDF extraction, page cleanup → embeddings chunking, batching + rate limit, pgvector → course-map binding chunks ↔ chapters → summary | flashcards | quiz (in parallel) Hybrid RAG: pgvector + BM25 (GIN) fused, filtered by course/chapter, parameterised SQL. On a follow-up, the question is condensed into a standalone query before retrieval. Citations → document + page.
47,600
TS LINES
78
API ROUTES
74
TEST FILES
25
PRISMA MODELS
A FALSIFIABLE SCORE

The student enters their real grade after the exam; the product displays the mean error between predicted score and grade obtained. The real grade is never fed back into the calculation: the score makes itself refutable instead of declaring itself correct.

AN HONEST SCORE

Coverage acts as a confidence multiplier: three correct answers cannot make it read "Ready". The overall score is smoothed, so one bad quiz does not collapse everything.

DATA MODEL

A DocumentChapterSpan bridge model with page ranges rather than a foreign key: one PDF often spans several chapters, and one chapter is spread across several PDFs. No scalar metric is stored as raw JSON.

Next.js 15React 18PostgreSQL + pgvectorPrisma 6BullMQ + RedisAuth.js v5Gemini / OpenAI / DeepSeekStripePino + Prometheusnext-intl
CASE 03Sanade
ROLEDesign & engineering, soloPERIOD2025-2026STATUSIn productionVIEW LIVE ↗

Sanade: the habit tracker that arbitrates instead of recording

Trackers faithfully display the gap between planned and done, for months, without ever acting on it. Sanade computes the time actually available in a day, proposes two or three achievable goals and sets the rest aside, saying why.

Sanade screenshot: today's arbitration
AUTOMATIC PREVIEW OF SANADE.APP · CAPTURED AFTER SETTLING
WHAT THIS CHANGES FOR THE USER
01

Two or three achievable goals for today, instead of a guilt-inducing list of twelve.

02

Every goal set aside comes with a reason: the user sees why, rather than facing an opaque filter.

03

Notes can be written in French, transliterated Darija or Arabic: the raw text is kept exactly as entered.

04

Web and mobile share the same domain core: no divergence in calculation between the two.

THE PROBLEM

A declared capacity is an imagined capacity. And with six domains and time lags, one analysis cycle tests hundreds of pairs: an individual threshold would mechanically guarantee false links on every pass.

THE CENTRAL DECISION

Facts against projections, visible in the table names: every stored calculation carries the proj_ prefix, so clearProjections() is safe at any moment and a scoring formula can be corrected without leaving an inconsistent history. No fact table points at a projection, and an architecture test verifies it, because the rule was silently broken once already.

INGESTION · AN EXTRACTION NEVER CREATES DATA
raw text (FR / transliterated Darija / Arabic) → RawNote stored as-is, never rewritten → versioned prompt + server-side LLM → JSON validated by a strict Zod schema ├─ failure → one repair, then a logged failure └─ success → Extraction { proposals, confidence } → review screen item-by-item confirmation → Trackable (PLAN) or LogEntry (CHECKIN)
62,000
TS LINES
941
TESTS
13,700
PURE DOMAIN
0
SERVICES REQUIRED
THE KINDNESS IS IN THE FORMULA

A day left blank drops out of the calculation instead of counting as zero: it lowers the displayed confidence, never the score. Three days without data show "score 74, low confidence", not "score 31", otherwise the product would punish not opening the app.

STATISTICAL RIGOUR

What is displayed is an empirical conditional frequency: two numbers reproducible by hand. Links are tested per full cycle, the number of tests is counted, and publication is filtered on the false discovery rate. Every pattern freezes its cycle.

PURE DOMAIN CORE

packages/core never imports db, api, ingestion or React: 13,700 lines testable with no database, no network, no API key. The logic cannot diverge between web and mobile: it is a property of the structure, not a discipline.

TypeScript ESMNext.js 16 / React 19Expo · React NativetRPC v11Prisma + PostgreSQLPGlite (WASM)ZodVitest · PlaywrightTurborepo · pnpmSentry
CASE 04CSPM-Lite
ROLEPersonal toolPERIOD2025STATUSInternal tool

CSPM-Lite: cloud security that blocks the pipeline

A CLI tool that scans an AWS account, detects misconfigurations, evaluates compliance and produces actionable reports, then refuses to let the deployment through.

~/cspm-lite
$ cspm-lite scan --account prod --gate
WHAT THIS CHANGES FOR THE TEAM
01

A critical finding stops the deployment: security becomes a gate, not a report.

02

Two outputs: JSON for the machine, readable HTML for human review.

03

CIS-aligned checks without a commercial tool licence.

THE PROBLEM

A cloud misconfiguration is invisible in a code review: a public S3 bucket, an open SSH port, a user without MFA. It becomes visible in production, or in a breach.

THE CENTRAL DECISION

A report is not enough: nobody reads a report. The check becomes blocking: a critical finding stops the CI/CD pipeline, which moves security from the audit to the front door.

CHECKS AND OUTPUTS
scan AWS account → detection public S3 · open SSH · missing MFA → compliance checks aligned to CIS Benchmark → prioritisation severity + remediation guidance → reports JSON (machine) + HTML (human) → CI/CD gate critical finding → build blocked
CIS
BENCHMARK
2
REPORT FORMATS
CI
GATE ENFORCED
A
CYBERSECURITY COURSE
WHY THIS TOOL

A cybersecurity course gives you the concepts; a real AWS account gives you the unpleasant surprises. This tool came out of needing to check my own deployments before a grader, or an attacker, did it for me.

RELATED LAB WORK

Network discovery, service enumeration, basic web security and troubleshooting in Linux environments. Advent of Cyber (TryHackMe, Dec. 2025) for structured investigative method.

PythonAWS SDK (boto3)CIS BenchmarkLinuxGitHub ActionsJSON / HTML
03 · AGGREGATED ACROSS THE THREE PLATFORMS

What that adds up to

~110,000
LINES OF TYPESCRIPT
941 + 74
TEST CASES · TEST FILES
78
API ROUTES · STUDYLUMINA
3
BILINGUAL FR/EN PRODUCTS
0
TRAINED ML MODELS
2
STRIPE WEBHOOKS IN PROD

All three products share the same backbone: schema validation at every boundary, never a .parse() that blows up, external clients initialised lazily so a build passes without secrets, and a loud failure preferred over a value quietly made up.

04 · FILTER BY DOMAIN

Capabilities

TypeScript strictexpert
Next.js · SvelteKit · Reactadvanced
Node.js · typed APIs (tRPC)advanced
Pythonadvanced
C / C++ · systemssolid
PostgreSQL · Prisma · MongoDBadvanced
AWS · serverless deploymentsolid
Docker · Linux · WSLadvanced
Job queues (BullMQ · Redis)solid
RAG · pgvector · embeddingssolid
Application security · authenticationadvanced
Cloud posture · CIS · IAMsolid
Network reconnaissance · Linuxsolid
05 · SWIPE →

Career path

→ DEC. 2027

B.Eng. Computer Engineering

Polytechnique Montréal

A track oriented toward secure systems, cloud and distributed environments.

Cybersecurity : ADistributed systems & cloud : B+GPA : 3.65 (winter 2026)
SINCE OCT. 2024

Brand representative

Qualcomm / Snapdragon PC, Channel Partners

Explaining technical solutions to the public: adapting the pitch to each person, making an architecture understandable in two minutes. It is the skill that makes an engineering decision defensible.

2025-2026

Three products shipped solo

Carriv · StudyLumina · Sanade

Design, development, production release, payments, transactional email, bilingual SEO and observability, with no team.

CERTIFICATIONS & LANGUAGES

Markers

Advent of Cyber · TryHackMe · Dec. 2025French : nativeEnglish : fluentMontréal, QC · open to remote
~/contact
$ open --channel internship-2027

Give me the constraint, I will come back with the architecture.

I am looking for an internship where I touch production: pipeline, security, data, not just the mockup. Reply within 24 h.

MONTRÉAL, QCUTC-5FR / ENAVAILABLE 2027