Phase 3: VISUAL feed and M-Files drawings in the worker
Migration 0004 (VISUAL and drawing caches, go-live ignored list, resource map, job tables, order-derived columns with provenance; work order key includes the operation sequence). The real worker on APScheduler with settings re-read each fire, pause, run now, advisory locks, job_runs and a heartbeat. The visual-feed job (five VisualKit reads, COPY and MERGE cache, suspect-batch guard, the apply in one transaction: drafts, change orders, retire-moved, work order gone, closed and cancelled observed, projects and units from order links, auto-release) and the fingerprint. The drawing-lookup job (queue, budget, download on version change, sha256 into assets, decision table, staging for rev approval, drawing-origin change orders). Clerical From VISUAL panel, flags, rev approval, hand uploads, change-order review; Admin Feed settings and resource map. Synthetic fixture generator and a fixture-driven worker in CI with a Playwright scenario. Docs updated. Verified: 3249 server tests and 13 Playwright scenarios on the docker-1 CI stack, 76 frontend tests, doctor at 0004; one feed and one drawing run against VISUAL DEV and the vault from the developer machine (counts in the changelog). Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
@@ -43,4 +43,29 @@ export const packetsApi = {
|
||||
setVclosed: (id: number, closed: boolean, extra: Guarded = {}) =>
|
||||
api.post<PacketRead>(`${base(id)}/vclosed`, { closed, ...extra }),
|
||||
databook: (id: number) => api.post<PacketRead>(`${base(id)}/databook`, {}),
|
||||
|
||||
/* Phase 3: VISUAL packets. */
|
||||
revApprove: (id: number, body: { reason: string } & Guarded) => api.post<PacketRead>(`${base(id)}/rev-approve`, body),
|
||||
handDrawing: (id: number, body: { asset_id: string; reason: string } & Guarded) =>
|
||||
api.post<PacketRead>(`${base(id)}/hand/drawing`, body),
|
||||
/** Multipart cannot carry JSON, so the signature rides as sign_factor and sign_secret. */
|
||||
handBom: (id: number, file: File, reason: string, extra: Guarded = {}) => {
|
||||
const fd = new FormData();
|
||||
fd.append("file", file, file.name);
|
||||
fd.append("reason", reason);
|
||||
if (extra.sign) {
|
||||
fd.append("sign_factor", extra.sign.factor);
|
||||
fd.append("sign_secret", extra.sign.secret);
|
||||
}
|
||||
if (extra.it_reason) fd.append("it_reason", extra.it_reason);
|
||||
return request<PacketRead>(`${base(id)}/hand/bom`, { method: "POST", body: fd });
|
||||
},
|
||||
removeHandBom: (id: number, extra: Guarded = {}) => api.delWithBody<PacketRead>(`${base(id)}/hand/bom`, extra),
|
||||
|
||||
/* Change orders. */
|
||||
coApprove: (id: number, no: number, extra: Guarded = {}) => api.post<PacketRead>(`${base(id)}/change-orders/${no}/approve`, extra),
|
||||
coReject: (id: number, no: number, body: { reason: string } & Guarded) =>
|
||||
api.post<PacketRead>(`${base(id)}/change-orders/${no}/reject`, body),
|
||||
coHold: (id: number, no: number, hold: boolean, extra: Guarded = {}) =>
|
||||
api.post<PacketRead>(`${base(id)}/change-orders/${no}/hold`, { hold, ...extra }),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user