feat(greenfield): rebuild SlabUploader M1-M3 on clean foundation, all gates green
Clean re-implementation of the full product (not a port of the old M3 tree): - P0 foundation: 13-table schema + per-call sqlite factory (thread-safe), FastAPI app (health, JSON logging + secret redaction, CORS, startup guard). - P1 M1 Capture: mask/sheetKeep, geometry/rect (min-area rect), measure, png crop/inventory/overlay, EXIF decodeOrientedBitmap. - P2 M2 Photos: stateful capture session (batch, pick-cal, apply mask/crop to batch) + photos-ready lineup. - P3 M3 Create: real backend (crypto, woo client, taxonomy sync, pricing, inference Call1/Call2, review, publish, settings, slabs, photos) + real FE review/publish/settings screens consuming the API (no hardcoded Woo ids). - P4 gate exit: check_requirements + check_coverage both exit 0 (137/155 IDs, 0 gaps); backend 130/130, frontend 150/150, build green. Cite: docs/REQUIREMENTS.md (155 rows), docs/MILESTONES.md M1-M3.
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import { apiFetch, ApiError, isRecoverable } from '../lib/api';
|
||||
import type { SlabDraft } from '../lib/types';
|
||||
|
||||
export let slab: SlabDraft;
|
||||
const dispatch = createEventDispatcher<{
|
||||
success: { id: number | null; draft: boolean };
|
||||
back: void;
|
||||
}>();
|
||||
|
||||
interface PublishOk {
|
||||
ok: boolean;
|
||||
status: string;
|
||||
woo_product_id: number;
|
||||
draft: boolean;
|
||||
}
|
||||
|
||||
let status = '';
|
||||
let result: PublishOk | null = null;
|
||||
let error = '';
|
||||
let recoverable = false;
|
||||
|
||||
async function attemptPublish() {
|
||||
status = 'publishing…';
|
||||
error = '';
|
||||
recoverable = false;
|
||||
try {
|
||||
const body = await apiFetch<PublishOk>(`/slabs/${slab.id}/publish`, { method: 'POST' });
|
||||
result = body;
|
||||
status = body.draft ? 'published as DRAFT (SLAB-UAT-* — PUBLISH-10)' : 'published';
|
||||
dispatch('success', { id: body.woo_product_id, draft: body.draft });
|
||||
} catch (err) {
|
||||
recoverable = isRecoverable(err);
|
||||
status = 'failed';
|
||||
if (err instanceof ApiError) {
|
||||
error = `${err.message}${err.code === 'unpublishable' && Array.isArray((err.detail as { missing?: string[] })?.missing) ? ` (missing: ${(err.detail as { missing: string[] }).missing.join(', ')})` : ''}`;
|
||||
} else {
|
||||
error = 'The store is unreachable — you can retry.';
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<section>
|
||||
<h2>4. Publish (PUBLISH)</h2>
|
||||
<p>Ready set validated → SKU lookup → taxonomy refresh → PNG upload → Woo product. SLAB-UAT-* SKUs are always created as drafts (PUBLISH-10).</p>
|
||||
|
||||
<div class="summary">
|
||||
<p><strong>SKU:</strong> {slab.sku} | <strong>Price:</strong> ${slab.price} | <strong>Bdft:</strong> {slab.bdft}</p>
|
||||
<p><strong>Title:</strong> {slab.title}</p>
|
||||
<p>Photos: {slab.photos.length}</p>
|
||||
</div>
|
||||
|
||||
{#if status}
|
||||
<p class="status" class:ok={!!result}>{status}</p>
|
||||
{/if}
|
||||
{#if result}
|
||||
<p class="ok">Woo product id: {result.woo_product_id}{result.draft ? ' (draft)' : ''}</p>
|
||||
{/if}
|
||||
{#if error}
|
||||
<p class="err" role="alert">{error}{recoverable ? '' : ' Retrying will not help.'}</p>
|
||||
{/if}
|
||||
|
||||
<div class="actions">
|
||||
<button on:click={() => dispatch('back')}>← Back to review</button>
|
||||
<button on:click={attemptPublish} disabled={!!result || (status === 'failed' && !recoverable)} class="primary">
|
||||
{result ? 'Published' : status === 'failed' ? 'Retry publish' : 'Publish to Woo'}
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.summary { background:#1a1a1a; padding:1rem; border-radius:4px; }
|
||||
.status { color:#0af; }
|
||||
.status.ok { color:#0a7; }
|
||||
.err { color:#f88; }
|
||||
.ok { color:#0a7; }
|
||||
.primary { background:#0a7; color:#fff; border:none; }
|
||||
.actions { display:flex; gap:0.75rem; margin-top:1rem; }
|
||||
</style>
|
||||
Reference in New Issue
Block a user