[{"data":1,"prerenderedAt":426},["ShallowReactive",2],{"nav-stories":3,"footer-stories":61,"project-cloudform-ui":74},[4,16,25,34,43,52],{"id":5,"color":6,"extension":7,"image":8,"label":9,"link":10,"meta":11,"order":12,"stem":13,"text":14,"__hash__":15},"stories\u002Fstories\u002F01-data-center.yml",null,"yml","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1558494949-ef010cbdcc31?w=1080","DATA_CENTER","https:\u002F\u002Fx.com\u002Fabbeytetteh_",{},1,"stories\u002F01-data-center","Racking new servers. 40gbit backbone online.","0QUZQbaANhdO8WemZxkDdO7vbVopfnynHtH9FxBZb_w",{"id":17,"color":6,"extension":7,"image":18,"label":19,"link":6,"meta":20,"order":21,"stem":22,"text":23,"__hash__":24},"stories\u002Fstories\u002F02-thoughts.yml","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1498050108023-c5249f4df085?w=1080","THOUGHTS",{},2,"stories\u002F02-thoughts","Late night bug hunting. Found the memory leak.","Gd1am954aasY6HRHD7hCtOuessXb6zYZ8iizS501ICg",{"id":26,"color":27,"extension":7,"image":6,"label":28,"link":6,"meta":29,"order":30,"stem":31,"text":32,"__hash__":33},"stories\u002Fstories\u002F03-coding.yml","#3b82f6","CODING",{},3,"stories\u002F03-coding","Just thinking about how much easier life is with Swarm.","vLAyiGUPtlXB2SHa5KM_U2AaK4QkG3Og85UEUE7qzgM",{"id":35,"color":6,"extension":7,"image":36,"label":37,"link":6,"meta":38,"order":39,"stem":40,"text":41,"__hash__":42},"stories\u002Fstories\u002F04-update.yml","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1591799264318-7e6ef8ddb7ea?w=1080","UPDATE",{},4,"stories\u002F04-update","New cluster nodes arrived. Prepping for installation.","kyT60N5C6Re_jMonZbgNy0PbQhzXmUWxDbD0D_v43ts",{"id":44,"color":45,"extension":7,"image":6,"label":46,"link":6,"meta":47,"order":48,"stem":49,"text":50,"__hash__":51},"stories\u002Fstories\u002F05-setup.yml","#86868b","SETUP",{},5,"stories\u002F05-setup","Optimizing the telemetry pipeline for 1M req\u002Fs.","cPOBkzoyXsCmPgRO2d80Hj3vm4MP-6nAejtlQ5iuSzw",{"id":53,"color":6,"extension":7,"image":54,"label":55,"link":6,"meta":56,"order":57,"stem":58,"text":59,"__hash__":60},"stories\u002Fstories\u002F06-travel.yml","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1560969184-10fe8719e047?w=1080","TRAVEL",{},6,"stories\u002F06-travel","Travel log — system architecture workshop in Berlin.","jnOxerdF6usAIHdR35Z-opx0LJAy9kZluXnZhtz62Z0",[62,64,66,68,70,72],{"id":5,"color":6,"extension":7,"image":8,"label":9,"link":10,"meta":63,"order":12,"stem":13,"text":14,"__hash__":15},{},{"id":17,"color":6,"extension":7,"image":18,"label":19,"link":6,"meta":65,"order":21,"stem":22,"text":23,"__hash__":24},{},{"id":26,"color":27,"extension":7,"image":6,"label":28,"link":6,"meta":67,"order":30,"stem":31,"text":32,"__hash__":33},{},{"id":35,"color":6,"extension":7,"image":36,"label":37,"link":6,"meta":69,"order":39,"stem":40,"text":41,"__hash__":42},{},{"id":44,"color":45,"extension":7,"image":6,"label":46,"link":6,"meta":71,"order":48,"stem":49,"text":50,"__hash__":51},{},{"id":53,"color":6,"extension":7,"image":54,"label":55,"link":6,"meta":73,"order":57,"stem":58,"text":59,"__hash__":60},{},{"id":75,"title":76,"body":77,"description":416,"extension":417,"hash":418,"liveUrl":6,"meta":419,"navigation":214,"order":48,"path":420,"rackBay":6,"rackStatus":6,"region":421,"seo":422,"stem":423,"thumbnail":424,"vault":214,"__hash__":425},"projects\u002Fprojects\u002Fcloudform-ui.md","Cloudform UI",{"type":78,"value":79,"toc":411},"minimark",[80,84,89,92,380,384,400,404,407],[81,82,83],"p",{},"Cloudform UI is the control plane interface for the private cloud. It provides operators with a live view of cluster state, service health, and resource utilisation without requiring SSH access to manager nodes.",[85,86,88],"h2",{"id":87},"stack","Stack",[81,90,91],{},"Built on Nuxt 4 with TypeScript throughout. The real-time data layer uses Server-Sent Events — a simpler and more reliable transport than WebSockets for unidirectional state streaming.",[93,94,99],"pre",{"className":95,"code":96,"language":97,"meta":98,"style":98},"language-typescript shiki shiki-themes vitesse-light","\u002F\u002F server\u002Froutes\u002Fstream\u002Fcluster.ts\nexport default defineEventHandler(async (event) => {\n  setHeader(event, 'Content-Type', 'text\u002Fevent-stream')\n  setHeader(event, 'Cache-Control', 'no-cache')\n\n  const send = (data: ClusterState) => {\n    event.node.res.write(`data: ${JSON.stringify(data)}\\n\\n`)\n  }\n\n  const unsubscribe = clusterBus.subscribe(send)\n  event.node.req.on('close', unsubscribe)\n})\n","typescript","",[100,101,102,110,147,182,210,216,245,303,309,314,338,374],"code",{"__ignoreMap":98},[103,104,106],"span",{"class":105,"line":12},"line",[103,107,109],{"class":108},"s8zF2","\u002F\u002F server\u002Froutes\u002Fstream\u002Fcluster.ts\n",[103,111,112,116,119,123,127,131,134,138,141,144],{"class":105,"line":21},[103,113,115],{"class":114},"sbBg2","export",[103,117,118],{"class":114}," default",[103,120,122],{"class":121},"sySUi"," defineEventHandler",[103,124,126],{"class":125},"sYZai","(",[103,128,130],{"class":129},"si04Y","async",[103,132,133],{"class":125}," (",[103,135,137],{"class":136},"svycV","event",[103,139,140],{"class":125},")",[103,142,143],{"class":125}," =>",[103,145,146],{"class":125}," {\n",[103,148,149,152,154,156,159,163,167,170,172,174,177,179],{"class":105,"line":30},[103,150,151],{"class":121},"  setHeader",[103,153,126],{"class":125},[103,155,137],{"class":136},[103,157,158],{"class":125},",",[103,160,162],{"class":161},"sSP4y"," '",[103,164,166],{"class":165},"spphp","Content-Type",[103,168,169],{"class":161},"'",[103,171,158],{"class":125},[103,173,162],{"class":161},[103,175,176],{"class":165},"text\u002Fevent-stream",[103,178,169],{"class":161},[103,180,181],{"class":125},")\n",[103,183,184,186,188,190,192,194,197,199,201,203,206,208],{"class":105,"line":39},[103,185,151],{"class":121},[103,187,126],{"class":125},[103,189,137],{"class":136},[103,191,158],{"class":125},[103,193,162],{"class":161},[103,195,196],{"class":165},"Cache-Control",[103,198,169],{"class":161},[103,200,158],{"class":125},[103,202,162],{"class":161},[103,204,205],{"class":165},"no-cache",[103,207,169],{"class":161},[103,209,181],{"class":125},[103,211,212],{"class":105,"line":48},[103,213,215],{"emptyLinePlaceholder":214},true,"\n",[103,217,218,221,224,227,229,232,235,239,241,243],{"class":105,"line":57},[103,219,220],{"class":129},"  const ",[103,222,223],{"class":121},"send",[103,225,226],{"class":125}," =",[103,228,133],{"class":125},[103,230,231],{"class":136},"data",[103,233,234],{"class":125},": ",[103,236,238],{"class":237},"sUxyF","ClusterState",[103,240,140],{"class":125},[103,242,143],{"class":125},[103,244,146],{"class":125},[103,246,248,251,254,257,259,262,264,267,269,272,275,278,281,283,286,288,290,292,295,299,301],{"class":105,"line":247},7,[103,249,250],{"class":136},"    event",[103,252,253],{"class":125},".",[103,255,256],{"class":136},"node",[103,258,253],{"class":125},[103,260,261],{"class":136},"res",[103,263,253],{"class":125},[103,265,266],{"class":121},"write",[103,268,126],{"class":125},[103,270,271],{"class":161},"`",[103,273,274],{"class":165},"data: ",[103,276,277],{"class":114},"${",[103,279,280],{"class":165},"JSON",[103,282,253],{"class":125},[103,284,285],{"class":121},"stringify",[103,287,126],{"class":125},[103,289,231],{"class":165},[103,291,140],{"class":125},[103,293,294],{"class":114},"}",[103,296,298],{"class":297},"sEi1f","\\n\\n",[103,300,271],{"class":161},[103,302,181],{"class":125},[103,304,306],{"class":105,"line":305},8,[103,307,308],{"class":125},"  }\n",[103,310,312],{"class":105,"line":311},9,[103,313,215],{"emptyLinePlaceholder":214},[103,315,317,319,322,324,327,329,332,334,336],{"class":105,"line":316},10,[103,318,220],{"class":129},[103,320,321],{"class":136},"unsubscribe",[103,323,226],{"class":125},[103,325,326],{"class":136}," clusterBus",[103,328,253],{"class":125},[103,330,331],{"class":121},"subscribe",[103,333,126],{"class":125},[103,335,223],{"class":136},[103,337,181],{"class":125},[103,339,341,344,346,348,350,353,355,358,360,362,365,367,369,372],{"class":105,"line":340},11,[103,342,343],{"class":136},"  event",[103,345,253],{"class":125},[103,347,256],{"class":136},[103,349,253],{"class":125},[103,351,352],{"class":136},"req",[103,354,253],{"class":125},[103,356,357],{"class":121},"on",[103,359,126],{"class":125},[103,361,169],{"class":161},[103,363,364],{"class":165},"close",[103,366,169],{"class":161},[103,368,158],{"class":125},[103,370,371],{"class":136}," unsubscribe",[103,373,181],{"class":125},[103,375,377],{"class":105,"line":376},12,[103,378,379],{"class":125},"})\n",[85,381,383],{"id":382},"key-features","Key Features",[385,386,387,391,394,397],"ul",{},[388,389,390],"li",{},"Live node map with per-hypervisor CPU, memory, and network I\u002FO",[388,392,393],{},"Service deployment UI with rollback-to-previous-version in two clicks",[388,395,396],{},"Audit log viewer showing all API calls with the operator identity and timestamp",[388,398,399],{},"Alert acknowledgement workflow integrated with PagerDuty",[85,401,403],{"id":402},"status","Status",[81,405,406],{},"Internal tool, not publicly accessible. Actively developed — next milestone is adding a resource quota management view for multi-tenant environments.",[408,409,410],"style",{},"html pre.shiki code .s8zF2, html code.shiki .s8zF2{--shiki-default:#A0ADA0}html pre.shiki code .sbBg2, html code.shiki .sbBg2{--shiki-default:#1E754F}html pre.shiki code .sySUi, html code.shiki .sySUi{--shiki-default:#59873A}html pre.shiki code .sYZai, html code.shiki .sYZai{--shiki-default:#999999}html pre.shiki code .si04Y, html code.shiki .si04Y{--shiki-default:#AB5959}html pre.shiki code .svycV, html code.shiki .svycV{--shiki-default:#B07D48}html pre.shiki code .sSP4y, html code.shiki .sSP4y{--shiki-default:#B5695977}html pre.shiki code .spphp, html code.shiki .spphp{--shiki-default:#B56959}html pre.shiki code .sUxyF, html code.shiki .sUxyF{--shiki-default:#2E8F82}html pre.shiki code .sEi1f, html code.shiki .sEi1f{--shiki-default:#A65E2B}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);}",{"title":98,"searchDepth":21,"depth":21,"links":412},[413,414,415],{"id":87,"depth":21,"text":88},{"id":382,"depth":21,"text":383},{"id":402,"depth":21,"text":403},"A reactive management dashboard for OpenStack clusters built with Nuxt 3 and TypeScript, providing real-time visibility into cluster state.","md","M3N4O5",{},"\u002Fprojects\u002Fcloudform-ui","EU-WEST-2",{"title":76,"description":416},"projects\u002Fcloudform-ui","\u002Fimages\u002Fthumbnails\u002Fcloudform-ui.png","Iz2PSS-_TOi34gAgOQDGl_IgzGUXCxWrs4PMu5k7mWs",1779361989360]