feat: Phase 0.5 — remote feed sync via Bearer token auth
Server (bincio/serve/server.py): - Add _require_auth: accepts session cookie OR Authorization: Bearer token - POST /api/auth/token: same as /api/auth/login but returns token in body (password used once, not stored; mobile stores only the session token) - GET /api/feed: auth-gated; reads _merged/index.json for the user and returns the activities array as JSON Mobile: - db/sync.ts: syncFeed(db) fetches /api/feed, upserts each summary into local SQLite as origin='remote'; skips locally-imported activities - db/queries.ts: add upsertRemoteActivity (INSERT ... ON CONFLICT DO UPDATE WHERE origin='remote' — never overwrites local imports); fix feed sort order to started_at DESC instead of insertion order - settings.tsx: Connect section — password field (not persisted) + Connect button calls POST /api/auth/token and stores token; Disconnect clears it - index.tsx: ↓ Sync button + pull-to-refresh both trigger syncFeed; cloud badge on remote activities; empty state updated
This commit is contained in:
+19
-1
@@ -52,7 +52,7 @@ export function useActivities(): ActivitySummary[] {
|
||||
json_extract(detail_json, '$.duration_s') AS duration_s,
|
||||
json_extract(detail_json, '$.elevation_gain_m') AS elevation_gain_m
|
||||
FROM activities
|
||||
ORDER BY created_at DESC
|
||||
ORDER BY json_extract(detail_json, '$.started_at') DESC
|
||||
`);
|
||||
return rows;
|
||||
}
|
||||
@@ -85,6 +85,24 @@ export async function insertActivity(
|
||||
);
|
||||
}
|
||||
|
||||
export async function upsertRemoteActivity(
|
||||
db: ReturnType<typeof useSQLiteContext>,
|
||||
id: string,
|
||||
detailJson: string,
|
||||
): Promise<boolean> {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const result = await db.runAsync(
|
||||
`INSERT INTO activities (id, source_hash, detail_json, origin, synced_at)
|
||||
VALUES (?, ?, ?, 'remote', ?)
|
||||
ON CONFLICT(id) DO UPDATE SET
|
||||
detail_json = excluded.detail_json,
|
||||
synced_at = excluded.synced_at
|
||||
WHERE origin = 'remote'`,
|
||||
[id, id, detailJson, now],
|
||||
);
|
||||
return result.changes > 0;
|
||||
}
|
||||
|
||||
// ── Settings ───────────────────────────────────────────────────────────────
|
||||
|
||||
export async function getSetting(
|
||||
|
||||
Reference in New Issue
Block a user