Add background bulk import for Komoot

Replace the per-tour import UI with a fire-and-forget background job:

- Add `import_batches` DB table tracking status, found/imported/duplicate counts
- Add `runKomootBulkImport` server function that pages all Komoot tours,
  fetches GPX, creates activities, and deduplicates via sync_imports
- Add `komoot-bulk-import` pg-boss job registered at server startup
- Add POST /api/sync/komoot/import to enqueue the job
- Add GET /api/sync/komoot/import-status to return the latest batch
- Replace the Komoot import page with a progress UI that polls every 2s
  while a batch is running and shows found/imported/skipped counts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Ullrich Schäfer 2026-05-23 18:19:10 +02:00
parent 386867ef6a
commit 5ff7af8a81
No known key found for this signature in database
GPG key ID: A32FF691A0F752D9
10 changed files with 442 additions and 211 deletions

View file

@ -0,0 +1,39 @@
// POST /api/sync/komoot/import
// Enqueues a background bulk import of all Komoot tours for the connected user.
// Returns { batchId } immediately; poll /api/sync/komoot/import-status for progress.
import { randomUUID } from "node:crypto";
import { data, redirect } from "react-router";
import type { Route } from "./+types/api.sync.komoot.import";
import { getSessionUser } from "~/lib/auth/session.server";
import { getService } from "~/lib/connected-services/manager";
import { getBoss } from "~/lib/boss.server";
import { getDb } from "~/lib/db";
import { importBatches } from "@trails-cool/db/schema/journal";
export async function action({ request }: Route.ActionArgs) {
const user = await getSessionUser(request);
if (!user) return redirect("/auth/login");
const service = await getService(user.id, "komoot");
if (!service) return data({ error: "not_connected" }, { status: 400 });
const db = getDb();
const batchId = randomUUID();
await db.insert(importBatches).values({
id: batchId,
userId: user.id,
connectionId: service.id,
provider: "komoot",
status: "pending",
});
const boss = getBoss();
await boss.send("komoot-bulk-import", {
batchId,
userId: user.id,
creds: service.credentials,
});
return data({ batchId });
}