Merges github/main (6 commits: 17-bug audit fix, CI quality gate,
.env.example + .gitignore fix, missing platform clients + registry
services, docs accuracy overhaul) into gitea/main (8 commits: Iceberg
write boundary + live ST0RE verification, lakehouse mapping routes,
Waves 1-4 foundational hardening).
16 conflicts. Both sides had independently written the four
src/clients/*.ts and the two registry services, so those are combined
rather than picked:
- st0re-client.ts: GitHub's endpoint wins on evidence. POST goes to
/v1/st0re/artifacts/register, not /v1/st0re/artifacts -- verified in
sax3l/st0re src/api/routes/artifacts.ts, where the bare path is a
GET-only list route. Gitea's URL normalisation, error-body text and
mock kept.
- n0d-client.ts: field is `status`, not `state`, with N0D's real 13-state
union -- verified in sax3l/n0d packages/schemas/n0d.job.schema.json,
which says explicitly not to add "succeeded". Gitea's mock echo,
URL normalisation and error-body text kept.
- cl0ud-client.ts: Gitea's fail-closed HTTP normalisation kept (a 200
with no `decision` reads as "deny", not as a silent allow). GitHub's
PolicyDecision/PolicyDecisionValue naming kept; PolicyResult retained
as an alias.
- aud0-client.ts: permissive union of both input types (optional
payload/metadata/correlation_id), GitHub's echo return, Gitea's URL
normalisation and error-body text, plus a JSON-parse fallback so a
successful POST with an empty body does not throw.
- dataset-service.ts / source-service.ts: GitHub's record/DTO split and
event naming (0pt.source_created / 0pt.create_source, which the merged
docs already reference) plus Gitea's name validation, description /
created_by fields and actor_id derivation. List filters are the union.
- lakehouse mapping routes: GitHub's shared lakehouse-mapping-registry
singletons (without which every write 400'd "mapping not found") AND
Gitea's Zod parseBody validation. Both, not either.
- src/types/source.ts, src/types/dataset.ts: unions of both vocabularies;
GitHub's `access` legal-sourcing field kept.
- .env.example: GitHub's audited inventory plus Gitea's Zitadel /
AUTH_ENFORCE block.
- CLAUDE.md, docs/ICEBERG_WRITE_BOUNDARY.md: GitHub's corrections kept,
Gitea's live-verification kept and marked as superseding the
"would 400 outright" finding (Gitea had already added the required
X-Tenant-Id/X-Actor-Id headers).
- pnpm-lock.yaml: regenerated with pnpm 9.15.9, not merged.
Also corrects CLAUDE.md's claim that the banned services/scrapers stack
was "since removed" -- the removal PR is open, not merged, and this
branch inherits that code from Gitea main. Nothing here resurrects,
extends or re-wires any of it; services/scrapers/ is byte-identical to
Gitea main.
Verified on the merged tree: typecheck (src/ + tests/) clean;
17 test files, 121 passed, 1 skipped (the realinfra test skipping
honestly on ST0RE HTTP 401), 0 failures. Gitea main baseline was the
same 121/1; GitHub main baseline could not even `pnpm install`
("packages field missing or empty") -- Gitea's pnpm-workspace.yaml fix
resolves that. Whole-repo `typecheck:app` reports 9 errors, an identical
set to Gitea main's baseline, so it is advisory in both CI workflows
rather than deleted. Lint: 16 problems, identical to Gitea baseline.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
68 lines
9.8 KiB
Markdown
68 lines
9.8 KiB
Markdown
# CLAUDE.md — 0pt (SIAX Technology AB)
|
|
|
|
> Read this first. It is the contract for how this project is built. Then read `docs/` in order.
|
|
|
|
## What 0pt is
|
|
|
|
**0pt — your data.** A Nordic/European data-services platform (`0pt.app`) where customers:
|
|
1. **Compose** a data job (markets, entity type, fields, enrichment, frequency, output) — or browse ready-made datasets.
|
|
2. Pay a **50 % deposit** to start; the remaining 50 % is held in **escrow** and released only on approval.
|
|
3. **Watch production live** (sourcing → extraction → structuring → enrichment → QA).
|
|
4. **Validate** the result with full freedom (table / map / schema / quality views) and deliver to any format/destination.
|
|
|
|
Owned by SIAX Technology AB. Feeds internal products too (Protosell/FiveCRM, VehIQ).
|
|
|
|
## Non-negotiable constraints (do not violate)
|
|
|
|
1. **Legal sourcing only.** The data engine uses, in strict priority: official APIs/bulk → authorized scraping of clearly public pages (respect `robots.txt` + rate limits) → licensed partner data → otherwise the field is delivered as **"not available / licensed only"**. We never invent values.
|
|
- **Do NOT build, keep, or extend**: WAF/bot-detection bypass (incl. FlareSolverr, "stealth" browsers, undetected-* used to defeat detection), fingerprint/proxy rotation to evade bans, scraping behind login walls, or automated fake-account creation (Apollo etc.).
|
|
- **Path corrected this pass:** no `src/workers/browser_worker.py` exists anywhere in this checkout (verified via full-repo search) — the engine's actual workers live under `services/api/workers/` (`adaptive_router.py`, `pipeline.py`, `queue.py`, `resolve.py`, `run.py`), none of which contain a FlareSolverr/bypass path today. The precedent for this concern is real and, **as of this GitHub<->Gitea unification merge, it is in this tree**: Gitea's `git.siax.io/sax3l/0pt` `main` independently accumulated a WAF-bypass/proxy-rotation/fake-identity scraper stack (`services/scrapers/*` — `curl_cffi`, `cloudscraper`, Tor circuit rotation) in three 2026-07-13 commits, and this branch inherits it because it branches from Gitea `main`. **The deletion PR (`feature/0pt-remove-noncompliant-scrapers`) is open, NOT merged** — an earlier version of this paragraph claimed it was "since removed", which was false. That removal is deliberately left to its own PR and was *not* folded into this merge; nothing in this merge resurrects, extends, or re-wires any of it. If new code (from either remote) reintroduces a bypass path anywhere, **remove or disable it** and replace with compliant fetching. This is a product-positioning + compliance requirement, not a preference. "Honest accuracy" is the whole moat.
|
|
2. **Postgres is the backbone.** One Postgres is the source of truth. Catalog, portal, NocoDB views, Metabase dashboards, workers, exports all read/write the *same* DB. A tool may only enter the stack if it (a) reads that Postgres and (b) sits behind the same auth.
|
|
3. **Provenance per field.** Every fact carries source, freshness, confidence (`bridge_provenance`). This drives the UI signature too.
|
|
4. **One tool per job.** Do not add overlapping tools. The approved stack is in `docs/02-architecture.md` and `docs/07-dependencies.md`. Anything not listed needs a documented reason.
|
|
5. **GDPR-native.** DPA, lawful basis, audit log, deletion-after-job. Customer DB access is *pull by the customer* via a read-only, time-boxed role they create — never us asking for admin, never raw creds stored in plaintext.
|
|
6. **Design is fixed.** Mono/editorial system (white `#fff`, text `#0a0a0a`, hairline `#e5e5e5`, radius 0, Inter + JetBrains Mono, single red `#e40014`). Exact tokens + motion in `docs/05-design-system.md`. No photography — imagery is rendered data (`DataArtifact`).
|
|
|
|
## Build on existing code
|
|
|
|
A working engine repo already exists. **Corrected this pass — the previous description of it was wrong on every specific:** the FastAPI orchestrator lives at `services/api/orchestrator/main.py` (not `src/orchestrator/main.py`) and registers **12** route handlers (not "25+"); the workers directory is `services/api/workers/` and contains `adaptive_router.py`, `pipeline.py`, `queue.py`, `resolve.py`, and `run.py` (not `browser_worker`/`ocr_worker`/`db` — none of those three files exist anywhere in this repo); and `services/api/sources/sources.yaml` currently covers **7** markets (`SE`, `NO`, `DK`, `FI`, `GB`, `NL`, plus `global`), not 20. `services/api/` holds 11 Python source files total (excluding `__pycache__`). **Reconcile with the code as it actually is, not this description's prior claims.** Where this documentation defines a target contract, migrate the existing code toward it. Flag conflicts instead of guessing.
|
|
|
|
**Two remotes claim to be this repo, and it's unresolved which is authoritative.** `origin` here is `github.com/sax3l/0pt`. A separate Gitea remote, `git.siax.io/sax3l/0pt`, shares at least part of the same history but has independently diverged (see README "Known issues" for specifics). Do not assume `origin` is the only copy of this codebase, and do not silently resolve the question of which is canonical — that is Simon's decision.
|
|
|
|
**Before trusting any status claim in this doc corpus, read README's "Known issues" section.** It covers the auth/tenant-scoping gap, the platform-client mock-only status, and the underlying fact that 0pt's quality-check/QA enforcement code was never built despite once being described as real. **Corrected this pass:** `docs/ICEBERG_WRITE_BOUNDARY.md`, `docs/11-lakehouse-write-plan.md`, and `docs/P0_QUERY_SOURCE_FLOW.md` are now all consistently corrected — each carries its own "fabricated, not built" callout and none asserts `quality-check-service.ts`/`quality-report-service.ts`/etc. as real or tested anywhere in its current body (verified this pass by reading all three in full). `docs/P0_DATASET_QUALITY_FLOW.md` remains the explicit target-spec replacement for what that stage should look like once built. Treat any *other* doc claiming the QA stage already exists as wrong.
|
|
|
|
## How to work
|
|
|
|
- Work in **dependency order** per `docs/09-build-plan.md`. Finish a phase to its acceptance criteria before the next.
|
|
- Small, reviewable commits. Conventional Commits (`feat:`, `fix:`, `docs:`, `chore:`).
|
|
- Frontend = Next.js App Router + TS + Tailwind + shadcn/ui on the SIAX Deploy Platform. Backend = FastAPI + workers on a VPS (long jobs).
|
|
- Tech docs + code identifiers in **English**; all visible **UI copy in Swedish**.
|
|
- Never hardcode secrets — use env (`docs/08-infrastructure.md`).
|
|
- When unsure about a source's current access/licence terms, **verify before relying on it** and record it in the sourcing map; do not assume.
|
|
|
|
## Documentation index
|
|
|
|
| Doc | Purpose |
|
|
|---|---|
|
|
| `docs/01-product.md` | Vision, the three flows, order lifecycle, business model |
|
|
| `docs/02-architecture.md` | System architecture, stack decisions (in/out), hosting |
|
|
| `docs/03-data-model.md` | Postgres schema, provenance model, migrations |
|
|
| `docs/04-api.md` | FastAPI contract (canonical endpoints) |
|
|
| `docs/05-design-system.md` | Mono tokens, motion, visual system, signature |
|
|
| `docs/06-data-engine.md` | Workers, legal sourcing chain, pipeline, QA, fusion, sources.yaml |
|
|
| `docs/07-dependencies.md` | Repos/libraries to import (+ explicit exclusions) |
|
|
| `docs/08-infrastructure.md` | Hosting, docker-compose, env, security, CI/CD |
|
|
| `docs/09-build-plan.md` | Phased milestones with acceptance criteria |
|
|
| `docs/10-lakehouse-decision.md` | Pointer to an ecosystem-wide lakehouse ADR made outside this repo (Apache Iceberg = canonical SIAX lakehouse format, ADR-0030 in the `n0d` repo; 0pt = write-path owner). Does not change `docs/02`/`docs/03` |
|
|
| `docs/11-lakehouse-write-plan.md` | 0pt's own follow-up task list for the Iceberg write boundary — schema/event names for the implementation. **Corrected**: item 4 (quality rules) is explicitly labeled NOT BUILT, and the old fabricated `quality-check-service.ts`/`quality-report-service.ts` claim is quoted only inside its own "Correction" callout, never asserted as fact |
|
|
| `docs/12-edge-capability-api.md` | Edge-native TypeScript P0 capability API contract (`app/api/0pt/*`, `/api/screen`, `/api/ai/parse`) — distinct from `docs/04-api.md`'s FastAPI-engine contract; documents several confirmed always-fails-over-HTTP routes and the tenant_id/in-memory gaps |
|
|
| `docs/ICEBERG_WRITE_BOUNDARY.md` | Implementation record + "real vs. contract-only" verification status: dataset<->Iceberg-table mapping and source-rate-policy contracts, ST0RE lakehouse client, and the 2026-07-13 **live-verified** write path (real namespace/table/snapshot IDs). **Corrected**: its "Data quality: not yet built" section explicitly quotes and retracts the old fabricated claim rather than repeating it as fact |
|
|
| `docs/P0_QUERY_SOURCE_FLOW.md` | `0pt.query_source` bounded source-query flow — **corrected**: no longer claims `quality-check-service.ts` exists, now points at the real precedent (`iceberg-write-service.ts`) instead |
|
|
| `docs/P0_DATASET_QUALITY_FLOW.md` | An explicit **target-spec-only, not-yet-built** replacement for the fabricated quality-check/QA claims — read it as "should", never "does" |
|
|
|
|
**Corrected:** this table previously listed `docs/design/0pt-v0-build-brief.md` and `docs/design/0pt-design-coverage-and-visuals.md` as if they existed. They do not — confirmed via a full-repo search, including after this unification merge; there is no `docs/design/` directory at all. No `docs/` design-brief content is fabricated here to fill the gap. Either write those two docs or stop referencing them; until one of those happens, treat any prior claim that they exist as false.
|
|
|
|
## Definition of done (every screen, before real data)
|
|
|
|
Mono chrome · correct scroll-reveal motion · representative placeholder content · **loading + empty + error** states · mobile layout · provenance signature where facts appear · red used ≤ once · visible focus ring · `prefers-reduced-motion` respected.
|