[{"data":1,"prerenderedAt":1505},["ShallowReactive",2],{"ecosystem-page":3},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":5,"title":7,"description":8,"body":9,"_type":1499,"_id":1500,"_source":1501,"_file":1502,"_stem":1503,"_extension":1504},"/ecosystem","",false,"Ecosystem Architecture","How production projects connect as one intentional platform — shared ingress, embeds, and ops habits.",{"type":10,"children":11,"toc":1475},"root",[12,20,24,31,363,372,375,381,397,408,426,451,454,467,476,494,517,520,533,542,567,582,585,598,607,616,631,634,647,656,681,696,699,705,871,895,898,904,910,976,982,1036,1042,1073,1076,1082,1252,1255,1261,1309,1312,1318,1326,1400,1407,1451,1454,1469],{"type":13,"tag":14,"props":15,"children":16},"element","p",{},[17],{"type":18,"value":19},"text","These projects share ingress patterns, embeddable services, and repeatable ops habits—not five unrelated demos. The portfolio is the hub; production apps feed data back into it and into GitHub.",{"type":13,"tag":21,"props":22,"children":23},"hr",{},[],{"type":13,"tag":25,"props":26,"children":28},"h2",{"id":27},"architecture-overview",[29],{"type":18,"value":30},"Architecture overview",{"type":13,"tag":32,"props":33,"children":37},"pre",{"className":34,"code":35,"language":36,"meta":5,"style":5},"language-mermaid shiki shiki-themes github-dark github-dark-dimmed","flowchart TB\n  Users[\"Users / browsers\"]\n\n  subgraph apps[\"Apps\"]\n    Portfolio[\"jovylle.com\u003Cbr/>Nuxt portfolio + widget\"]\n    Playbase[\"fast.jovylle.com\u003Cbr/>Playbase reaction game\"]\n    D1G[\"d1g.uk\u003Cbr/>Desert digging tool\"]\n    ChatW[\"chat-widget.uft1.com\u003Cbr/>Embeddable GPT chat\"]\n  end\n\n  subgraph shared[\"Shared services\"]\n    CDN[\"content.jovylle.com\u003Cbr/>Project catalog + notifications\"]\n    Pocket[\"pocket.uft1.com\u003Cbr/>Highlights JSON\"]\n    PMate[\"projectmate.uft1.com\u003Cbr/>Feedback & updates overlay\"]\n  end\n\n  subgraph platform[\"Platform layer\"]\n    Netlify[\"Netlify\u003Cbr/>Build + serverless functions\"]\n    GH[\"GitHub\u003Cbr/>Repos + Actions\"]\n  end\n\n  Obs[\"Umami analytics\u003Cbr/>jovylle.com\"]\n\n  Users --> Portfolio\n  Users --> Playbase\n  Users --> D1G\n  Users --> ChatW\n  Portfolio --> Netlify\n  Portfolio --> Playbase\n  Portfolio --> Pocket\n  Portfolio --> PMate\n  Portfolio --> CDN\n  Playbase --> GH\n  GH --> CDN\n  GH --> Netlify\n  Users --> Obs\n","mermaid",[38],{"type":13,"tag":39,"props":40,"children":41},"code",{"__ignoreMap":5},[42,53,62,72,81,90,99,108,117,126,134,143,152,161,170,178,186,195,204,213,221,229,238,246,255,264,273,282,291,300,309,318,327,336,345,354],{"type":13,"tag":43,"props":44,"children":47},"span",{"class":45,"line":46},"line",1,[48],{"type":13,"tag":43,"props":49,"children":50},{},[51],{"type":18,"value":52},"flowchart TB\n",{"type":13,"tag":43,"props":54,"children":56},{"class":45,"line":55},2,[57],{"type":13,"tag":43,"props":58,"children":59},{},[60],{"type":18,"value":61},"  Users[\"Users / browsers\"]\n",{"type":13,"tag":43,"props":63,"children":65},{"class":45,"line":64},3,[66],{"type":13,"tag":43,"props":67,"children":69},{"emptyLinePlaceholder":68},true,[70],{"type":18,"value":71},"\n",{"type":13,"tag":43,"props":73,"children":75},{"class":45,"line":74},4,[76],{"type":13,"tag":43,"props":77,"children":78},{},[79],{"type":18,"value":80},"  subgraph apps[\"Apps\"]\n",{"type":13,"tag":43,"props":82,"children":84},{"class":45,"line":83},5,[85],{"type":13,"tag":43,"props":86,"children":87},{},[88],{"type":18,"value":89},"    Portfolio[\"jovylle.com\u003Cbr/>Nuxt portfolio + widget\"]\n",{"type":13,"tag":43,"props":91,"children":93},{"class":45,"line":92},6,[94],{"type":13,"tag":43,"props":95,"children":96},{},[97],{"type":18,"value":98},"    Playbase[\"fast.jovylle.com\u003Cbr/>Playbase reaction game\"]\n",{"type":13,"tag":43,"props":100,"children":102},{"class":45,"line":101},7,[103],{"type":13,"tag":43,"props":104,"children":105},{},[106],{"type":18,"value":107},"    D1G[\"d1g.uk\u003Cbr/>Desert digging tool\"]\n",{"type":13,"tag":43,"props":109,"children":111},{"class":45,"line":110},8,[112],{"type":13,"tag":43,"props":113,"children":114},{},[115],{"type":18,"value":116},"    ChatW[\"chat-widget.uft1.com\u003Cbr/>Embeddable GPT chat\"]\n",{"type":13,"tag":43,"props":118,"children":120},{"class":45,"line":119},9,[121],{"type":13,"tag":43,"props":122,"children":123},{},[124],{"type":18,"value":125},"  end\n",{"type":13,"tag":43,"props":127,"children":129},{"class":45,"line":128},10,[130],{"type":13,"tag":43,"props":131,"children":132},{"emptyLinePlaceholder":68},[133],{"type":18,"value":71},{"type":13,"tag":43,"props":135,"children":137},{"class":45,"line":136},11,[138],{"type":13,"tag":43,"props":139,"children":140},{},[141],{"type":18,"value":142},"  subgraph shared[\"Shared services\"]\n",{"type":13,"tag":43,"props":144,"children":146},{"class":45,"line":145},12,[147],{"type":13,"tag":43,"props":148,"children":149},{},[150],{"type":18,"value":151},"    CDN[\"content.jovylle.com\u003Cbr/>Project catalog + notifications\"]\n",{"type":13,"tag":43,"props":153,"children":155},{"class":45,"line":154},13,[156],{"type":13,"tag":43,"props":157,"children":158},{},[159],{"type":18,"value":160},"    Pocket[\"pocket.uft1.com\u003Cbr/>Highlights JSON\"]\n",{"type":13,"tag":43,"props":162,"children":164},{"class":45,"line":163},14,[165],{"type":13,"tag":43,"props":166,"children":167},{},[168],{"type":18,"value":169},"    PMate[\"projectmate.uft1.com\u003Cbr/>Feedback & updates overlay\"]\n",{"type":13,"tag":43,"props":171,"children":173},{"class":45,"line":172},15,[174],{"type":13,"tag":43,"props":175,"children":176},{},[177],{"type":18,"value":125},{"type":13,"tag":43,"props":179,"children":181},{"class":45,"line":180},16,[182],{"type":13,"tag":43,"props":183,"children":184},{"emptyLinePlaceholder":68},[185],{"type":18,"value":71},{"type":13,"tag":43,"props":187,"children":189},{"class":45,"line":188},17,[190],{"type":13,"tag":43,"props":191,"children":192},{},[193],{"type":18,"value":194},"  subgraph platform[\"Platform layer\"]\n",{"type":13,"tag":43,"props":196,"children":198},{"class":45,"line":197},18,[199],{"type":13,"tag":43,"props":200,"children":201},{},[202],{"type":18,"value":203},"    Netlify[\"Netlify\u003Cbr/>Build + serverless functions\"]\n",{"type":13,"tag":43,"props":205,"children":207},{"class":45,"line":206},19,[208],{"type":13,"tag":43,"props":209,"children":210},{},[211],{"type":18,"value":212},"    GH[\"GitHub\u003Cbr/>Repos + Actions\"]\n",{"type":13,"tag":43,"props":214,"children":216},{"class":45,"line":215},20,[217],{"type":13,"tag":43,"props":218,"children":219},{},[220],{"type":18,"value":125},{"type":13,"tag":43,"props":222,"children":224},{"class":45,"line":223},21,[225],{"type":13,"tag":43,"props":226,"children":227},{"emptyLinePlaceholder":68},[228],{"type":18,"value":71},{"type":13,"tag":43,"props":230,"children":232},{"class":45,"line":231},22,[233],{"type":13,"tag":43,"props":234,"children":235},{},[236],{"type":18,"value":237},"  Obs[\"Umami analytics\u003Cbr/>jovylle.com\"]\n",{"type":13,"tag":43,"props":239,"children":241},{"class":45,"line":240},23,[242],{"type":13,"tag":43,"props":243,"children":244},{"emptyLinePlaceholder":68},[245],{"type":18,"value":71},{"type":13,"tag":43,"props":247,"children":249},{"class":45,"line":248},24,[250],{"type":13,"tag":43,"props":251,"children":252},{},[253],{"type":18,"value":254},"  Users --> Portfolio\n",{"type":13,"tag":43,"props":256,"children":258},{"class":45,"line":257},25,[259],{"type":13,"tag":43,"props":260,"children":261},{},[262],{"type":18,"value":263},"  Users --> Playbase\n",{"type":13,"tag":43,"props":265,"children":267},{"class":45,"line":266},26,[268],{"type":13,"tag":43,"props":269,"children":270},{},[271],{"type":18,"value":272},"  Users --> D1G\n",{"type":13,"tag":43,"props":274,"children":276},{"class":45,"line":275},27,[277],{"type":13,"tag":43,"props":278,"children":279},{},[280],{"type":18,"value":281},"  Users --> ChatW\n",{"type":13,"tag":43,"props":283,"children":285},{"class":45,"line":284},28,[286],{"type":13,"tag":43,"props":287,"children":288},{},[289],{"type":18,"value":290},"  Portfolio --> Netlify\n",{"type":13,"tag":43,"props":292,"children":294},{"class":45,"line":293},29,[295],{"type":13,"tag":43,"props":296,"children":297},{},[298],{"type":18,"value":299},"  Portfolio --> Playbase\n",{"type":13,"tag":43,"props":301,"children":303},{"class":45,"line":302},30,[304],{"type":13,"tag":43,"props":305,"children":306},{},[307],{"type":18,"value":308},"  Portfolio --> Pocket\n",{"type":13,"tag":43,"props":310,"children":312},{"class":45,"line":311},31,[313],{"type":13,"tag":43,"props":314,"children":315},{},[316],{"type":18,"value":317},"  Portfolio --> PMate\n",{"type":13,"tag":43,"props":319,"children":321},{"class":45,"line":320},32,[322],{"type":13,"tag":43,"props":323,"children":324},{},[325],{"type":18,"value":326},"  Portfolio --> CDN\n",{"type":13,"tag":43,"props":328,"children":330},{"class":45,"line":329},33,[331],{"type":13,"tag":43,"props":332,"children":333},{},[334],{"type":18,"value":335},"  Playbase --> GH\n",{"type":13,"tag":43,"props":337,"children":339},{"class":45,"line":338},34,[340],{"type":13,"tag":43,"props":341,"children":342},{},[343],{"type":18,"value":344},"  GH --> CDN\n",{"type":13,"tag":43,"props":346,"children":348},{"class":45,"line":347},35,[349],{"type":13,"tag":43,"props":350,"children":351},{},[352],{"type":18,"value":353},"  GH --> Netlify\n",{"type":13,"tag":43,"props":355,"children":357},{"class":45,"line":356},36,[358],{"type":13,"tag":43,"props":359,"children":360},{},[361],{"type":18,"value":362},"  Users --> Obs\n",{"type":13,"tag":14,"props":364,"children":365},{},[366],{"type":13,"tag":367,"props":368,"children":369},"em",{},[370],{"type":18,"value":371},"Alt text: Architecture diagram showing browsers connecting to portfolio, Playbase, d1g.uk, and chat-widget; content.jovylle.com for catalog + notifications, pocket.uft1.com for highlights, projectmate.uft1.com for feedback; Netlify and GitHub as platform; Umami for site analytics.",{"type":13,"tag":21,"props":373,"children":374},{},[],{"type":13,"tag":25,"props":376,"children":378},{"id":377},"products-in-the-ecosystem",[379],{"type":18,"value":380},"Products in the ecosystem",{"type":13,"tag":382,"props":383,"children":385},"h3",{"id":384},"portfolio-jovyllecom",[386,388],{"type":18,"value":387},"Portfolio — ",{"type":13,"tag":389,"props":390,"children":394},"a",{"href":391,"rel":392},"https://jovylle.com",[393],"nofollow",[395],{"type":18,"value":396},"jovylle.com",{"type":13,"tag":14,"props":398,"children":399},{},[400,406],{"type":13,"tag":401,"props":402,"children":403},"strong",{},[404],{"type":18,"value":405},"Problem:",{"type":18,"value":407}," Recruiters need one place to see shipped work, not a scatter of repos.",{"type":13,"tag":14,"props":409,"children":410},{},[411,416,418,424],{"type":13,"tag":401,"props":412,"children":413},{},[414],{"type":18,"value":415},"Role in the platform:",{"type":18,"value":417}," Central hub. Nuxt 3 site on Netlify with a floating widget (AI chat, Playbase leaderboard, notifications), ProjectMate embed for feedback/updates, and a prerendered project archive fed by ",{"type":13,"tag":39,"props":419,"children":421},{"className":420},[],[422],{"type":18,"value":423},"content.jovylle.com",{"type":18,"value":425},".",{"type":13,"tag":14,"props":427,"children":428},{},[429,434,436,442,444],{"type":13,"tag":401,"props":430,"children":431},{},[432],{"type":18,"value":433},"Case study:",{"type":18,"value":435}," ",{"type":13,"tag":389,"props":437,"children":439},{"href":438},"/personal-projects",[440],{"type":18,"value":441},"Personal projects archive",{"type":18,"value":443}," · ",{"type":13,"tag":389,"props":445,"children":448},{"href":446,"rel":447},"https://github.com/jovylle/jovylle.com",[393],[449],{"type":18,"value":450},"GitHub",{"type":13,"tag":21,"props":452,"children":453},{},[],{"type":13,"tag":382,"props":455,"children":457},{"id":456},"d1guk-d1guk",[458,460],{"type":18,"value":459},"d1g.uk — ",{"type":13,"tag":389,"props":461,"children":464},{"href":462,"rel":463},"https://d1g.uk",[393],[465],{"type":18,"value":466},"d1g.uk",{"type":13,"tag":14,"props":468,"children":469},{},[470,474],{"type":13,"tag":401,"props":471,"children":472},{},[473],{"type":18,"value":405},{"type":18,"value":475}," Sunflower Land players need a fast, visual way to plan Desert digs when the in-game API only shows today.",{"type":13,"tag":14,"props":477,"children":478},{},[479,483,485,492],{"type":13,"tag":401,"props":480,"children":481},{},[482],{"type":18,"value":415},{"type":18,"value":484}," Highest-traffic standalone product in the ecosystem. Companion hub at ",{"type":13,"tag":389,"props":486,"children":489},{"href":487,"rel":488},"https://hub.d1g.uk",[393],[490],{"type":18,"value":491},"hub.d1g.uk",{"type":18,"value":493}," for saved/shared community grids. Shares the uft1/d1g domain family with other tools.",{"type":13,"tag":14,"props":495,"children":496},{},[497,501,502,509,510],{"type":13,"tag":401,"props":498,"children":499},{},[500],{"type":18,"value":433},{"type":18,"value":435},{"type":13,"tag":389,"props":503,"children":506},{"href":504,"rel":505},"https://github.com/jovylle/sfl-crab",[393],[507],{"type":18,"value":508},"GitHub — sfl-crab",{"type":18,"value":443},{"type":13,"tag":389,"props":511,"children":514},{"href":512,"rel":513},"https://d1g.uk/feedbacks",[393],[515],{"type":18,"value":516},"User feedback",{"type":13,"tag":21,"props":518,"children":519},{},[],{"type":13,"tag":382,"props":521,"children":523},{"id":522},"playbase-fastjovyllecom",[524,526],{"type":18,"value":525},"Playbase — ",{"type":13,"tag":389,"props":527,"children":530},{"href":528,"rel":529},"https://fast.jovylle.com",[393],[531],{"type":18,"value":532},"fast.jovylle.com",{"type":13,"tag":14,"props":534,"children":535},{},[536,540],{"type":13,"tag":401,"props":537,"children":538},{},[539],{"type":18,"value":405},{"type":18,"value":541}," A lightweight, replayable skill game that keeps score across sessions and surfaces results outside the game tab.",{"type":13,"tag":14,"props":543,"children":544},{},[545,549,551,557,559,565],{"type":13,"tag":401,"props":546,"children":547},{},[548],{"type":18,"value":415},{"type":18,"value":550}," Gamification layer. Reaction-test game with an all-time leaderboard JSON API (",{"type":13,"tag":39,"props":552,"children":554},{"className":553},[],[555],{"type":18,"value":556},"/reaction/top.json",{"type":18,"value":558},"). The portfolio widget proxies this via ",{"type":13,"tag":39,"props":560,"children":562},{"className":561},[],[563],{"type":18,"value":564},"/api/leaderboard",{"type":18,"value":566}," and links directly to play. Seasonal leaderboard is synced through GitHub Actions.",{"type":13,"tag":14,"props":568,"children":569},{},[570,574,575],{"type":13,"tag":401,"props":571,"children":572},{},[573],{"type":18,"value":433},{"type":18,"value":435},{"type":13,"tag":389,"props":576,"children":579},{"href":577,"rel":578},"https://github.com/jovylle/playbase",[393],[580],{"type":18,"value":581},"GitHub — playbase",{"type":13,"tag":21,"props":583,"children":584},{},[],{"type":13,"tag":382,"props":586,"children":588},{"id":587},"chat-widget-chat-widgetuft1com",[589,591],{"type":18,"value":590},"chat-widget — ",{"type":13,"tag":389,"props":592,"children":595},{"href":593,"rel":594},"https://chat-widget.uft1.com",[393],[596],{"type":18,"value":597},"chat-widget.uft1.com",{"type":13,"tag":14,"props":599,"children":600},{},[601,605],{"type":13,"tag":401,"props":602,"children":603},{},[604],{"type":18,"value":405},{"type":18,"value":606}," Drop a GPT-powered chatbot onto any site without rebuilding the host app.",{"type":13,"tag":14,"props":608,"children":609},{},[610,614],{"type":13,"tag":401,"props":611,"children":612},{},[613],{"type":18,"value":415},{"type":18,"value":615}," Reusable embed product (separate from the portfolio's own AI widget). Standalone script + Netlify/serverless backend pattern, same \"one script tag\" philosophy as ProjectMate.",{"type":13,"tag":14,"props":617,"children":618},{},[619,623,624],{"type":13,"tag":401,"props":620,"children":621},{},[622],{"type":18,"value":433},{"type":18,"value":435},{"type":13,"tag":389,"props":625,"children":628},{"href":626,"rel":627},"https://github.com/jovylle/chatbot-widget",[393],[629],{"type":18,"value":630},"GitHub — chatbot-widget",{"type":13,"tag":21,"props":632,"children":633},{},[],{"type":13,"tag":382,"props":635,"children":637},{"id":636},"projectmate-projectmateuft1com",[638,640],{"type":18,"value":639},"ProjectMate — ",{"type":13,"tag":389,"props":641,"children":644},{"href":642,"rel":643},"https://projectmate.uft1.com",[393],[645],{"type":18,"value":646},"projectmate.uft1.com",{"type":13,"tag":14,"props":648,"children":649},{},[650,654],{"type":13,"tag":401,"props":651,"children":652},{},[653],{"type":18,"value":405},{"type":18,"value":655}," Visitors need in-context feedback and release notes without leaving the page or opening GitHub Issues.",{"type":13,"tag":14,"props":657,"children":658},{},[659,663,665,671,673,679],{"type":13,"tag":401,"props":660,"children":661},{},[662],{"type":18,"value":415},{"type":18,"value":664}," Cross-site support overlay. Loaded on jovylle.com via ",{"type":13,"tag":39,"props":666,"children":668},{"className":667},[],[669],{"type":18,"value":670},"embed.js",{"type":18,"value":672}," with ",{"type":13,"tag":39,"props":674,"children":676},{"className":675},[],[677],{"type":18,"value":678},"projectId: jovylle-com",{"type":18,"value":680}," — feedback, updates, and about panel; chat disabled on portfolio. Same embed pattern can attach to other properties in the uft1.com family.",{"type":13,"tag":14,"props":682,"children":683},{},[684,688,689],{"type":13,"tag":401,"props":685,"children":686},{},[687],{"type":18,"value":433},{"type":18,"value":435},{"type":13,"tag":389,"props":690,"children":693},{"href":691,"rel":692},"https://github.com/jovylle/projectmate-embedded-app",[393],[694],{"type":18,"value":695},"GitHub — projectmate-embedded-app",{"type":13,"tag":21,"props":697,"children":698},{},[],{"type":13,"tag":25,"props":700,"children":702},{"id":701},"infrastructure-highlights",[703],{"type":18,"value":704},"Infrastructure highlights",{"type":13,"tag":706,"props":707,"children":708},"ul",{},[709,735,752,770,795,813,830,853],{"type":13,"tag":710,"props":711,"children":712},"li",{},[713,718,720,726,728,733],{"type":13,"tag":401,"props":714,"children":715},{},[716],{"type":18,"value":717},"Netlify for jovylle.com",{"type":18,"value":719}," — static Nuxt build, ",{"type":13,"tag":39,"props":721,"children":723},{"className":722},[],[724],{"type":18,"value":725},"/.netlify/functions/chatbot",{"type":18,"value":727}," for production AI chat, ",{"type":13,"tag":39,"props":729,"children":731},{"className":730},[],[732],{"type":18,"value":564},{"type":18,"value":734}," proxy in dev and prod.",{"type":13,"tag":710,"props":736,"children":737},{},[738,743,745,750],{"type":13,"tag":401,"props":739,"children":740},{},[741],{"type":18,"value":742},"Decoupled content CDN",{"type":18,"value":744}," — project catalog at ",{"type":13,"tag":39,"props":746,"children":748},{"className":747},[],[749],{"type":18,"value":423},{"type":18,"value":751},"; portfolio rebuild triggered by GitHub Actions → Netlify build hook after CDN publish (hook URL in GitHub secrets, not in git).",{"type":13,"tag":710,"props":753,"children":754},{},[755,760,762,768],{"type":13,"tag":401,"props":756,"children":757},{},[758],{"type":18,"value":759},"Notification bus",{"type":18,"value":761}," — ",{"type":13,"tag":39,"props":763,"children":765},{"className":764},[],[766],{"type":18,"value":767},"content.jovylle.com/notifications/index.json",{"type":18,"value":769}," feeds the portfolio widget's alert tab.",{"type":13,"tag":710,"props":771,"children":772},{},[773,778,779,785,787,793],{"type":13,"tag":401,"props":774,"children":775},{},[776],{"type":18,"value":777},"Highlights feed",{"type":18,"value":761},{"type":13,"tag":39,"props":780,"children":782},{"className":781},[],[783],{"type":18,"value":784},"pocket.uft1.com/data/highlights.json",{"type":18,"value":786}," powers ",{"type":13,"tag":39,"props":788,"children":790},{"className":789},[],[791],{"type":18,"value":792},"/highlights",{"type":18,"value":794}," and the widget highlights view.",{"type":13,"tag":710,"props":796,"children":797},{},[798,803,805,811],{"type":13,"tag":401,"props":799,"children":800},{},[801],{"type":18,"value":802},"Embeds over iframes where it matters",{"type":18,"value":804}," — ProjectMate overlay, portfolio widget (",{"type":13,"tag":39,"props":806,"children":808},{"className":807},[],[809],{"type":18,"value":810},"embed-inline.js",{"type":18,"value":812},"), and chat-widget each ship as a single async script.",{"type":13,"tag":710,"props":814,"children":815},{},[816,821,822,828],{"type":13,"tag":401,"props":817,"children":818},{},[819],{"type":18,"value":820},"Secrets out of repo",{"type":18,"value":761},{"type":13,"tag":39,"props":823,"children":825},{"className":824},[],[826],{"type":18,"value":827},"OPENAI_API_KEY",{"type":18,"value":829}," via Netlify env; build hooks via GitHub Actions secrets.",{"type":13,"tag":710,"props":831,"children":832},{},[833,838,839,844,846,851],{"type":13,"tag":401,"props":834,"children":835},{},[836],{"type":18,"value":837},"Prerender vs live fetch",{"type":18,"value":761},{"type":13,"tag":39,"props":840,"children":842},{"className":841},[],[843],{"type":18,"value":438},{"type":18,"value":845}," prerendered from CDN JSON at build time; ",{"type":13,"tag":39,"props":847,"children":849},{"className":848},[],[850],{"type":18,"value":792},{"type":18,"value":852}," fetches live at runtime (different freshness tradeoffs, intentional).",{"type":13,"tag":710,"props":854,"children":855},{},[856,861,863,869],{"type":13,"tag":401,"props":857,"children":858},{},[859],{"type":18,"value":860},"GitHub as integration bus",{"type":18,"value":862}," — profile automation repo (",{"type":13,"tag":39,"props":864,"children":866},{"className":865},[],[867],{"type":18,"value":868},"jovylle/jovylle",{"type":18,"value":870},", GitHub Actions), content rebuild webhooks, and Playbase leaderboard automation.",{"type":13,"tag":872,"props":873,"children":874},"blockquote",{},[875],{"type":13,"tag":14,"props":876,"children":877},{},[878,880,886,888,893],{"type":18,"value":879},"Edge/CDN provider for ",{"type":13,"tag":39,"props":881,"children":883},{"className":882},[],[884],{"type":18,"value":885},"uft1.com",{"type":18,"value":887}," and ",{"type":13,"tag":39,"props":889,"children":891},{"className":890},[],[892],{"type":18,"value":466},{"type":18,"value":894},", and chat-widget consumer sites, are intentionally not listed publicly until confirmed.",{"type":13,"tag":21,"props":896,"children":897},{},[],{"type":13,"tag":25,"props":899,"children":901},{"id":900},"cross-project-flows",[902],{"type":18,"value":903},"Cross-project flows",{"type":13,"tag":382,"props":905,"children":907},{"id":906},"_1-play-score-portfolio-and-github",[908],{"type":18,"value":909},"1. Play → score → portfolio (and GitHub)",{"type":13,"tag":911,"props":912,"children":913},"ol",{},[914,925,937,956],{"type":13,"tag":710,"props":915,"children":916},{},[917,919,924],{"type":18,"value":918},"User plays the reaction test at ",{"type":13,"tag":389,"props":920,"children":922},{"href":528,"rel":921},[393],[923],{"type":18,"value":532},{"type":18,"value":425},{"type":13,"tag":710,"props":926,"children":927},{},[928,930,936],{"type":18,"value":929},"Score is persisted server-side; top entries exposed at ",{"type":13,"tag":39,"props":931,"children":933},{"className":932},[],[934],{"type":18,"value":935},"https://fast.jovylle.com/reaction/top.json",{"type":18,"value":425},{"type":13,"tag":710,"props":938,"children":939},{},[940,942,947,949,954],{"type":18,"value":941},"Portfolio widget on ",{"type":13,"tag":389,"props":943,"children":945},{"href":391,"rel":944},[393],[946],{"type":18,"value":396},{"type":18,"value":948}," fetches via ",{"type":13,"tag":39,"props":950,"children":952},{"className":951},[],[953],{"type":18,"value":564},{"type":18,"value":955}," and shows live top players with a \"Play now\" link.",{"type":13,"tag":710,"props":957,"children":958},{},[959,961,967,968,974],{"type":18,"value":960},"GitHub profile README updated by Actions in the Playbase / profile automation repos (exact pipeline: see ",{"type":13,"tag":389,"props":962,"children":964},{"href":577,"rel":963},[393],[965],{"type":18,"value":966},"playbase",{"type":18,"value":887},{"type":13,"tag":389,"props":969,"children":972},{"href":970,"rel":971},"https://github.com/jovylle/jovylle",[393],[973],{"type":18,"value":868},{"type":18,"value":975},").",{"type":13,"tag":382,"props":977,"children":979},{"id":978},"_2-visitor-uses-d1guk",[980],{"type":18,"value":981},"2. Visitor uses d1g.uk",{"type":13,"tag":911,"props":983,"children":984},{},[985,997,1017],{"type":13,"tag":710,"props":986,"children":987},{},[988,990,995],{"type":18,"value":989},"Player opens ",{"type":13,"tag":389,"props":991,"children":993},{"href":462,"rel":992},[393],[994],{"type":18,"value":466},{"type":18,"value":996}," for today's Desert grid visualization.",{"type":13,"tag":710,"props":998,"children":999},{},[1000,1002,1008,1010,1016],{"type":18,"value":1001},"Tool runs as a Nuxt/serverless front-end (repo: ",{"type":13,"tag":39,"props":1003,"children":1005},{"className":1004},[],[1006],{"type":18,"value":1007},"sfl-crab",{"type":18,"value":1009},"); optional feedback via ",{"type":13,"tag":389,"props":1011,"children":1013},{"href":512,"rel":1012},[393],[1014],{"type":18,"value":1015},"d1g.uk/feedbacks",{"type":18,"value":425},{"type":13,"tag":710,"props":1018,"children":1019},{},[1020,1022,1027,1029,1035],{"type":18,"value":1021},"Community history and shared grids live on ",{"type":13,"tag":389,"props":1023,"children":1025},{"href":487,"rel":1024},[393],[1026],{"type":18,"value":491},{"type":18,"value":1028}," (separate repo: ",{"type":13,"tag":39,"props":1030,"children":1032},{"className":1031},[],[1033],{"type":18,"value":1034},"sfl-digging-hub",{"type":18,"value":975},{"type":13,"tag":382,"props":1037,"children":1039},{"id":1038},"_3-support-notifications-on-portfolio",[1040],{"type":18,"value":1041},"3. Support & notifications on portfolio",{"type":13,"tag":911,"props":1043,"children":1044},{},[1045,1056,1068],{"type":13,"tag":710,"props":1046,"children":1047},{},[1048,1050,1055],{"type":18,"value":1049},"Visitor lands on jovylle.com; widget loads notifications from ",{"type":13,"tag":39,"props":1051,"children":1053},{"className":1052},[],[1054],{"type":18,"value":767},{"type":18,"value":425},{"type":13,"tag":710,"props":1057,"children":1058},{},[1059,1061,1066],{"type":18,"value":1060},"Support action opens the ProjectMate overlay (",{"type":13,"tag":39,"props":1062,"children":1064},{"className":1063},[],[1065],{"type":18,"value":646},{"type":18,"value":1067},") for feedback and release notes.",{"type":13,"tag":710,"props":1069,"children":1070},{},[1071],{"type":18,"value":1072},"AI chat tab calls Netlify serverless function with portfolio context (when enabled); widget itself carries no third-party analytics.",{"type":13,"tag":21,"props":1074,"children":1075},{},[],{"type":13,"tag":25,"props":1077,"children":1079},{"id":1078},"impact-metrics",[1080],{"type":18,"value":1081},"Impact & metrics",{"type":13,"tag":1083,"props":1084,"children":1085},"table",{},[1086,1110],{"type":13,"tag":1087,"props":1088,"children":1089},"thead",{},[1090],{"type":13,"tag":1091,"props":1092,"children":1093},"tr",{},[1094,1100,1105],{"type":13,"tag":1095,"props":1096,"children":1097},"th",{},[1098],{"type":18,"value":1099},"Metric",{"type":13,"tag":1095,"props":1101,"children":1102},{},[1103],{"type":18,"value":1104},"Source",{"type":13,"tag":1095,"props":1106,"children":1107},{},[1108],{"type":18,"value":1109},"Note",{"type":13,"tag":1111,"props":1112,"children":1113},"tbody",{},[1114,1133,1158,1180,1205,1234],{"type":13,"tag":1091,"props":1115,"children":1116},{},[1117,1123,1128],{"type":13,"tag":1118,"props":1119,"children":1120},"td",{},[1121],{"type":18,"value":1122},"d1g.uk daily visitors",{"type":13,"tag":1118,"props":1124,"children":1125},{},[1126],{"type":18,"value":1127},"Project catalog metadata",{"type":13,"tag":1118,"props":1129,"children":1130},{},[1131],{"type":18,"value":1132},"~300/day (self-reported in CMS catalog; verify with analytics export)",{"type":13,"tag":1091,"props":1134,"children":1135},{},[1136,1141,1153],{"type":13,"tag":1118,"props":1137,"children":1138},{},[1139],{"type":18,"value":1140},"Portfolio traffic",{"type":13,"tag":1118,"props":1142,"children":1143},{},[1144,1146,1151],{"type":18,"value":1145},"Umami (",{"type":13,"tag":39,"props":1147,"children":1149},{"className":1148},[],[1150],{"type":18,"value":396},{"type":18,"value":1152},")",{"type":13,"tag":1118,"props":1154,"children":1155},{},[1156],{"type":18,"value":1157},"Regular daily usage; no public DAU/WAU figure",{"type":13,"tag":1091,"props":1159,"children":1160},{},[1161,1166,1175],{"type":13,"tag":1118,"props":1162,"children":1163},{},[1164],{"type":18,"value":1165},"Playbase leaderboard",{"type":13,"tag":1118,"props":1167,"children":1168},{},[1169],{"type":13,"tag":39,"props":1170,"children":1172},{"className":1171},[],[1173],{"type":18,"value":1174},"fast.jovylle.com/reaction/top.json",{"type":13,"tag":1118,"props":1176,"children":1177},{},[1178],{"type":18,"value":1179},"Public JSON; all-time archive on game site",{"type":13,"tag":1091,"props":1181,"children":1182},{},[1183,1188,1193],{"type":13,"tag":1118,"props":1184,"children":1185},{},[1186],{"type":18,"value":1187},"Content freshness",{"type":13,"tag":1118,"props":1189,"children":1190},{},[1191],{"type":18,"value":1192},"GitHub Actions → Netlify hook",{"type":13,"tag":1118,"props":1194,"children":1195},{},[1196,1198,1203],{"type":18,"value":1197},"Rebuild after ",{"type":13,"tag":39,"props":1199,"children":1201},{"className":1200},[],[1202],{"type":18,"value":423},{"type":18,"value":1204}," JSON updates",{"type":13,"tag":1091,"props":1206,"children":1207},{},[1208,1213,1221],{"type":13,"tag":1118,"props":1209,"children":1210},{},[1211],{"type":18,"value":1212},"Widget notification reach",{"type":13,"tag":1118,"props":1214,"children":1215},{},[1216],{"type":13,"tag":39,"props":1217,"children":1219},{"className":1218},[],[1220],{"type":18,"value":767},{"type":13,"tag":1118,"props":1222,"children":1223},{},[1224,1226,1232],{"type":18,"value":1225},"Tag-filtered (",{"type":13,"tag":39,"props":1227,"children":1229},{"className":1228},[],[1230],{"type":18,"value":1231},"jovylle.com,all",{"type":18,"value":1233},") on portfolio",{"type":13,"tag":1091,"props":1235,"children":1236},{},[1237,1242,1247],{"type":13,"tag":1118,"props":1238,"children":1239},{},[1240],{"type":18,"value":1241},"chat-widget adoption",{"type":13,"tag":1118,"props":1243,"children":1244},{},[1245],{"type":18,"value":1246},"TBD",{"type":13,"tag":1118,"props":1248,"children":1249},{},[1250],{"type":18,"value":1251},"Confirm embed domains before publishing counts",{"type":13,"tag":21,"props":1253,"children":1254},{},[],{"type":13,"tag":25,"props":1256,"children":1258},{"id":1257},"what-id-improve-next",[1259],{"type":18,"value":1260},"What I'd improve next",{"type":13,"tag":911,"props":1262,"children":1263},{},[1264,1274,1299],{"type":13,"tag":710,"props":1265,"children":1266},{},[1267,1272],{"type":13,"tag":401,"props":1268,"children":1269},{},[1270],{"type":18,"value":1271},"Single observability layer",{"type":18,"value":1273}," — Umami covers the portfolio; d1g.uk, Playbase, and uft1 subdomains lack a unified dashboard. I'd add consistent uptime checks and error logging across the ecosystem, not just the main site.",{"type":13,"tag":710,"props":1275,"children":1276},{},[1277,1282,1284,1289,1291,1297],{"type":13,"tag":401,"props":1278,"children":1279},{},[1280],{"type":18,"value":1281},"Hostname clarity",{"type":18,"value":1283}," — Playbase (",{"type":13,"tag":39,"props":1285,"children":1287},{"className":1286},[],[1288],{"type":18,"value":532},{"type":18,"value":1290}," vs ",{"type":13,"tag":39,"props":1292,"children":1294},{"className":1293},[],[1295],{"type":18,"value":1296},"playbase.jovylle.com",{"type":18,"value":1298},") and the three embed products (portfolio widget, chat-widget, ProjectMate) need a public map so integrators know which script to use.",{"type":13,"tag":710,"props":1300,"children":1301},{},[1302,1307],{"type":13,"tag":401,"props":1303,"children":1304},{},[1305],{"type":18,"value":1306},"Document cross-repo data contracts",{"type":18,"value":1308}," — leaderboard JSON, notification index, and CDN project schema are integration APIs today but undocumented for external consumers; I'd version and publish them.",{"type":13,"tag":21,"props":1310,"children":1311},{},[],{"type":13,"tag":25,"props":1313,"children":1315},{"id":1314},"explore-the-ecosystem",[1316],{"type":18,"value":1317},"Explore the ecosystem",{"type":13,"tag":14,"props":1319,"children":1320},{},[1321],{"type":13,"tag":401,"props":1322,"children":1323},{},[1324],{"type":18,"value":1325},"Live",{"type":13,"tag":706,"props":1327,"children":1328},{},[1329,1339,1349,1359,1369,1379,1389],{"type":13,"tag":710,"props":1330,"children":1331},{},[1332,1337],{"type":13,"tag":389,"props":1333,"children":1335},{"href":391,"rel":1334},[393],[1336],{"type":18,"value":396},{"type":18,"value":1338}," — Portfolio & widget hub",{"type":13,"tag":710,"props":1340,"children":1341},{},[1342,1347],{"type":13,"tag":389,"props":1343,"children":1345},{"href":462,"rel":1344},[393],[1346],{"type":18,"value":466},{"type":18,"value":1348}," — Desert digging tool",{"type":13,"tag":710,"props":1350,"children":1351},{},[1352,1357],{"type":13,"tag":389,"props":1353,"children":1355},{"href":487,"rel":1354},[393],[1356],{"type":18,"value":491},{"type":18,"value":1358}," — Community digging hub",{"type":13,"tag":710,"props":1360,"children":1361},{},[1362,1367],{"type":13,"tag":389,"props":1363,"children":1365},{"href":528,"rel":1364},[393],[1366],{"type":18,"value":532},{"type":18,"value":1368}," — Playbase reaction game",{"type":13,"tag":710,"props":1370,"children":1371},{},[1372,1377],{"type":13,"tag":389,"props":1373,"children":1375},{"href":593,"rel":1374},[393],[1376],{"type":18,"value":597},{"type":18,"value":1378}," — Embeddable chatbot",{"type":13,"tag":710,"props":1380,"children":1381},{},[1382,1387],{"type":13,"tag":389,"props":1383,"children":1385},{"href":642,"rel":1384},[393],[1386],{"type":18,"value":646},{"type":18,"value":1388}," — Feedback & updates overlay",{"type":13,"tag":710,"props":1390,"children":1391},{},[1392,1398],{"type":13,"tag":389,"props":1393,"children":1396},{"href":1394,"rel":1395},"https://uft1.com",[393],[1397],{"type":18,"value":885},{"type":18,"value":1399}," — Utility tools hub",{"type":13,"tag":14,"props":1401,"children":1402},{},[1403],{"type":13,"tag":401,"props":1404,"children":1405},{},[1406],{"type":18,"value":450},{"type":13,"tag":706,"props":1408,"children":1409},{},[1410],{"type":13,"tag":710,"props":1411,"children":1412},{},[1413,1418,1419,1424,1425,1430,1431,1437,1438,1444,1445],{"type":13,"tag":389,"props":1414,"children":1416},{"href":446,"rel":1415},[393],[1417],{"type":18,"value":396},{"type":18,"value":443},{"type":13,"tag":389,"props":1420,"children":1422},{"href":504,"rel":1421},[393],[1423],{"type":18,"value":1007},{"type":18,"value":443},{"type":13,"tag":389,"props":1426,"children":1428},{"href":577,"rel":1427},[393],[1429],{"type":18,"value":966},{"type":18,"value":443},{"type":13,"tag":389,"props":1432,"children":1434},{"href":626,"rel":1433},[393],[1435],{"type":18,"value":1436},"chatbot-widget",{"type":18,"value":443},{"type":13,"tag":389,"props":1439,"children":1441},{"href":691,"rel":1440},[393],[1442],{"type":18,"value":1443},"projectmate-embedded-app",{"type":18,"value":443},{"type":13,"tag":389,"props":1446,"children":1448},{"href":970,"rel":1447},[393],[1449],{"type":18,"value":1450},"Profile automation",{"type":13,"tag":21,"props":1452,"children":1453},{},[],{"type":13,"tag":14,"props":1455,"children":1456},{},[1457],{"type":13,"tag":367,"props":1458,"children":1459},{},[1460,1462,1468],{"type":18,"value":1461},"Built by Jovylle Bermudez — infrastructure-minded full-stack engineer. Questions: ",{"type":13,"tag":389,"props":1463,"children":1465},{"href":1464},"mailto:me@jovylle.com",[1466],{"type":18,"value":1467},"me@jovylle.com",{"type":18,"value":425},{"type":13,"tag":1470,"props":1471,"children":1472},"style",{},[1473],{"type":18,"value":1474},"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 .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);}",{"title":5,"searchDepth":55,"depth":55,"links":1476},[1477,1478,1490,1491,1496,1497,1498],{"id":27,"depth":55,"text":30},{"id":377,"depth":55,"text":380,"children":1479},[1480,1482,1484,1486,1488],{"id":384,"depth":64,"text":1481},"Portfolio — jovylle.com",{"id":456,"depth":64,"text":1483},"d1g.uk — d1g.uk",{"id":522,"depth":64,"text":1485},"Playbase — fast.jovylle.com",{"id":587,"depth":64,"text":1487},"chat-widget — chat-widget.uft1.com",{"id":636,"depth":64,"text":1489},"ProjectMate — projectmate.uft1.com",{"id":701,"depth":55,"text":704},{"id":900,"depth":55,"text":903,"children":1492},[1493,1494,1495],{"id":906,"depth":64,"text":909},{"id":978,"depth":64,"text":981},{"id":1038,"depth":64,"text":1041},{"id":1078,"depth":55,"text":1081},{"id":1257,"depth":55,"text":1260},{"id":1314,"depth":55,"text":1317},"markdown","content:ecosystem.md","content","ecosystem.md","ecosystem","md",1782748760569]