Ownware
Home›Specta›Manual
Specta · Manual

Specta Manual, as shipped in the download

Specta — User Manual

Supplier catalogues and spec sheets, normalised into product rows you can import. Version 3.1.4 [src: app/controllers/api.php:108].

About this manual

Every statement here was written by reading Specta's own source, and each one carries the file it came from in a bracketed src marker. Paths are relative to the folder this docs directory sits in. If a sentence disagrees with the application, the application is right and this manual has a bug — the markers exist so you can check rather than take our word for it.

Nothing is described that the code does not do. Where something is deliberately limited, that is said plainly rather than left out.

What Specta is

You declare the columns you want. You upload a supplier's PDF or spreadsheet. A model extracts the products, every value carries a confidence score, and what comes out is a CSV or JSON file a store's importer will accept [src: app/controllers/v3.php:289].

The extraction is the only part a model touches. The mapping, the scoring and the export are pure and offline — no database, no network — which is what allows all of it to be tested [src: app/src/Catalog.php:6].

Schemas: declaring what you want

A schema is a named template of attribute columns [src: app/src/Catalog.php:3]. Each column carries a key, a label, a role, a type, whether it is required, and an optional unit [src: app/src/Catalog.php:13].

Roles are name, sku, price and attribute [src: app/src/Catalog.php:23]. They do two jobs: they promote a column to a canonical product field, and they decide how it maps into each export preset [src: app/src/Catalog.php:13].

Type, required and unit steer two further things — the prompt the model is given, and the offline confidence scoring described below [src: app/src/Catalog.php:14].

Column labels become safe keys automatically. "Width (mm)" becomes width_mm; a key that would start with a digit is prefixed so that it cannot [src: app/src/Catalog.php:44].

A schema is capped at sixty columns, so that a pasted schema cannot blow up the interface or an import file [src: app/src/Catalog.php:28].

Confidence scoring — the part worth understanding

Every extracted value gets a score between 0 and 1. The model is never asked how confident it is. The score is computed offline from the value as printed [src: app/src/Extraction.php:115], which is the only honest way to do it — a model's own confidence report is not evidence.

The scoring is published in the source rather than hidden [src: app/src/Extraction.php:100]:

CaseScore
Empty, and the column is required0.0
Empty, and the column is optional1.0
A placeholder — n/a, -, TBD, unknown0.3
Text, non-empty1.0
Text over 500 characters0.7 — truncation risk [src: app/src/Extraction.php:101]
Numeric, nothing parseable0.2
Numeric, clean as printed1.0
Numeric, coerced out of prose ("approx 42 kg total")0.65 [src: app/src/Extraction.php:106]

Then three caps apply: a negative value or a magnitude above ten million is capped at 0.4 as implausible [src: app/src/Extraction.php:108], and a column with a unit hint whose unit is absent from the value is capped at 0.9 [src: app/src/Extraction.php:109].

The list of recognised placeholders is explicit [src: app/src/Extraction.php:89].

A field you have confirmed yourself is stored as 1.0 and never recomputed [src: app/src/Extraction.php:113]. Your judgement is not overwritten by the scorer on the next pass.

What the scores are used for

A catalogue's lowest-scoring field is available as a single number [src: app/src/Catalog.php:354], and a record needs review when any field falls below your threshold [src: app/src/Catalog.php:360] — not when the average does, which would let one bad field hide behind nine good ones.

Scoring works on already-stored records too, for a catalogue that predates the feature or has been edited by hand [src: app/src/Catalog.php:344].

Extraction, and what is skipped

Rows that carry nothing — no name, no SKU, no price and no attribute value — are dropped rather than imported as blanks [src: app/src/Catalog.php:299]. The scoring path applies the identical rule, so the scored count and the record count always match [src: app/src/Catalog.php:315].

Batches

A batch is a stack of uploaded sheets, capped at twenty files [src: app/src/Batch.php:24].

They are processed one file per request [src: app/src/Batch.php:5]. There is no cron job, no long-running request and no queue daemon, which is a deliberate concession to shared hosting — the interface drives it with a "Process next" button or an auto-advancing page.

Each file runs queued → extracting → extracted, or → failed [src: app/src/Batch.php:25]. A failed file does not stop the batch: its error is stored and the rest is untouched [src: app/src/Batch.php:10], and a failed file can be returned to the queue and retried.

The whole state machine is HTTP-free — no session, no redirect, no output [src: app/src/Batch.php:15] — and the model call is injected rather than hard-wired, which is how the tests and demo mode run the entire flow with no API key at all [src: app/src/Batch.php:17].

Catalogue status is derived

A catalogue's status is rolled up from its products rather than stored: no products yet means pending, or extracted if a run has happened; all products reviewed means reviewed; anything else means extracted [src: app/src/Catalog.php:395].

Exporting

Three presets [src: app/src/Catalog.php:26]:

PresetShape
plainOne column per schema column, your labels as headers
woocommerceWooCommerce's product CSV importer format, with attribute name/value/visible triples
shopifyShopify's product CSV, with attributes folded into the body

All three are described in the source [src: app/src/Catalog.php:443] and written with CRLF line endings [src: app/src/Catalog.php:449], which is what those importers expect.

JSON export gives the canonical records with a decimal price and the full attribute map [src: app/src/Catalog.php:889].

Checking a mapping before you import

This is the feature to know about, because it turns a failed import into a five-second check.

Paste the header row from your store's own import template, and Specta compares it against the columns your export would actually produce [src: app/src/Catalog.php:828]. You get back four lists and a verdict:

  • missing — the store asks for it and your export would not produce it, so the import breaks or blanks the field [src: app/src/Catalog.php:824]
  • extra — your export produces it and the store's template has no slot, which some importers reject [src: app/src/Catalog.php:825]
  • matched — present on both sides
  • duplicates — the same column name twice in the store's header

The verdict is exact, covered or gaps.

Two details show the feature was built against real pasting rather than a clean test case. A non-breaking space — which is what a browser copy usually gives you — is normalised away [src: app/src/Catalog.php:815]. And pasting a sentence instead of a header row gets you a specific explanation rather than a nonsense result [src: app/src/Catalog.php:844].

Column order is reported, never failed on [src: app/src/Catalog.php:870], because order only matters to importers that read positionally.

Users, roles and what each may do

Three roles. This table was produced by executing the product's own permission function against every permission the routes ask for, rather than by reading its map.

Permissionviewermemberadmin
catalog.viewyesyesyes
catalog.exportyesyesyes
audit.viewyesyesyes
catalog.edit—yesyes
product.edit—yesyes
schema.edit—yesyes
batch.run—yesyes
views.save—yesyes
settings.edit——yes
users.manage——yes

The source names both seats. A member is the catalogue operator who uploads, runs extractions, corrects products and edits schemas [src: app/controllers/v3.php:50]. A viewer reads and exports — the seat for the person downstream who consumes the normalised data, a marketplace manager or a client, and who must not be able to change what a supplier's sheet said [src: app/controllers/v3.php:51].

Why batch.run is its own permission

Because running an extraction spends your AI credits. It is separated deliberately so that you can hand somebody editing rights without handing them the spend [src: app/controllers/v3.php:54].

The API and agent access

The REST interface sits behind a key [src: app/controllers/api.php:108].

Six tools are exposed to an agent, and every one of them is read-only [src: app/controllers/v3.php:294]: listing catalogues, catalogue detail, listing items, item detail, export rows and batch status.

The reason is given in the instructions the agent receives, and it is the right one: these tools cannot start an extraction, because a run spends the operator's own AI credits, so it stays a deliberate action in the browser [src: app/controllers/v3.php:293].

What Specta does not do

It does not let an agent spend your money [src: app/controllers/v3.php:293]. Extraction is a browser action, by design.

It does not ask the model how confident it is. Confidence is computed offline from the printed value against your column's declared type, unit and required flag [src: app/src/Extraction.php:115]. That means a score is a statement about the text, not about the model's mood.

It does not push to your store. It writes files WooCommerce and Shopify importers accept [src: app/src/Catalog.php:443], and the mapping checker tells you in advance whether the file fits — but the upload is yours.

It does not judge whether a supplier's figure is correct. A clean, well-formed, entirely wrong price scores 1.0. The score measures how confidently the value was read, not whether the sheet was right.

← Back to Specta · Quickstart · API · Test run

Affiliate program
Recommend tools people own — earn 35% on every sale. 90-day tracking, instant delivery, payouts by Lemon Squeezy.
Become an affiliate →