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

HoussamNadir.

AI where it helps, code where it has to be right. three products in production, solo. an untested invariant does not exist. from the mockup to payments in production

I build complete products on my own and ship them to production: interface, backend, payments, security.

3
PRODUCTS IN PRODUCTION
1.1 M
POSTINGS WATCHED LIVE
1,500+
AUTOMATED TESTS
E2EE
SIGNAL PROTOCOL, REBUILT
01 · A SELECTION, BUILT SOLO

What I have built

IN PRODUCTION
01CAREERS · AIIn production

Carriv

Tailors a résumé to a job posting in 30 seconds, without ever inventing anything.

  1. posting
  2. LLM analysis
  3. tailored résumé
  4. deterministic ATS score
PER APPLICATION
~30 s
ATS-SAFE PDF TEMPLATES
10
INVENTED EXPERIENCE
0
SvelteKitTypeScriptMongoDBOpenAI Structured OutputsStripeVercel
VIEW LIVE ↗
Under the hood
THE PROBLEM

Asking a chatbot to "write the résumé" produces invented experience that collapses in the interview.

THE DECISION

The model rephrases, reorders, omits, but never fabricates. The ATS score comes out of a deterministic function: re-scoring always yields the same number.

POST /api/generate
reserveCredit atomic findOneAndUpdate { credits: { $gte: 1 } } → 402 analyzeJob Structured Outputs adaptCVAndLetter Structured Outputs scoreATS deterministic matching, must=2 / nice=1 catch → refundCredit + alert never paid for nothing
02EDUCATION · RAGIn production

StudyLumina

Tells a student whether they are ready for their exam, chapter by chapter.

  1. course PDF
  2. hybrid RAG
  3. quizzes & flashcards
  4. readiness score
ANSWERS SOURCED
100%
API ROUTES
78
TEST FILES
75
Next.jsPostgreSQL + pgvectorPrismaBullMQ + RedisStripenext-intl
VIEW LIVE ↗
Under the hood
THE PROBLEM

A summary does not tell a student whether they are ready. Neither does a global average.

THE DECISION

The score is a pure function, with no LLM. It makes itself refutable: the gap with real grades is shown.

INGESTION · 6 BULLMQ QUEUES
upload → ingestion PDF extraction → embeddings chunking, pgvector → course-map chunks ↔ chapters → summary | flashcards | quiz (in parallel) RAG: pgvector + BM25 fused · citations → document + page
03PRODUCTIVITY · WEB + MOBILEIn production

Sanade

Turns a scattered day into two or three goals you can actually hold.

  1. free note FR / darija
  2. validated extraction
  3. consistency scores
  4. today's priority
TESTS
1,020
DOMAIN COVERAGE
94%
APPS, ONE CORE
2
Next.js 16ExpotRPCPrismaPostgreSQLTurborepo
VIEW LIVE ↗
Under the hood
THE PROBLEM

Trackers show the gap between plan and reality for months, without ever doing anything about it.

THE DECISION

Facts versus projections: every stored computation is disposable and recomputable. An architecture test forbids a fact from depending on a projection.

AN EXTRACTION NEVER CREATES DATA
raw text (FR / darija / Arabic) → RawNote stored verbatim → LLM + strict Zod schema → review screen item-by-item approval → Trackable or LogEntry
LAB · TOOLS AND PROTOCOLS
~/job-radar
registry
4,899 validated sources
postings
1,133,000+ covered
ATS
Workday · Greenhouse · Lever · Oracle · +20
lead
2 h to 72 h ahead of LinkedIn
04MONITORING · REAL TIMEPersonal tool

Job Radar

Sees an internship posting minutes after it goes up, not days.

  1. 4,899 career sites
  2. requisition diff
  3. LLM-free score
  4. notification
SOURCES
4,899
POSTINGS COVERED
1.1 M
TESTS
429
Node.jsBrowser extensionPlaywrightDeterministic scoring
PRIVATE REPO · DEMO ON REQUEST
Under the hood
THE PROBLEM

A posting takes 2 to 72 hours to reach LinkedIn, while most hiring is decided in the first few days.

THE DECISION

Query the endpoint the career page itself calls, and diff on requisition IDs, never on content. The registry was mined from 37,000 real URLs, then every source validated live.

ONE PASS
fetch ~1 req/s per domain pre-score title + location, deterministic diff on requisition IDs enrichment only if the score can clear the threshold notification individual, or digest
~/ratchet
server
only ever sees opaque bytes
key
one message, then destroyed
calls
WebRTC, encrypted signaling
crypto
audited WebCrypto, nothing home-made
05CRYPTOGRAPHY · E2EEOpen source

Ratchet

An end-to-end encrypted messenger where even a compromised server reads nothing.

↳ Reused in Yamor, a private messenger for couples.

  1. X3DH
  2. Double Ratchet
  3. blind relay
  4. decrypted on device
TESTS
91
SECURITY INVARIANTS
6
READABLE BYTES SERVER-SIDE
0
Strict TypeScriptReact 19WebCryptoSupabaseWebRTCPWA
VIEW THE CODE ↗
Under the hood
THE PROBLEM

Most "encrypted chats" wrap the message in AES and stop there.

THE DECISION

Implement Signal's actual protocol, with audited primitives only, and document what it does not protect (metadata, a compromised device).

INVARIANTS ENFORCED BY TESTS
private key never leaves the device GCM nonce never reused with the same key header authenticated as AAD backup ratchet state excluded by construction
~/cspm-lite
detects
public S3 · open SSH · no MFA
standard
CIS Benchmark
outputs
JSON (machine) + HTML (human)
in CI
critical flaw → build blocked
06CLOUD SECURITY · CLIPersonal tool

CSPM-Lite

Scans an AWS account and blocks the deployment when a critical flaw shows up.

  1. AWS account
  2. CIS checks
  3. JSON + HTML report
  4. CI gate
BENCHMARK
CIS
REPORT FORMATS
2
ACTIVE BLOCKING
CI
Pythonboto3CIS BenchmarkGitHub Actions
PRIVATE REPO · DEMO ON REQUEST
Under the hood
THE PROBLEM

A cloud misconfiguration does not show up in code review. It shows up in production, or in a leak.

THE DECISION

Nobody reads a report: the check becomes a gate that stops the pipeline.

$ cspm-lite scan --account prod --gate
scan → detection → CIS compliance → prioritisation → JSON + HTML reports → critical flaw → exit 1
A selection of six. The rest are on GitHub ↗
02 · ./PRINCIPLES --APPLIED

Three rules, held everywhere

Not slogans: each one is verified by code.

PRINCIPLE I

AI where it helps, code where it has to be right

An LLM reads and rephrases very well. A score, a credit, a decision come out of a tested function.

✓Carrivdeterministic ATS score✓StudyLuminaLLM-free score✓Job RadarLLM-free ranking
PRINCIPLE II

An untested invariant does not exist

A product rule that does not fail CI is only a wish.

✓Sanadefacts ⇸ projections, tested✓Ratchetno key on the wire✓Coloursno hardcoded literals
PRINCIPLE III

A runtime constraint is a design constraint

Timeouts, rate limits, a dying Lambda: parameters, not accidents.

✓Carriv90 s < Lambda lifetime✓Creditreserved before the call✓Job Radar~1 req/s per domain
03 · EVERY TOOL, ITS PROOF

Stack

PRODUCT & BACKEND
  • Strict TypeScripteverywhere
  • Next.js · SvelteKit · ReactCarriv · StudyLumina · Sanade
  • Node.js · tRPCSanade · Job Radar
  • Expo · React NativeSanade
  • PythonCSPM-Lite
  • C / C++Polytechnique
CLOUD & DATA
  • PostgreSQL · PrismaStudyLumina · Sanade
  • pgvector · hybrid RAGStudyLumina
  • MongoDBCarriv
  • BullMQ · RedisStudyLumina
  • AWS · Vercel · serverlessCarriv · CSPM-Lite
  • Docker · Linuxeverywhere
SECURITY
  • Applied cryptographyRatchet
  • Payments · signed webhooksCarriv · StudyLumina
  • Cloud posture · CIS · IAMCSPM-Lite
  • Authentication · hashed tokensCarriv
  • Network reconnaissanceTryHackMe
04 · SWIPE →

Career path

→ DEC. 2027

B.Eng. computer engineering

Polytechnique Montréal
Cybersecurity : ADistributed systems & cloud : B+GPA : 3.65 (winter 2026)
2025-2026

Projects built solo

3 in production · more in the lab
Carriv · StudyLumina · SanadeJob Radar · Ratchet · CSPM-Lite
SINCE OCT. 2024

Brand representative

Qualcomm / Snapdragon PC

Making a technology clear in two minutes, to anyone.

MILESTONES

Certifications & languages

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

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

An internship where I touch production: pipeline, security, data. Reply within 24 h.

MONTRÉAL, QCUTC-5FR / ENAVAILABLE 2027