feat: Windows download link + self-served update feed + install tracking

Downloads/updates:
- config: DOWNLOADS_DIR (override to a mounted volume in prod).
- static.js: serves /downloads/* (installer, latest.yml, .blockmap) with range support for
  resumable + differential auto-updates; /download/windows redirects to the current .exe
  (stable link). Landing page gets a "Download the Windows desktop app" button (hidden in-app).

Install tracking (who installed the app):
- db app_installs + repos.appInstalls (upsert by install_id, fills in the user on sign-in).
- POST /api/v1/telemetry/install (records install + user once authenticated);
  GET /api/v1/admin/installs (admin: list installs with user/version/os/last-seen).
- desktop main.js: stable per-install id in userData, exposed via preload
  (bizConnectNative.installId/version/os); home.html reportInstall() posts it after login.
- e2e: +2 checks (telemetry recorded, admin sees it). 119/119. build batch20.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-01 21:28:53 +05:30
parent e5c94ebf6d
commit 899770ed02
11 changed files with 143 additions and 4 deletions
+3
View File
@@ -67,6 +67,7 @@
<!-- Team member path BELOW: log in to the full app. Stub SSO -> /home for now. -->
<div class="divider" style="margin-top:1.6rem">BizGaze team member?</div>
<a class="ssobtn" id="ssoBtn" href="/home"><span class="bmark">B</span> Log in with BizGaze</a>
<a class="dl-win" id="dlWin" href="/download/windows" style="display:inline-flex;align-items:center;gap:.5rem;margin-top:1rem;color:var(--blue);font-size:.88rem;text-decoration:none;font-weight:600"><span data-ic="download" data-sz="16"></span> Download the Windows desktop app</a>
</div>
</div>
<footer>© BizGaze · Remote Support</footer>
@@ -76,6 +77,8 @@ function profileHTML(name){return '<div class="profile"><button class="pbtn" id=
function wireProfile(){const btn=document.getElementById('pbtn'),menu=document.getElementById('pmenu');if(!btn)return;btn.onclick=(e)=>{e.stopPropagation();menu.classList.toggle('open');};document.addEventListener('click',()=>menu.classList.remove('open'));const lo=document.getElementById('plogout');if(lo)lo.onclick=async()=>{try{await fetch('/api/logout',{method:'POST'});}catch(_){}location.href='/';};}
function makeBrandClickable(){document.querySelectorAll('.brandrow,.wordmark').forEach(el=>{el.style.cursor='pointer';el.addEventListener('click',()=>{location.href='/';});});}
makeBrandClickable();
// No "download" link when we're already inside the desktop app.
if(window.__NATIVE__){var _dl=document.getElementById('dlWin');if(_dl)_dl.style.display='none';}
// Already signed in -> skip this landing entirely and go straight to the app (no redundant
// "Open Biz Connect" page). This landing only shows when logged out.
(async function(){try{const r=await fetch('/api/me');if(r.ok){ location.replace('/home'); return; }}catch(_){}})();