[{"data":1,"prerenderedAt":638},["ShallowReactive",2],{"palette-work":3,"case-ld-platform":381,"work-all":423},[4,106,182,252,314],{"id":5,"title":6,"body":7,"client":85,"description":78,"extension":86,"meta":87,"navigation":88,"order":89,"path":90,"role":91,"seo":92,"stack":93,"status":99,"stem":100,"summary":101,"surface":102,"thesis":103,"year":104,"__hash__":105},"work\u002Fwork\u002Fejaad.md","Ejaad.ai",{"type":8,"value":9,"toc":77},"minimark",[10,15,19,22,26,31,39,43,51,63,70,74],[11,12,14],"h2",{"id":13},"context","Context",[16,17,18],"p",{},"Ejaad.ai is an AI-powered platform focused on education and workforce\ndevelopment. AI products have a specific production problem: the interesting\npart — generation — is slow, unreliable, and priced per call. A request\u002Fresponse\nmental model collapses the first time a model takes ninety seconds or a\nprovider times out.",[16,20,21],{},"I led the team as Team Lead, owning architecture, code reviews, and feature\nplanning alongside hands-on frontend and backend work.",[11,23,25],{"id":24},"the-system","The system",[27,28],"arch-diagram",{":layers":29,"caption":30},"[{\"label\":\"Client\",\"nodes\":[\"Nuxt 3 app\",\"Realtime status\"]},{\"label\":\"API & orchestration\",\"nodes\":[\"Nitro server routes\",\"BullMQ queues\",\"Workers\"]},{\"label\":\"Data & providers\",\"nodes\":[\"Supabase \u002F Postgres\",\"Auth & storage\",\"AI providers\"]}]","Every AI operation is a job. The request cycle never waits on a model.",[16,32,33,34,38],{},"The rule that shaped everything: ",[35,36,37],"strong",{},"no HTTP request ever waits on a model.","\nEvery AI operation becomes a job — queued in BullMQ, processed by workers,\nits state written back to Postgres, its progress streamed to the client.",[11,40,42],{"id":41},"decisions","Decisions",[44,45,48],"decision-note",{"n":46,"title":47},"01","Jobs, not requests",[16,49,50],{},"Generation runs through BullMQ with explicit states — queued, active,\nretrying, failed, done. Retries and backoff live in the queue, not in\napplication code. When a provider degrades, jobs wait instead of erroring, and\nusers see honest progress instead of a spinner that lies.",[44,52,55],{"n":53,"title":54},"02","The queue is a product surface",[16,56,57,58,62],{},"Job state isn't hidden infrastructure — it is rendered. The frontend\nsubscribes to job progress and treats ",[59,60,61],"em",{},"pending"," as a designed state:\nskeletons that describe what is coming, cancellable work, resumable sessions.\nPerceived reliability comes from truthful intermediate states.",[44,64,67],{"n":65,"title":66},"03","Supabase as a boundary, not a backend",[16,68,69],{},"Auth, storage, and Postgres come from Supabase, but the app talks to its own\ntyped API layer. Provider-specific types never leak into components — which\nkept the option to move any piece without a rewrite.",[11,71,73],{"id":72},"outcome","Outcome",[16,75,76],{},"The platform ships AI features on infrastructure that fails gracefully and\nscales horizontally by adding workers. The team ships behind stable seams —\nprovider churn stays in one module. Still in production, still growing.",{"title":78,"searchDepth":79,"depth":79,"links":80},"",2,[81,82,83,84],{"id":13,"depth":79,"text":14},{"id":24,"depth":79,"text":25},{"id":41,"depth":79,"text":42},{"id":72,"depth":79,"text":73},"Alwasaet","md",{},true,1,"\u002Fwork\u002Fejaad","Team Lead · Fullstack",{"title":6,"description":78},[94,95,96,97,98],"Nuxt 3","TypeScript","Supabase","BullMQ","Postgres","In production","work\u002Fejaad","An AI-powered platform for education and workforce development — long-running AI work moved off the request cycle into an observable queue pipeline.","AI education & workforce platform","AI features fail in production for boring reasons. The interesting work was the queue.","2024 — present","2ULBt-S0DYTf4KqgTjAMnscym44ljR_o0wwapFAjOCA",{"id":107,"title":108,"body":109,"client":85,"description":78,"extension":86,"meta":168,"navigation":88,"order":79,"path":169,"role":170,"seo":171,"stack":172,"status":99,"stem":176,"summary":177,"surface":178,"thesis":179,"year":180,"__hash__":181},"work\u002Fwork\u002Flxp.md","Learning Experience Platform",{"type":8,"value":110,"toc":162},[111,113,116,123,125,129,131,137,143,157,159],[11,112,14],{"id":13},[16,114,115],{},"The LXP manages digital learning content and student engagement for\nenterprise deployments — courses, media, assessments, progress, and the\nadministrative machinery behind them, used by thousands of learners.",[16,117,118,119,122],{},"At that scale the hard problem isn't rendering. It's ",[35,120,121],{},"state",": server truth,\nsession identity, in-flight edits, and UI state, all with different lifetimes,\nall tangled together the moment someone reaches for one global store.",[11,124,25],{"id":24},[27,126],{":layers":127,"caption":128},"[{\"label\":\"Views\",\"nodes\":[\"Learner surfaces\",\"Authoring & admin\"]},{\"label\":\"State\",\"nodes\":[\"Pinia domain stores\",\"Session & auth\",\"Server cache\"]},{\"label\":\"Platform\",\"nodes\":[\"Typed REST client\",\"Auth boundary\",\"Content APIs\"]}]","State separated by lifetime, not by feature.",[11,130,42],{"id":41},[44,132,134],{"n":46,"title":133},"State sorted by lifetime",[16,135,136],{},"Server truth, session state, workflow drafts, and ephemeral UI state each get\na different home with different rules. Pinia stores map to domains, not\npages — a store outlives navigation, a component's state does not. Most\n\"state bugs\" stopped existing by classification alone.",[44,138,140],{"n":53,"title":139},"A component system with a spine",[16,141,142],{},"Reusable UI built as a layered system: primitives, composites, then\ndomain components. The rule that kept it honest — primitives never import\nfrom domains. Figma handoffs from product designers landed into an existing\nvocabulary instead of producing one-off screens.",[44,144,146],{"n":65,"title":145},"Auth as an architectural boundary",[16,147,148,149,152,153,156],{},"Authentication, token refresh, and permission checks live at the edge — route\nmiddleware and a typed client — never inside components. Screens ask\n",[59,150,151],{},"what may I show",", not ",[59,154,155],{},"how do I check",".",[11,158,73],{"id":72},[16,160,161],{},"A frontend that new developers navigate by convention instead of tribal\nknowledge. The component system now outlives individual features — screens\nare assembled, not built. Still the backbone of the company's learning\nproducts.",{"title":78,"searchDepth":79,"depth":79,"links":163},[164,165,166,167],{"id":13,"depth":79,"text":14},{"id":24,"depth":79,"text":25},{"id":41,"depth":79,"text":42},{"id":72,"depth":79,"text":73},{},"\u002Fwork\u002Flxp","Frontend Lead",{"title":108,"description":78},[94,173,95,174,175],"Vue 3","Pinia","REST","work\u002Flxp","A large-scale enterprise platform for digital learning content and student engagement — thousands of learners, one coherent frontend architecture.","Enterprise learning platform","At enterprise scale, the frontend problem is state. Everything else is decoration.","2023 — present","1aMCy4Fo2a4uGnEebtxiSnvM1PDLWSYAQ7XEHrnc9Sc",{"id":183,"title":184,"body":185,"client":85,"description":78,"extension":86,"meta":237,"navigation":88,"order":238,"path":239,"role":240,"seo":241,"stack":242,"status":99,"stem":246,"summary":247,"surface":248,"thesis":249,"year":250,"__hash__":251},"work\u002Fwork\u002Fld-platform.md","Learning & Development Platform",{"type":8,"value":186,"toc":231},[187,189,196,198,202,204,214,220,226,228],[11,188,14],{"id":13},[16,190,191,192,195],{},"The L&D platform runs the full lifecycle of corporate learning: training\nprograms, enrollment requests, approvals, certification, graduation. The\ndeceptive part is that almost nothing in that list is a CRUD operation —\nan enrollment can wait days for a manager, escalate, expire, or get\noverridden. These are ",[59,193,194],{},"processes",", not records.",[11,197,25],{"id":24},[27,199],{":layers":200,"caption":201},"[{\"label\":\"Client\",\"nodes\":[\"Nuxt 3 app\",\"Live process views\"]},{\"label\":\"Process & realtime\",\"nodes\":[\"Camunda workflows\",\"WebSocket channel\",\"API layer\"]},{\"label\":\"Content & data\",\"nodes\":[\"Directus\",\"SQL database\",\"Certificates\"]}]","Process state lives in the engine. The UI renders it, live.",[11,203,42],{"id":41},[44,205,207],{"n":46,"title":206},"Workflows belong to an engine",[16,208,209,210,213],{},"Approval chains, timeouts, and escalations are modelled in Camunda — as\ndiagrams the business can read — instead of nested conditionals nobody can.\nWhen a policy changed, the ",[59,211,212],{},"diagram"," changed. Code that encodes policy rots;\nprocess models get reviewed.",[44,215,217],{"n":53,"title":216},"WebSockets for truth, not decoration",[16,218,219],{},"An approval can happen at any moment on someone else's screen. Process state\nstreams to every affected client, so the UI never shows a stale \"pending\"\nafter the decision is made. Realtime here isn't a feature — it's the\ndifference between a dashboard and a rumor.",[44,221,223],{"n":65,"title":222},"Directus for content, custom code for process",[16,224,225],{},"Structured content — programs, catalogs, materials — lives in Directus and\nis editable without a deploy. Process logic stays in code and Camunda.\nChoosing which half of the system deserves custom software is the\narchitecture.",[11,227,73],{"id":72},[16,229,230],{},"Enrollment-to-certification runs digitally end to end, with the approval\nchain visible to everyone inside it. Adopted as the operational backbone\nfor client training programs — and still in production today.",{"title":78,"searchDepth":79,"depth":79,"links":232},[233,234,235,236],{"id":13,"depth":79,"text":14},{"id":24,"depth":79,"text":25},{"id":41,"depth":79,"text":42},{"id":72,"depth":79,"text":73},{},3,"\u002Fwork\u002Fld-platform","Fullstack · Team Lead",{"title":184,"description":78},[94,95,243,244,245],"WebSockets","Directus","Camunda","work\u002Fld-platform","An enterprise platform for training, enrollment, and certification — human approval workflows orchestrated by Camunda, kept live over WebSockets.","Training, enrollment & certification","Enrollment isn't a form. It's a long-running process with humans inside it.","2022 — present","A_rqYsazIgnMyp00zqkVV3OZkttpVhMriOszIRezhjo",{"id":253,"title":254,"body":255,"client":85,"description":78,"extension":86,"meta":303,"navigation":88,"order":304,"path":305,"role":306,"seo":307,"stack":308,"status":99,"stem":309,"summary":310,"surface":311,"thesis":312,"year":180,"__hash__":313},"work\u002Fwork\u002Fdam.md","Digital Asset Management",{"type":8,"value":256,"toc":297},[257,259,262,264,268,270,276,282,292,294],[11,258,14],{"id":13},[16,260,261],{},"The DAM gives teams one place to store, organize, and reuse digital assets —\nimages, video, documents — across the company's platforms. On paper, a\ngrid with folders. In practice: thousands of heavy objects, previews,\nmetadata, permissions, and users who expect it to feel like a native file\nbrowser.",[11,263,25],{"id":24},[27,265],{":layers":266,"caption":267},"[{\"label\":\"Interface\",\"nodes\":[\"Library grid\",\"Preview & detail\",\"Pickers\"]},{\"label\":\"Access layer\",\"nodes\":[\"Windowed queries\",\"Upload pipeline\",\"Metadata cache\"]},{\"label\":\"Storage\",\"nodes\":[\"Asset store\",\"Renditions\",\"Permissions\"]}]","The interface only ever touches a window of the library.",[11,269,42],{"id":41},[44,271,273],{"n":46,"title":272},"Render the window, not the library",[16,274,275],{},"Virtualized grids and windowed queries mean the DOM holds what the viewport\nshows — scroll position, not dataset size, drives cost. The library feels\nidentical at fifty assets and at fifty thousand.",[44,277,279],{"n":53,"title":278},"Renditions over originals",[16,280,281],{},"The interface never loads an original until someone explicitly asks.\nGrids run on generated renditions sized for their context — the single\nbiggest performance win in the system, and invisible when it works.",[44,283,285],{"n":65,"title":284},"The picker is the product",[16,286,287,288,291],{},"The DAM's real users are ",[59,289,290],{},"other platforms"," — every \"insert media\" flow in\nthe suite opens DAM components. Built as embeddable modules with a stable\ncontract, one asset system serves every product without duplication.",[11,293,73],{"id":72},[16,295,296],{},"Asset workflows consolidated into one system that other products embed.\nMeasured and tuned rendering paths — fewer re-renders, lighter payloads,\nfaster time-to-grid — turned the heaviest dataset in the suite into one of\nits fastest-feeling interfaces.",{"title":78,"searchDepth":79,"depth":79,"links":298},[299,300,301,302],{"id":13,"depth":79,"text":14},{"id":24,"depth":79,"text":25},{"id":41,"depth":79,"text":42},{"id":72,"depth":79,"text":73},{},4,"\u002Fwork\u002Fdam","Frontend Engineer",{"title":254,"description":78},[94,173,95,175],"work\u002Fdam","Frontend modules for managing digital assets and media libraries — where the dataset is heavy, and the interface must never feel like it.","Asset & media library system","A media library is a performance problem wearing a UI.","DTWaqU_4xZt5ywf1K4UjWzQ9SvHKCaIMf8YsJ1dgIT4",{"id":315,"title":316,"body":317,"client":365,"description":78,"extension":86,"meta":366,"navigation":88,"order":367,"path":368,"role":369,"seo":370,"stack":371,"status":374,"stem":375,"summary":376,"surface":377,"thesis":378,"year":379,"__hash__":380},"work\u002Fwork\u002Fdztenders.md","DZ Tenders",{"type":8,"value":318,"toc":359},[319,321,324,326,330,332,338,348,354,356],[11,320,14],{"id":13},[16,322,323],{},"Public tenders in Algeria were scattered across print bulletins and PDFs —\nfindable only if you already knew where to look. DZ Tenders turned that\nfirehose into a searchable, filterable platform where businesses discover\nand manage the government contracts relevant to them.",[11,325,25],{"id":24},[27,327],{":layers":328,"caption":329},"[{\"label\":\"Client\",\"nodes\":[\"Vue.js interface\",\"Search & filters\",\"Tracked tenders\"]},{\"label\":\"API\",\"nodes\":[\"Django REST\",\"Query & ranking\"]},{\"label\":\"Data\",\"nodes\":[\"Postgres\",\"Tender ingestion\"]}]","A dense-data reading interface over a Django API.",[11,331,42],{"id":41},[44,333,335],{"n":46,"title":334},"Design for scanning, not reading",[16,336,337],{},"Tender listings are dense — deadlines, sectors, regions, authorities. The\ninterface is typographic: strict hierarchy, tabular rhythm, no cards, no\nchrome. Users scan hundreds of records; every pixel that isn't information\nis friction.",[44,339,341],{"n":53,"title":340},"Filters as state, URLs as truth",[16,342,343,344,347],{},"Every search is a shareable URL. Filter state lives in the query string, so\na saved link ",[59,345,346],{},"is"," a saved search — the simplest possible sync feature, and\nusers treated it as one.",[44,349,351],{"n":65,"title":350},"A maintainable frontend, on purpose",[16,352,353],{},"Built early in my career and maintained after — which taught the lesson the\nhard way: boring, explicit Vue components survive handoffs. Cleverness is a\ncost you pay later.",[11,355,73],{"id":72},[16,357,358],{},"Businesses that relied on print bulletins got same-day, filtered access to\npublic contracts. The platform shipped to production and shaped how I've\nbuilt reading-heavy interfaces since: performance, usability, and\nmaintainable frontend architecture as the spec — not the aspiration.",{"title":78,"searchDepth":79,"depth":79,"links":360},[361,362,363,364],{"id":13,"depth":79,"text":14},{"id":24,"depth":79,"text":25},{"id":41,"depth":79,"text":42},{"id":72,"depth":79,"text":73},"Rym Services Express",{},5,"\u002Fwork\u002Fdztenders","Fullstack Developer",{"title":316,"description":78},[372,373,98,175],"Vue.js","Django","Shipped","work\u002Fdztenders","A public procurement platform where Algerian businesses discover and track government tenders — dense civic data made searchable and legible.","Public procurement platform","Civic data is only useful at the speed of search.","2021","TZF39R2DyuUJzbo7InirCTrmTfVR08lrU4nSNeCCzd8",{"id":183,"title":184,"body":382,"client":85,"description":78,"extension":86,"meta":420,"navigation":88,"order":238,"path":239,"role":240,"seo":421,"stack":422,"status":99,"stem":246,"summary":247,"surface":248,"thesis":249,"year":250,"__hash__":251},{"type":8,"value":383,"toc":414},[384,386,390,392,394,396,402,406,410,412],[11,385,14],{"id":13},[16,387,191,388,195],{},[59,389,194],{},[11,391,25],{"id":24},[27,393],{":layers":200,"caption":201},[11,395,42],{"id":41},[44,397,398],{"n":46,"title":206},[16,399,209,400,213],{},[59,401,212],{},[44,403,404],{"n":53,"title":216},[16,405,219],{},[44,407,408],{"n":65,"title":222},[16,409,225],{},[11,411,73],{"id":72},[16,413,230],{},{"title":78,"searchDepth":79,"depth":79,"links":415},[416,417,418,419],{"id":13,"depth":79,"text":14},{"id":24,"depth":79,"text":25},{"id":41,"depth":79,"text":42},{"id":72,"depth":79,"text":73},{},{"title":184,"description":78},[94,95,243,244,245],[424,470,516,558,598],{"id":5,"title":6,"body":425,"client":85,"description":78,"extension":86,"meta":467,"navigation":88,"order":89,"path":90,"role":91,"seo":468,"stack":469,"status":99,"stem":100,"summary":101,"surface":102,"thesis":103,"year":104,"__hash__":105},{"type":8,"value":426,"toc":461},[427,429,431,433,435,437,441,443,447,453,457,459],[11,428,14],{"id":13},[16,430,18],{},[16,432,21],{},[11,434,25],{"id":24},[27,436],{":layers":29,"caption":30},[16,438,33,439,38],{},[35,440,37],{},[11,442,42],{"id":41},[44,444,445],{"n":46,"title":47},[16,446,50],{},[44,448,449],{"n":53,"title":54},[16,450,57,451,62],{},[59,452,61],{},[44,454,455],{"n":65,"title":66},[16,456,69],{},[11,458,73],{"id":72},[16,460,76],{},{"title":78,"searchDepth":79,"depth":79,"links":462},[463,464,465,466],{"id":13,"depth":79,"text":14},{"id":24,"depth":79,"text":25},{"id":41,"depth":79,"text":42},{"id":72,"depth":79,"text":73},{},{"title":6,"description":78},[94,95,96,97,98],{"id":107,"title":108,"body":471,"client":85,"description":78,"extension":86,"meta":513,"navigation":88,"order":79,"path":169,"role":170,"seo":514,"stack":515,"status":99,"stem":176,"summary":177,"surface":178,"thesis":179,"year":180,"__hash__":181},{"type":8,"value":472,"toc":507},[473,475,477,481,483,485,487,491,495,503,505],[11,474,14],{"id":13},[16,476,115],{},[16,478,118,479,122],{},[35,480,121],{},[11,482,25],{"id":24},[27,484],{":layers":127,"caption":128},[11,486,42],{"id":41},[44,488,489],{"n":46,"title":133},[16,490,136],{},[44,492,493],{"n":53,"title":139},[16,494,142],{},[44,496,497],{"n":65,"title":145},[16,498,148,499,152,501,156],{},[59,500,151],{},[59,502,155],{},[11,504,73],{"id":72},[16,506,161],{},{"title":78,"searchDepth":79,"depth":79,"links":508},[509,510,511,512],{"id":13,"depth":79,"text":14},{"id":24,"depth":79,"text":25},{"id":41,"depth":79,"text":42},{"id":72,"depth":79,"text":73},{},{"title":108,"description":78},[94,173,95,174,175],{"id":183,"title":184,"body":517,"client":85,"description":78,"extension":86,"meta":555,"navigation":88,"order":238,"path":239,"role":240,"seo":556,"stack":557,"status":99,"stem":246,"summary":247,"surface":248,"thesis":249,"year":250,"__hash__":251},{"type":8,"value":518,"toc":549},[519,521,525,527,529,531,537,541,545,547],[11,520,14],{"id":13},[16,522,191,523,195],{},[59,524,194],{},[11,526,25],{"id":24},[27,528],{":layers":200,"caption":201},[11,530,42],{"id":41},[44,532,533],{"n":46,"title":206},[16,534,209,535,213],{},[59,536,212],{},[44,538,539],{"n":53,"title":216},[16,540,219],{},[44,542,543],{"n":65,"title":222},[16,544,225],{},[11,546,73],{"id":72},[16,548,230],{},{"title":78,"searchDepth":79,"depth":79,"links":550},[551,552,553,554],{"id":13,"depth":79,"text":14},{"id":24,"depth":79,"text":25},{"id":41,"depth":79,"text":42},{"id":72,"depth":79,"text":73},{},{"title":184,"description":78},[94,95,243,244,245],{"id":253,"title":254,"body":559,"client":85,"description":78,"extension":86,"meta":595,"navigation":88,"order":304,"path":305,"role":306,"seo":596,"stack":597,"status":99,"stem":309,"summary":310,"surface":311,"thesis":312,"year":180,"__hash__":313},{"type":8,"value":560,"toc":589},[561,563,565,567,569,571,575,579,585,587],[11,562,14],{"id":13},[16,564,261],{},[11,566,25],{"id":24},[27,568],{":layers":266,"caption":267},[11,570,42],{"id":41},[44,572,573],{"n":46,"title":272},[16,574,275],{},[44,576,577],{"n":53,"title":278},[16,578,281],{},[44,580,581],{"n":65,"title":284},[16,582,287,583,291],{},[59,584,290],{},[11,586,73],{"id":72},[16,588,296],{},{"title":78,"searchDepth":79,"depth":79,"links":590},[591,592,593,594],{"id":13,"depth":79,"text":14},{"id":24,"depth":79,"text":25},{"id":41,"depth":79,"text":42},{"id":72,"depth":79,"text":73},{},{"title":254,"description":78},[94,173,95,175],{"id":315,"title":316,"body":599,"client":365,"description":78,"extension":86,"meta":635,"navigation":88,"order":367,"path":368,"role":369,"seo":636,"stack":637,"status":374,"stem":375,"summary":376,"surface":377,"thesis":378,"year":379,"__hash__":380},{"type":8,"value":600,"toc":629},[601,603,605,607,609,611,615,621,625,627],[11,602,14],{"id":13},[16,604,323],{},[11,606,25],{"id":24},[27,608],{":layers":328,"caption":329},[11,610,42],{"id":41},[44,612,613],{"n":46,"title":334},[16,614,337],{},[44,616,617],{"n":53,"title":340},[16,618,343,619,347],{},[59,620,346],{},[44,622,623],{"n":65,"title":350},[16,624,353],{},[11,626,73],{"id":72},[16,628,358],{},{"title":78,"searchDepth":79,"depth":79,"links":630},[631,632,633,634],{"id":13,"depth":79,"text":14},{"id":24,"depth":79,"text":25},{"id":41,"depth":79,"text":42},{"id":72,"depth":79,"text":73},{},{"title":316,"description":78},[372,373,98,175],1787041281701]