mirror of
https://github.com/Patiun/com.gregkilmer.www.git
synced 2026-11-08 04:08:24 +00:00
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:
@@ -4,8 +4,10 @@
|
||||
* cannot change who may write or what the rules allow.
|
||||
*/
|
||||
import { resolve } from "node:path";
|
||||
import { syncSettings, type SyncSettings } from "./sync/settings.ts";
|
||||
|
||||
export type Role = "reader" | "agent" | "editor" | "admin";
|
||||
/** `intake` can only file submissions (the site's forms); it can read nothing. */
|
||||
export type Role = "reader" | "agent" | "editor" | "admin" | "intake";
|
||||
|
||||
export interface Config {
|
||||
/** The vault's Site folder. */
|
||||
@@ -22,9 +24,13 @@ export interface Config {
|
||||
notifyWebhookUrl?: string;
|
||||
allowedEmails: string[];
|
||||
scanMinutes: number;
|
||||
/** Which sync jobs run, their intervals, Healthchecks URLs and keys. */
|
||||
sync: SyncSettings;
|
||||
/** Largest attachment a submission may carry, in bytes. */
|
||||
submissionMaxBytes: number;
|
||||
}
|
||||
|
||||
const roles = new Set<Role>(["reader", "agent", "editor", "admin"]);
|
||||
const roles = new Set<Role>(["reader", "agent", "editor", "admin", "intake"]);
|
||||
|
||||
/** CONTENT_TOKENS is a comma separated list of role:token pairs. */
|
||||
export function parseTokens(raw: string | undefined): Map<string, Role> {
|
||||
@@ -53,12 +59,14 @@ export function loadConfig(env: NodeJS.ProcessEnv = process.env): Config {
|
||||
notifyWebhookUrl: env.NOTIFY_WEBHOOK_URL || undefined,
|
||||
allowedEmails: (env.ALLOWED_EMAILS ?? "").split(",").map((s) => s.trim().toLowerCase()).filter(Boolean),
|
||||
scanMinutes: Number(env.SCAN_MINUTES ?? 5),
|
||||
sync: syncSettings(env),
|
||||
submissionMaxBytes: Math.round(Number(env.SUBMISSION_MAX_MB ?? 10) * 1024 * 1024),
|
||||
};
|
||||
}
|
||||
|
||||
/** What each role may do. Checked by the HTTP API and the MCP server alike. */
|
||||
export const can = {
|
||||
readDrafts: (r: Role) => r !== "reader",
|
||||
readDrafts: (r: Role) => r !== "reader" && r !== "intake",
|
||||
write: (r: Role) => r === "agent" || r === "editor" || r === "admin",
|
||||
review: (r: Role) => r === "editor" || r === "admin",
|
||||
rollback: (r: Role) => r === "admin",
|
||||
|
||||
Reference in New Issue
Block a user