BI-P028 extends the BI-P002 MetricDefinition rather than defining a second,
parallel metric — a second metric type would be the exact failure the DoD is
about. `MetricSpec` is the fifteen-field shape the prompt names; explicit
bridge functions map it onto the persisted row plus the six columns it adds.
The DoD ("no production metric exists only inside a dashboard tool") is
enforced by something that refuses: a dashboard panel carrying an inline
expression, inline aggregation or inline SQL is rejected, as is one naming an
unregistered or RETIRED metric. So a metric cannot come into existence inside
Superset and quietly become production.
Validation refuses the metrics that render as a plausible number and mean
nothing: no description, no owner, no time dimension, a ratio without a
denominator, a currency format with no currency (which is how SEK gets
rendered as USD), a filter on a dimension the metric does not declare.
BI-P031's DoD is checked on a MEANING HASH rather than a field diff, so a
field this code has never heard of still counts as changing the meaning —
fail-closed rather than fail-open on future additions. Eight semantic fields
are each mutated and each refused; three editorial fields are each mutated and
each allowed, because forcing a version bump to fix a typo is how teams learn
to route around governance. A new version starts DRAFT and EXPERIMENTAL: it
never inherits the certification, or a certified metric's meaning could change
while still wearing the badge.
BI-P030 stores the semantic model separately from any engine, and that
negative is enforced two ways after the first way turned out to be
insufficient:
* a VOCABULARY scan rejects a model mentioning metricflow / clickhouse /
trino / cube / superset anywhere in its serialized form;
* a STRUCTURAL check rejects any top-level key outside BI-P030's field list.
The second exists because a test expected the vocabulary scan to catch a
MetricFlow-shaped manifest and it did not — the manifest never says
"metricflow". The structural check holds regardless of what a document calls
itself. The manifest is now also stamped with its generator so a leaked copy
is detectable.
The replaceability DoD is tested with TWO providers whose naming rules differ
(MetricFlow-shaped and Cube-shaped, `ds_sales.amount_sek`): the canonical id
set must be identical across both AND the provider bindings must differ —
otherwise the equality would hold trivially for a registry that only ever had
one provider.
BI-P029 — WHAT IS NOT PROVEN IS STATED IN THE MODULE AND RETURNED BY THE CODE.
MetricFlow is a Python package and was NOT executed: no Python runtime is
provisioned here, and BI-P029's "pin a currently verified version" requires a
licence/supply-chain review that has not happened. `providerReadiness()`
returns `verified: false` and names all four open items, including that the
Superset path is unimplemented and the AI Analyst path uncompared. The
constant `METRICFLOW_PINNED_VERSION` is labelled a declared intent, not a
certification. A test asserts the readiness report says so, so the honesty
cannot rot silently.
353 tests. typecheck + eslint clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
0pt — your data
Data services on demand for the Nordics + Europe. Compose a data job, pay 50 % to start, watch production live, validate with full provenance, deliver anywhere. Owned by SIAX Technology AB. Honest accuracy is the moat: every field carries source, freshness and confidence; nothing is guessed.
Live: https://0pt.app · Contract: CLAUDE.md + docs/
Architecture (verified against code, not aspirational):
docs/architecture/ARCHITECTURE.md. It documents the real API surface, the real persistence story, and the known security gaps — including several places where this README is optimistic. Read it before trusting any capability claim below. Repo identity + estate classification:siax.repo.json+siax.config.json. Compliance state:docs/compliance/(INVENTORY, RELATIONS, OSS-INVENTORY, GOLDEN-STANDARD-REPORT, BACKLOG, SLUTRAPPORT).
Two planes (see docs/02-architecture.md)
- Edge (Vercel, this app) — marketing, catalog, the order lifecycle, customer portal,
admin portal, and the API route handlers. Defers to the data engine when
ENGINE_URLis set. - Engine (
services/api, runs on a VPS) — FastAPI orchestrator + worker pipeline doing the compliant sourcing (official API → bulk → authorized web → licensed → else level 0). Never on Vercel (long jobs). Bypass/stealth/proxy-rotation/fake-account paths are excluded by design (CLAUDE.md §1).
Routes
| Area | Routes |
|---|---|
| Marketing | / (hero, filosofi, katalog, motorn, visualiseringar, täckning, editorial, bevis, priser, footer) |
| Catalog | /katalog, /katalog/[id] |
| Sourcing map | /kallor |
| Order lifecycle | /bestall → /bestall/forskott → /order/[id] → /order/[id]/validera |
| Customer portal | /portal, /portal/subscriptions, /portal/files, /portal/integrationer, /portal/settings |
| Admin portal | /admin, /admin/sources, /admin/jobs, /admin/customers |
| API | /api/{health,estimates,catalog,sources,orders,orders/[id],subscriptions,admin/metrics,uploads,auth/*,payments/*,webhooks/stripe,connections/db-grant} |
Design system
Mono/editorial, light, radius 0, Inter + JetBrains Mono, single red #e40014, animated grain,
scroll-reveal motion. No photography — imagery is rendered data (DataArtifact). Every fact
shows a provenance square (ProvenanceBadge). Full spec: docs/05-design-system.md.
Run locally
pnpm install
pnpm dev # Next.js on http://localhost:3000
# data engine (separate, optional)
cd services/api && pip install -r requirements.txt && uvicorn orchestrator.main:app --reload
Deploy
- Config target (as of 2026-08-09):
siax.config.jsondeclaresdeploy.target: "coolify", matching every other SIAX Cloud OS repo (n0d, st0re, aud0, ...) — a Dockerfile "for Coolify" (already committed, seeDockerfile) plus.gitea/workflows/cd.yml(renamed fromdeploy.yml2026-08-10) that POSTs a restart to a Coolify app UUID onCOOLIFY_TOKENpush. Actually live right now: the only running instance ofSee0pt.appis still on Vercel (project0pt, scope Simon Axelsson's projects) — no Coolify app has been provisioned for this repo yet, sodeploy.yml's app UUID is a placeholder that fails the job on purpose until someone fills it in. Flipping the config declares intent; it does not move traffic.docs/architecture/ARCHITECTURE.md§5/§8 for the full "Vercel or fleet" state and what's still open (Coolify app provisioning + DNS cutover — a separate decision from this config change, since the live Vercel deployment is not being touched).- CORRECTED 2026-09-06 — the bullet above is no longer true. The Coolify deploy hook is LIVE.
The repo secret
COOLIFY_TOKENexists (created 2026-08-31T11:34:34Z) and the repo Actions variableCOOLIFY_APP_IDholds a real 24-character UUID, not theTODO-no-coolify-app-provisioned-yetliteral. Both guard conditions in.gitea/workflows/cd.ymltherefore pass. Measured on the push tomainat1ff34410(2026-09-06): jobDeploy to Coolify / deploy(run 11695, job 26295) finished success withcoolify deploy HTTP 200in its log. Every merge intomainnow fires a real redeploy againstcloud.siax.io— know what you are shipping before you merge. Probed 2026-09-06 08:00 UTC:0pt.appstill answers from Vercel (server: Vercel,x-vercel-id: arn1::…) and returns HTTP 402DEPLOYMENT_DISABLED— "Payment required" on both/and/api/health. So the public domain is down, DNS has not been cut over to Coolify, and the Coolify app — whatever state it is in — serves no0pt.apptraffic. Two separate facts, both true at once: the deploy hook fires for real, and the product domain is dark behind an unpaid Vercel deployment. Still not established: whether the Coolify app itself builds and starts — the deploy endpoint returning 200 only means the request was accepted, not that a container came up healthy. - Engine + DB + embeds → one VPS via
infra/docker-compose.yml(Postgres+pgvector, Redis, api, worker, NocoDB, Metabase, Caddy). - Env inventory:
.env.example. - Auth on
/api/0pt/*is fail-closed: withAUTH_ENFORCEunset the middleware REQUIRES a verified Zitadel Bearer token (401 without one). Only the literalAUTH_ENFORCE=falsedisables it, and that is refused whenNODE_ENV=production(the process throws at startup rather than serving anonymously). Caveat (live-verified 2026-08-10): the deployed instance still answersGET /api/0ptwith 200 anonymously — the middleware appears not to run in production (gap S1, root cause unknown). Do not rely on this being enforced until an anonymous request gets a real 401. - Fonts: self-hosted via
@fontsource-variable/inter+@fontsource-variable/jetbrains-mono(no Google Fonts /next/font/google). - API contract (SSOT):
contracts/openapi.yaml.
Status
Frontend, full order lifecycle, customer + admin portals, edge API, payment/auth/embed infrastructure, the compliant data engine, schema and infra are all in place and building green. Integrations are env-guarded and activate when their keys/DB are provided:
- Database — Vercel → Storage → Postgres (sets
POSTGRES_URL) → durable persistence (schema insql/001_init.sql). - Stripe + Resend keys → payments + email.
- VPS for the engine → set
ENGINE_URL. AUTH_SECRET+DEV_LOGIN_KEY→ login (full OAuth via Auth.js lands with the DB).
© 2026 SIAX Technology AB. Not affiliated with Protosell.