[{"data":1,"prerenderedAt":402},["ShallowReactive",2],{"navigation":3,"page-projects,solinum":55},[4,8,12,16,51],{"title":5,"path":6,"stem":7},"Vivian SARAZIN","\u002F","1.index",{"title":9,"path":10,"stem":11},"AI","\u002Fai","ai",{"title":13,"path":14,"stem":15},"Misc","\u002Fmisc","misc",{"title":17,"path":18,"stem":19,"children":20},"Projects","\u002Fprojects","projects",[21,23,27,31,35,39,43,47],{"title":17,"path":18,"stem":22},"projects\u002Findex",{"title":24,"path":25,"stem":26},"David Poupon","\u002Fprojects\u002Fdavid-poupon","projects\u002Fdavid-poupon",{"title":28,"path":29,"stem":30},"Groupe Nomblot","\u002Fprojects\u002Fgroupe-nomblot","projects\u002Fgroupe-nomblot",{"title":32,"path":33,"stem":34},"My Grandmother's Recipe Notebooks","\u002Fprojects\u002Fles-cahiers-de-jeanine","projects\u002Fles-cahiers-de-jeanine",{"title":36,"path":37,"stem":38},"TrialFinder by OmiCure","\u002Fprojects\u002Fomicure","projects\u002Fomicure",{"title":40,"path":41,"stem":42},"PME Partner","\u002Fprojects\u002Fpme-partner","projects\u002Fpme-partner",{"title":44,"path":45,"stem":46},"Radiofrance","\u002Fprojects\u002Fradiofrance","projects\u002Fradiofrance",{"title":48,"path":49,"stem":50},"Solinum","\u002Fprojects\u002Fsolinum","projects\u002Fsolinum",{"title":52,"path":53,"stem":54},"Resume","\u002Fresume","resume",{"id":56,"title":48,"body":57,"description":395,"extension":396,"layout":397,"meta":398,"navigation":298,"path":49,"seo":400,"stem":50,"__hash__":401},"content\u002Fprojects\u002Fsolinum.md",{"type":58,"value":59,"toc":388},"minimark",[60,64,87,96,99,118,121,124,127,132,137,140,143,146,270,273,352,361,365,368,371,374,378,381,384],[61,62,48],"h1",{"id":63},"solinum",[65,66,67,68,75,76,80,81,86],"p",{},"Thanks to ",[69,70,74],"a",{"href":71,"rel":72},"https:\u002F\u002Fzenika.com\u002Fen-US\u002Fagency\u002Fbrest",[73],"nofollow","Zenika Brest",", I had the chance to work as a volunteer for ",[69,77,48],{"href":78,"rel":79},"https:\u002F\u002Fwww.solinum.org\u002F",[73]," via a ",[69,82,85],{"href":83,"rel":84},"https:\u002F\u002Fen.vendredi.cc\u002F",[73],"Vendredi"," partnership.",[65,88,89,90,95],{},"The job was pretty straightforward, to setup an open-source tracking analytics solutions called ",[69,91,94],{"href":92,"rel":93},"https:\u002F\u002Fposthog.com\u002F",[73],"PostHog",".",[65,97,98],{},"Solinum's technical stack:",[100,101,102,106,109,112,115],"ul",{},[103,104,105],"li",{},"TypeScript",[103,107,108],{},"Express",[103,110,111],{},"Angular",[103,113,114],{},"Lerna",[103,116,117],{},"GitHub",[65,119,120],{},"As the mono-repository is well organized (real clean archi this time), it was quite fast to add some code.",[65,122,123],{},"The README.md was up-to-date (not a joke, a real README with instructions working like a charm!) and I started my journey in minutes.",[65,125,126],{},"The TypeScript implemetation was very handy too. I quickly stumbled upon all the types\u002Finterfaces needed for my first iteration.",[128,129,131],"h2",{"id":130},"code","Code",[133,134,136],"h3",{"id":135},"type-stuffs","Type stuffs",[65,138,139],{},"As described earlier, my job was to setup a tracking system. In order to avoid some fuzzy events, I suggested a simple tracking rule.",[65,141,142],{},"With TypeScript litterals this suggestion turned quite robust.",[65,144,145],{},"Type definition",[147,148,153],"pre",{"className":149,"code":150,"language":151,"meta":152,"style":152},"language-ts shiki shiki-themes github-dark github-light","type Action = \"EDIT\" | \"VIEW\";\ntype Feature = \"PLACE\" | \"SEARCH\";\ntype TrackedEvent = `${Action}_${Feature}`;\ntype TrackedEvents = { [T in TrackedEvent]?: Lowercase\u003CT> };\n","ts","",[130,154,155,185,205,232],{"__ignoreMap":152},[156,157,160,164,168,171,175,178,181],"span",{"class":158,"line":159},"line",1,[156,161,163],{"class":162},"scx8i","type",[156,165,167],{"class":166},"s-Z4r"," Action",[156,169,170],{"class":162}," =",[156,172,174],{"class":173},"sg6BJ"," \"EDIT\"",[156,176,177],{"class":162}," |",[156,179,180],{"class":173}," \"VIEW\"",[156,182,184],{"class":183},"sQ3_J",";\n",[156,186,188,190,193,195,198,200,203],{"class":158,"line":187},2,[156,189,163],{"class":162},[156,191,192],{"class":166}," Feature",[156,194,170],{"class":162},[156,196,197],{"class":173}," \"PLACE\"",[156,199,177],{"class":162},[156,201,202],{"class":173}," \"SEARCH\"",[156,204,184],{"class":183},[156,206,208,210,213,215,218,221,224,227,230],{"class":158,"line":207},3,[156,209,163],{"class":162},[156,211,212],{"class":166}," TrackedEvent",[156,214,170],{"class":162},[156,216,217],{"class":173}," `${",[156,219,220],{"class":166},"Action",[156,222,223],{"class":173},"}_${",[156,225,226],{"class":166},"Feature",[156,228,229],{"class":173},"}`",[156,231,184],{"class":183},[156,233,235,237,240,242,245,248,251,253,256,259,262,265,267],{"class":158,"line":234},4,[156,236,163],{"class":162},[156,238,239],{"class":166}," TrackedEvents",[156,241,170],{"class":162},[156,243,244],{"class":183}," { [",[156,246,247],{"class":166},"T",[156,249,250],{"class":162}," in",[156,252,212],{"class":166},[156,254,255],{"class":183},"]",[156,257,258],{"class":162},"?:",[156,260,261],{"class":166}," Lowercase",[156,263,264],{"class":183},"\u003C",[156,266,247],{"class":166},[156,268,269],{"class":183},"> };\n",[65,271,272],{},"Constants",[147,274,276],{"className":149,"code":275,"language":151,"meta":152,"style":152},"import { TrackedEvents } from \"..\u002Ftypes\u002FTrackedEvents.type\";\n\nexport const TRACKED_EVENTS = {\n  VIEW_PLACE: \"view_place\",\n  EDIT_SEARCH: \"edit_search\",\n} satisfies TrackedEvents;\n",[130,277,278,294,300,317,328,339],{"__ignoreMap":152},[156,279,280,283,286,289,292],{"class":158,"line":159},[156,281,282],{"class":162},"import",[156,284,285],{"class":183}," { TrackedEvents } ",[156,287,288],{"class":162},"from",[156,290,291],{"class":173}," \"..\u002Ftypes\u002FTrackedEvents.type\"",[156,293,184],{"class":183},[156,295,296],{"class":158,"line":187},[156,297,299],{"emptyLinePlaceholder":298},true,"\n",[156,301,302,305,308,312,314],{"class":158,"line":207},[156,303,304],{"class":162},"export",[156,306,307],{"class":162}," const",[156,309,311],{"class":310},"s0DvM"," TRACKED_EVENTS",[156,313,170],{"class":162},[156,315,316],{"class":183}," {\n",[156,318,319,322,325],{"class":158,"line":234},[156,320,321],{"class":183},"  VIEW_PLACE: ",[156,323,324],{"class":173},"\"view_place\"",[156,326,327],{"class":183},",\n",[156,329,331,334,337],{"class":158,"line":330},5,[156,332,333],{"class":183},"  EDIT_SEARCH: ",[156,335,336],{"class":173},"\"edit_search\"",[156,338,327],{"class":183},[156,340,342,345,348,350],{"class":158,"line":341},6,[156,343,344],{"class":183},"} ",[156,346,347],{"class":162},"satisfies",[156,349,239],{"class":166},[156,351,184],{"class":183},[65,353,354,355,360],{},"The const declaration avoid the ",[69,356,359],{"href":357,"rel":358},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=jjMbPt_H3RQ",[73],"enum problem"," and the satisfies operator ensure a magical inference.",[133,362,364],{"id":363},"refactor","Refactor",[65,366,367],{},"By removing the former analytics integration (MongoDB documents), I managed to delete a bunch of files\u002Flines. Always cool.",[65,369,370],{},"I also took the initiative to refactor some specs with the infamous jest it.each method.",[65,372,373],{},"A use case where ChatGPT is delightful.",[128,375,377],{"id":376},"conclusion","Conclusion",[65,379,380],{},"I had a lot of fun to do this tiny project. It helps a lot to work with other ways of coding.",[65,382,383],{},"Next time, I will stick more closely with my favorites craft paradigms (baby steps and mob programming) in order to ship even faster.",[385,386,387],"style",{},"html pre.shiki code .scx8i, html code.shiki .scx8i{--shiki-dark:#F97583;--shiki-default:#D73A49}html pre.shiki code .s-Z4r, html code.shiki .s-Z4r{--shiki-dark:#B392F0;--shiki-default:#6F42C1}html pre.shiki code .sg6BJ, html code.shiki .sg6BJ{--shiki-dark:#9ECBFF;--shiki-default:#032F62}html pre.shiki code .sQ3_J, html code.shiki .sQ3_J{--shiki-dark:#E1E4E8;--shiki-default:#24292E}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s0DvM, html code.shiki .s0DvM{--shiki-dark:#79B8FF;--shiki-default:#005CC5}",{"title":152,"searchDepth":187,"depth":187,"links":389},[390,394],{"id":130,"depth":187,"text":131,"children":391},[392,393],{"id":135,"depth":207,"text":136},{"id":363,"depth":207,"text":364},{"id":376,"depth":187,"text":377},"A very cool non-profit mission","md",null,{"stack":399},[105,108,94],{"title":48,"description":395},"m5gz12d9ATxsto0_nCrkyzJHgkZFKvHLZG4kxKtu3Fs",1785077665245]