Owner-only tracker for learning the Cargill Bioindustrial plant in Gouda: schema plant (entries, links with confidence, pending refs), plant.apply_entries bulk import, overview with clusters and flow diagram, kind tabs, glossary, questions, detail pages and owner inline editing. Docs in docs/plant-tracker.md.
4.1 KiB
Plant tracker (/trackers/cargill)
A private (owner-only) knowledge base about the Cargill Bioindustrial plant in Gouda:
departments, products, process steps, equipment, glossary terms, questions, notes and roles
(never colleague names). Logged-out visitors get a 404 on the page, its data and its actions
(ownerOnlyPrefixes in src/lib/server/owner.ts).
Schema plant (migration drizzle/20261026133106_plant)
plant.entries:kind,slug(unique per kind),title,summary,body(markdown),parent_id(any kind, e.g. a note under a note),tags,sort_order,source,confidence(confirmed|assumed|open),answered_at(questions), timestamps.plant.links:from_id,to_id,relation(feeds_into,made_in,uses,part_of,related), optionallabel,dashed,confidence(defaultconfirmed;assumedoropenlinks show dashed in the flow and with a "?" badge on entry pages).plant.pending: parents and links whose target doesn't exist yet. Everyapply_entriesrun retries them, so a later batch that adds the target resolves them. Entry pages list them as "pending".
Kinds: department, product, process_step, equipment, glossary, question, note,
person_role.
How tags drive the UI:
cluster(departments): a section in the departments tab and a card in the overview, with every unit below it (units withparent: "cluster-ea", and their own units, like MP1's).inactive: dimmed everywhere; the "hide inactive" switch hides them (off by default).overview(notes): shown at the top of the overview.
Bulk import: plant.apply_entries(jsonb)
Upserts by (kind, slug), then sets parents and links by slug. Run it as the app user or the
owner; for big files pipe SQL through stdin, e.g.
select plant.apply_entries($doc$ { ... } $doc$::jsonb);
The argument is either an object { "source": ..., "entries": [...], "links": [...], "delete": [...] } or a bare array of entries.
{
"source": "Walter White, batch 5 (2026-10-26)",
"entries": [
{
"kind": "department",
"slug": "414-kolom-1",
"title": "414 Kolom 1",
"summary": "Fat splitting column, continuous",
"body": "In and out:\n- In: feed, water and high-pressure steam.\n- Out: fatty acid and glycerine water.",
"parent": "cluster-dim",
"tags": ["splitting", "continuous"],
"confidence": "confirmed",
"links": [{ "to": "splitting", "relation": "uses", "label": "optional" }]
},
{ "kind": "question", "slug": "rndm", "title": "What is RNDM?", "tags": ["answered"] }
]
}
- Required:
kind, plusslugor atitleto slugify; new entries need atitle. - Optional:
summary,body,parent(aliasparent_slug;nullclears it),tags,confidence(defaultassumed,openfor questions),sort_order,source,answered,replace_links,replace_tags,body_mode("append"),links(to,relation,label,dashed,confidence,remove). - Updating an existing entry:
- Keys that are left out keep their current value. An empty
summaryorbodyalso keeps the current text. With"body_mode": "append"the new body is added below the current one (skipped when it is already there) instead of replacing it. tagsare merged into the existing tags, unless the entry sets"confidence": "confirmed"or"replace_tags": true, which replace them.- The top-level
sourceis only the default for new entries; passsourceon an entry to overwrite it.
- Keys that are left out keep their current value. An empty
- A question tagged
answered(or with"answered": true) is marked answered; the tag is dropped. - References (
parent,to,from) are a slug orkind:slug. A bare slug used by several kinds resolves in this order: process_step, product, department, equipment, note, question, person_role, glossary (sosplittingis the process step). - Unknown references never abort the import: they are listed in
unresolvedand kept inplant.pendinguntil their target exists.
Returns { inserted, updated, linked, unlinked, deleted, unresolved: [{from, field, to}], resolved_pending, pending, entries: [{id, kind, slug, action}] }.