Phase 6: sync jobs, inquiry and order forms

- Sync scheduler in the content service with a per-job cache (sync_cache),
  sync_runs reporting and Healthchecks pings. Jobs: Archidekt, BoardGameGeek,
  cover art (Open Library, TMDB, AniList), Suwayomi and Kavita reading
  progress, Bambuddy filament and Homebox material stock. A note's own value
  always wins over a synced one.
- PersonalReader: updates only Library notes with a matching anilistId,
  changes to Greg's notes are held for review; Reading series with no note
  show as suggestions on the admin Overview.
- /api/inquiries and /api/orders: Turnstile, rate limits, a saved copy in the
  content service (intake token) plus email over SMTP. Orders are re-checked
  against the live notes: accepted only when the category's ordersOpen is
  true and the line has capacity.
- Admin Inbox for saved submissions. Options' inStock is optional so synced
  stock can fill it. All settings from process.env; .env.example per service.
- Sources could not be reached from the build environment; parsers are tested
  against fixtures labelled as not live.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012aSbo2D1qP8cMFQCykf7kx
This commit is contained in:
Claude
2026-10-11 23:50:06 +00:00
parent 60dfeecd7f
commit e3b0cf60c5
76 changed files with 6050 additions and 86 deletions
+2 -2
View File
@@ -8,7 +8,7 @@
*/
import { basename } from "node:path";
import { checkNote, checkVault, formatNote, notePath, outgoingLinks, slugify, typeDef, type CheckedNote } from "@gk/schema";
import { defaultRules, evaluate, type RuleSettings } from "./rules.ts";
import { defaultRules, evaluate, isLimited, type RuleSettings } from "./rules.ts";
import type { Author, HeldChange, HeldReason, StoredNote, Store } from "./store.ts";
import { hashText, isNotePath, type Vault } from "./vault.ts";
@@ -264,7 +264,7 @@ export class ContentService {
current,
nameTakenBy,
slugTakenBy,
recentAgentChanges: author === "agent" ? this.store.changesSince("agent", window) : 0,
recentAgentChanges: isLimited(author) ? this.store.changesSince(author, window) : 0,
settings: this.rules,
},
);