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:
+17
-1
@@ -299,4 +299,20 @@ const deviceTokens = {
|
||||
removeByToken: (token) => db.prepare('DELETE FROM device_tokens WHERE token=?').run(token),
|
||||
};
|
||||
|
||||
module.exports = { teams, users, authSessions, machines, audit, sessionsLog, refreshTokens, apiKeys, webhooks, messages, reactions, attachments, conversations, scheduledMeetings, recordings, polls, pollVotes, pushSubs, favorites, deviceTokens };
|
||||
const appInstalls = {
|
||||
// Upsert by install_id: each launch refreshes version/os/last_seen and fills in the user once
|
||||
// they sign in (COALESCE keeps a known user if a later anonymous ping arrives).
|
||||
record: ({ id, installId, userId, userEmail, tenantId, platform, appVersion, os }) =>
|
||||
db.prepare(`INSERT INTO app_installs (id,install_id,user_id,user_email,tenant_id,platform,app_version,os,first_seen,last_seen)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?)
|
||||
ON CONFLICT(install_id) DO UPDATE SET
|
||||
user_id=COALESCE(excluded.user_id, app_installs.user_id),
|
||||
user_email=COALESCE(excluded.user_email, app_installs.user_email),
|
||||
tenant_id=COALESCE(excluded.tenant_id, app_installs.tenant_id),
|
||||
platform=excluded.platform, app_version=excluded.app_version, os=excluded.os,
|
||||
last_seen=excluded.last_seen`)
|
||||
.run(id, installId, userId || null, userEmail || null, tenantId || null, platform || null, appVersion || null, os || null, now(), now()),
|
||||
listForTenant: (tenantId) => db.prepare('SELECT * FROM app_installs WHERE tenant_id=? ORDER BY last_seen DESC').all(tenantId),
|
||||
};
|
||||
|
||||
module.exports = { teams, users, authSessions, machines, audit, sessionsLog, refreshTokens, apiKeys, webhooks, messages, reactions, attachments, conversations, scheduledMeetings, recordings, polls, pollVotes, pushSubs, favorites, deviceTokens, appInstalls };
|
||||
|
||||
Reference in New Issue
Block a user