Cilt365

A clinical-grade skincare recommendation engine that turns a dermatologist-designed questionnaire into a personalized routine and product match, with clinical logic held as editable data rather than code.

Read as Markdown ↗
2026
Full Stack Developer
Neon Apps

Developed at

Neon Apps

Full Stack Developer

Cilt365 - Image 1
View full size

About This Project

The clinical logic belonged to dermatologists, not to me, so hardcoding it would have made every revision a deploy. I moved the whole rule surface into the database — questions, answer-to-fact mappings, axis calibration, clinical rules — and the engine reads it at request time, so doctors iterate without an engineer in the loop. The engine scores five clinical axes from the answer set, derives secondary facts, then runs a priority cascade of clinical safety modes to pick a routine branch and apply hard ingredient blocks before any product is considered. The real problem was making clinical revisions safe: each doctor revision arrives as a spec whose edge cases contradict the previous version, so I built a simulation harness that runs any answer set through the live engine, snapshots it, re-runs after a change, and diffs against a doctor-recorded expectation — encoding the doctor's own QA table as tests before touching the engine, which repeatedly caught new rules silently breaking older ones. I also drew a line between what recomputes and what freezes: presentation output derives on every read, so a fix retroactively repairs existing profiles with no migration and no resubmit, while the resolved skin type is frozen at submission so a threshold change never silently reclassifies someone who already has a result. That boundary is the difference between a fix and an incident.

Technologies

NestJSTypeScriptDrizzle ORMPostgreSQLRedisBullMQGoogle GeminiSharpNext.jsJestSwaggerSentry

Key Features

Clinical logic as data — questions, calibration, rules and labels are editable rows; dermatologists ship revisions without a deploy
Multi-axis scoring with a safety cascade — five clinical indices feed a prioritized mode resolver that applies hard ingredient blocks (pregnancy, active medication, diagnosed conditions) ahead of any recommendation
Simulation harness for clinical review — snapshot, re-run and diff any profile against a doctor-recorded expectation as the primary gate for validating a revision before release
Structurally isolated product catalog — recommendations query a separate read-only database, so the engine cannot mutate the product source of truth
Parallel engine versions behind a feature gate — two clinical models serve from one schema, letting a new one be validated on real traffic before cutover
Retroactive-by-design presentation layer — result labels recompute on read so fixes reach existing users instantly, while the resolved skin type stays frozen to prevent silent reclassification