diff --git a/.env.example b/.env.example
index be9397f..bec0d82 100644
--- a/.env.example
+++ b/.env.example
@@ -97,6 +97,9 @@ ENGINE_URL=http://localhost:8000
CL0UD_URL=
N0D_URL=
AUD0_URL=
+# INF0 (AI OS) -- documented target, not yet read by any code in this repo.
+# Route AI-parsning / model calls through the gateway instead of raw provider keys.
+INF0_URL=
# ST0RE_URL is the convention name for src/clients/st0re-client.ts /
# st0re-lakehouse-client.ts and is read by the real-infra test suite
# (tests/p0/*.realinfra.test.ts). The lakehouse write path was live-verified
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..e7a6cdc
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,37 @@
+# Normalize line endings for text files; keep binaries untouched.
+* text=auto
+
+# Source / config
+*.ts text eol=lf
+*.tsx text eol=lf
+*.js text eol=lf
+*.mjs text eol=lf
+*.cjs text eol=lf
+*.css text eol=lf
+*.json text eol=lf
+*.jsonc text eol=lf
+*.yaml text eol=lf
+*.yml text eol=lf
+*.py text eol=lf
+*.md text eol=lf
+*.sh text eol=lf
+Dockerfile text eol=lf
+*.dockerfile text eol=lf
+
+# Binaries / generated — never text-normalized
+*.png binary
+*.jpg binary
+*.jpeg binary
+*.gif binary
+*.webp binary
+*.ico binary
+*.svg text eol=lf
+*.woff binary
+*.woff2 binary
+*.ttf binary
+*.otf binary
+*.pyc binary
+*.pyo binary
+
+# Lockfiles — keep exactly as generated
+pnpm-lock.yaml -text
diff --git a/.npmrc b/.npmrc
index 21d37e3..8e42c68 100644
--- a/.npmrc
+++ b/.npmrc
@@ -1,3 +1,8 @@
verify-deps-before-run=false
include-workspace-root=true
confirmModulesPurge=false
+
+# SIAX Cloud publishes @siax/* packages from Gitea's own npm registry.
+# Only scoped @siax/* names resolve here; everything else stays on the
+# public npm registry.
+@siax:registry=https://git.siax.io/api/packages/sax3l/npm/
diff --git a/app/globals.css b/app/globals.css
index 5ac6dd8..bf952b2 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -1,9 +1,13 @@
+@import '@fontsource-variable/inter';
+@import '@fontsource-variable/jetbrains-mono';
@import 'tailwindcss';
@import 'tw-animate-css';
@custom-variant dark (&:is(.dark *));
:root {
+ --font-inter: 'Inter Variable', 'Inter', system-ui, sans-serif;
+ --font-jetbrains-mono: 'JetBrains Mono Variable', 'JetBrains Mono', ui-monospace, monospace;
--background: #FFFFFF;
--foreground: #0A0A0A;
--card: #FFFFFF;
diff --git a/app/layout.tsx b/app/layout.tsx
index 45197b8..7c3ea82 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -1,16 +1,11 @@
import React from "react";
import type { Metadata } from "next";
-import { Inter, JetBrains_Mono } from "next/font/google";
-import { Analytics } from "@vercel/analytics/next";
import { Toaster } from "sonner";
import { LocaleProvider } from "@/components/locale-provider";
import { ThemeProvider } from "@/components/theme-provider";
import { RouteReveal } from "@/components/route-reveal";
import "./globals.css";
-const inter = Inter({ subsets: ["latin"], variable: "--font-inter" });
-const jetbrainsMono = JetBrains_Mono({ subsets: ["latin"], variable: "--font-jetbrains-mono" });
-
export const metadata: Metadata = {
title: "0pt — your data",
description:
@@ -47,7 +42,7 @@ export const metadata: Metadata = {
export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) {
return (
-
+
-
);
diff --git a/contracts/openapi.yaml b/contracts/openapi.yaml
new file mode 100644
index 0000000..4891b0b
--- /dev/null
+++ b/contracts/openapi.yaml
@@ -0,0 +1,548 @@
+openapi: 3.1.0
+info:
+ title: 0pt Data OS API
+ version: 1.0.0
+ description: >
+ SIAX Cloud Data OS — order-, estimat- och capability-API (0pt).
+ Single Source of Truth för HTTP-kontraktet (SSOT). Routehandlers i
+ app/api/* realiserar dessa kontrakt; se x-siax-status för vad som är
+ live vs kontrakt-first (target).
+ x-siax:
+ appId: 0PT
+ capabilityPrefix: 0pt
+ tenantBinding: header X-Tenant-Id (live), session (target — se BACKLOG P0-2)
+servers:
+ - url: https://0pt.app
+ description: Production (edge plane)
+ - url: https://api.0pt.app
+ description: Target API-host (Caddy, EJ verifierad live)
+security:
+ - bearerAuth: []
+paths:
+ /api/health:
+ get:
+ operationId: 0pt.health
+ summary: Liveness + dependency state
+ x-siax-status: live
+ responses:
+ "200":
+ description: OK — db/queue rapporterar "configured"/"not_configured"
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/HealthResponse"
+ /api/estimates:
+ post:
+ operationId: 0pt.estimate_order
+ summary: Prisestimat för en datajob-konfiguration
+ x-siax-status: live
+ security: []
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/EstimateRequest"
+ responses:
+ "200":
+ description: Estimat (öre)
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/EstimateResponse"
+ "400":
+ $ref: "#/components/responses/BadRequest"
+ /api/orders:
+ post:
+ operationId: 0pt.create_order
+ summary: Skapa draft-order (50 % deposition startar jobbet)
+ x-siax-status: live
+ security: []
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/CreateOrderRequest"
+ responses:
+ "201":
+ description: Order skapad
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/OrderSummary"
+ "400":
+ $ref: "#/components/responses/BadRequest"
+ get:
+ operationId: 0pt.list_orders
+ summary: Lista ordrar (org-scoping saknas — se BACKLOG P0-3)
+ x-siax-status: live
+ x-siax-gap: S3 — ingen auth/org-scoping
+ security: []
+ responses:
+ "200":
+ description: Orderlista
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: "#/components/schemas/OrderSummary"
+ /api/orders/{id}:
+ get:
+ operationId: 0pt.get_order
+ summary: Hämta order
+ x-siax-status: live
+ security: []
+ parameters:
+ - $ref: "#/components/parameters/OrderId"
+ responses:
+ "200":
+ description: Order
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/Order"
+ "404":
+ $ref: "#/components/responses/NotFound"
+ patch:
+ operationId: 0pt.update_order
+ summary: Uppdatera order
+ x-siax-status: live
+ security: []
+ parameters:
+ - $ref: "#/components/parameters/OrderId"
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ responses:
+ "200":
+ description: Uppdaterad order
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/Order"
+ "404":
+ $ref: "#/components/responses/NotFound"
+ /api/0pt:
+ get:
+ operationId: 0pt.capability_index
+ summary: Capability-index
+ x-siax-status: live
+ responses:
+ "200":
+ description: Index med endpoints
+ content:
+ application/json:
+ schema:
+ type: object
+ additionalProperties: true
+ /api/0pt/sources/{sourceId}/query:
+ post:
+ operationId: 0pt.query_source
+ summary: Bunden källfråga (enrich-primitiv)
+ x-siax-status: live
+ x-siax-gap: S10 — connection_config ur body (SSRF-primitiv, BACKLOG P0-7)
+ parameters:
+ - name: sourceId
+ in: path
+ required: true
+ schema:
+ type: string
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/SourceQueryRequest"
+ responses:
+ "200":
+ description: Källdata med provenance per fält
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: "#/components/schemas/EnrichedRecord"
+ "400":
+ $ref: "#/components/responses/BadRequest"
+ /api/0pt/documents/capture:
+ post:
+ operationId: 0pt.capture_document
+ summary: Ta emot dokument (PII) för extraktion
+ x-siax-status: live
+ x-siax-gap: S2 — tenant_id från body (BACKLOG P0-2)
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ additionalProperties: true
+ responses:
+ "201":
+ description: Dokument registrerat
+ "400":
+ $ref: "#/components/responses/BadRequest"
+ get:
+ operationId: 0pt.list_documents
+ summary: Lista dokument
+ x-siax-status: live
+ x-siax-gap: S2 — tenant_id från query (BACKLOG P0-2)
+ responses:
+ "200":
+ description: Dokumentlista
+ /api/0pt/documents/{documentId}/extraction:
+ post:
+ operationId: 0pt.extract_document
+ summary: Extrahera dokument (OCR/AI — env-guardad, 501 utan konfig)
+ x-siax-status: live
+ parameters:
+ - name: documentId
+ in: path
+ required: true
+ schema:
+ type: string
+ responses:
+ "200":
+ description: Extraktion — aldrig fabricerade värden
+ "404":
+ $ref: "#/components/responses/NotFound"
+ "501":
+ $ref: "#/components/responses/NotConfigured"
+ /api/0pt/lakehouse/mappings:
+ post:
+ operationId: 0pt.map_dataset_to_iceberg
+ summary: Registrera dataset↔Iceberg-mappning
+ x-siax-status: live
+ x-siax-gap: S2 — tenant_id från body (BACKLOG P0-2)
+ responses:
+ "201":
+ description: Mappning registrerad
+ "400":
+ $ref: "#/components/responses/BadRequest"
+ get:
+ operationId: 0pt.list_iceberg_mappings
+ summary: Lista mappningar
+ x-siax-status: live
+ x-siax-gap: S2 — tenant_id från query (BACKLOG P0-2)
+ responses:
+ "200":
+ description: Mappningslista
+ /api/0pt/lakehouse/mappings/{mappingId}/writes:
+ post:
+ operationId: 0pt.request_iceberg_write
+ summary: Iceberg-write (L4) — tung variant delegeras till N0D-jobb
+ x-siax-status: live
+ x-siax-gap: S5 — CL0UD fail-open (BACKLOG P0-5)
+ parameters:
+ - name: mappingId
+ in: path
+ required: true
+ schema:
+ type: string
+ responses:
+ "202":
+ description: Skrivning begärd (job_id eller synkront snapshot)
+ "400":
+ $ref: "#/components/responses/BadRequest"
+ /api/0pt/sources/rate-policies:
+ post:
+ operationId: 0pt.create_rate_policy
+ summary: Registrera käll-rate-policy
+ x-siax-status: live
+ x-siax-gap: S2 — tenant_id från body (BACKLOG P0-2)
+ responses:
+ "201":
+ description: Rate-policy skapad
+ get:
+ operationId: 0pt.list_rate_policies
+ summary: Lista rate-policies
+ x-siax-status: live
+ x-siax-gap: S2 — tenant_id från query (BACKLOG P0-2)
+ responses:
+ "200":
+ description: Rate-policylista
+ /api/screen:
+ get:
+ operationId: 0pt.screen_entity
+ summary: Sanktions-/PEP-screening via OpenSanctions
+ x-siax-status: live
+ security: []
+ parameters:
+ - name: q
+ in: query
+ required: true
+ schema:
+ type: string
+ responses:
+ "200":
+ description: Screeningträffar
+ "400":
+ $ref: "#/components/responses/BadRequest"
+ /v1/0pt/enrichment/company-lists:
+ post:
+ operationId: 0pt.enrich_company_list
+ summary: >
+ (TARGET) Capability-formen av enrichment: lista → enrichade poster med
+ bridge_provenance. Kontrakt-first — implementeras av 0pt-motor/edge
+ via N0D-jobb (job_type 0pt.enrichment.company_list).
+ x-siax-status: target
+ security: []
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/EnrichCompanyListRequest"
+ responses:
+ "202":
+ description: Jobb begärt — poll via /v1/0pt/jobs/{id} (target)
+ "401":
+ $ref: "#/components/responses/Unauthorized"
+ /v1/0pt/resolve/entities:
+ post:
+ operationId: 0pt.resolve_entities
+ summary: (TARGET) Entity resolution/dedupe (rapidfuzz idag, spaCy planerat)
+ x-siax-status: target
+ security: []
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ResolveEntitiesRequest"
+ responses:
+ "200":
+ description: Kluster med konfidens
+ "401":
+ $ref: "#/components/responses/Unauthorized"
+ /v1/0pt/provenance/records/{entityType}/{entityKey}:
+ get:
+ operationId: 0pt.get_provenance
+ summary: (TARGET) Provenance per fält — bridge_provenance (källa, färskhet, konfidens, level)
+ x-siax-status: target
+ security: []
+ parameters:
+ - name: entityType
+ in: path
+ required: true
+ schema:
+ type: string
+ enum: [company, contact, vehicle, ubo]
+ - name: entityKey
+ in: path
+ required: true
+ schema:
+ type: string
+ responses:
+ "200":
+ description: Provenance per fält
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ProvenanceRecord"
+ "401":
+ $ref: "#/components/responses/Unauthorized"
+components:
+ securitySchemes:
+ bearerAuth:
+ type: http
+ scheme: bearer
+ description: Zitadel-utfärdad token; verifieras i middleware mot ZITADEL_ISSUER
+ parameters:
+ OrderId:
+ name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ responses:
+ BadRequest:
+ description: Ogiltig input
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ErrorEnvelope"
+ Unauthorized:
+ description: Saknad/ogiltig Bearer-token
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ErrorEnvelope"
+ NotFound:
+ description: Resursen finns inte
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ErrorEnvelope"
+ NotConfigured:
+ description: Integration ej konfigurerad (501)
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ErrorEnvelope"
+ schemas:
+ ErrorEnvelope:
+ type: object
+ required: [error]
+ properties:
+ error:
+ type: object
+ required: [code]
+ properties:
+ code:
+ type: string
+ description: error.code-envelope (t.ex. bad_json, storage_not_configured)
+ message:
+ type: string
+ HealthResponse:
+ type: object
+ required: [ok, service, db, queue, ts]
+ properties:
+ ok:
+ type: boolean
+ service:
+ type: string
+ db:
+ type: string
+ enum: [configured, not_configured]
+ queue:
+ type: string
+ enum: [configured, not_configured]
+ ts:
+ type: string
+ format: date-time
+ EstimateRequest:
+ type: object
+ properties:
+ flow:
+ type: string
+ config:
+ type: object
+ additionalProperties: true
+ EstimateResponse:
+ type: object
+ properties:
+ estimate:
+ type: object
+ additionalProperties: true
+ CreateOrderRequest:
+ type: object
+ properties:
+ flow:
+ type: string
+ default: custom
+ config:
+ type: object
+ additionalProperties: true
+ OrderSummary:
+ type: object
+ required: [order_id, status]
+ properties:
+ order_id:
+ type: string
+ status:
+ type: string
+ deposit_ore:
+ type: integer
+ description: Deposition i öre
+ total_ore:
+ type: integer
+ description: Totalsumma i öre
+ Order:
+ type: object
+ properties:
+ order_id:
+ type: string
+ status:
+ type: string
+ config:
+ type: object
+ additionalProperties: true
+ SourceQueryRequest:
+ type: object
+ required: [tenant_id, source_id, query]
+ properties:
+ tenant_id:
+ type: string
+ description: (GAP) ska komma från session — BACKLOG P0-2
+ project_id:
+ type: string
+ source_id:
+ type: string
+ query:
+ type: string
+ connection_config:
+ type: object
+ additionalProperties: true
+ description: (GAP) SSRF-primitiv — BACKLOG P0-7
+ EnrichedRecord:
+ type: object
+ properties:
+ fields:
+ type: object
+ additionalProperties: true
+ provenance:
+ type: object
+ additionalProperties:
+ $ref: "#/components/schemas/FieldProvenance"
+ FieldProvenance:
+ type: object
+ required: [source_id, freshness, confidence, level]
+ properties:
+ source_id:
+ type: string
+ freshness:
+ type: string
+ format: date-time
+ confidence:
+ type: number
+ minimum: 0
+ maximum: 1
+ level:
+ type: integer
+ minimum: 0
+ maximum: 3
+ description: 0=ej tillgänglig · 1=licensierad · 2=authorized web · 3=officiell API/bulk
+ EnrichCompanyListRequest:
+ type: object
+ required: [market, entities]
+ properties:
+ market:
+ type: string
+ entities:
+ type: array
+ items:
+ type: object
+ additionalProperties: true
+ fields:
+ type: array
+ items:
+ type: string
+ output_artifact_type:
+ type: string
+ default: st0re.artifact
+ ResolveEntitiesRequest:
+ type: object
+ required: [records]
+ properties:
+ records:
+ type: array
+ items:
+ type: object
+ additionalProperties: true
+ threshold:
+ type: number
+ default: 0.85
+ algorithm:
+ type: string
+ enum: [rapidfuzz, target_spacy]
+ default: rapidfuzz
+ ProvenanceRecord:
+ type: object
+ additionalProperties:
+ $ref: "#/components/schemas/FieldProvenance"
diff --git a/package.json b/package.json
index 725427b..8bdf905 100644
--- a/package.json
+++ b/package.json
@@ -1,5 +1,5 @@
{
- "name": "my-v0-project",
+ "name": "@siax/0pt",
"version": "0.1.0",
"private": true,
"packageManager": "pnpm@9.15.9",
@@ -17,6 +17,8 @@
"typecheck:app": "tsc --noEmit -p tsconfig.json"
},
"dependencies": {
+ "@fontsource-variable/inter": "^5.2.5",
+ "@fontsource-variable/jetbrains-mono": "^5.2.5",
"@hookform/resolvers": "^3.10.0",
"@radix-ui/react-accordion": "1.2.2",
"@radix-ui/react-alert-dialog": "1.1.4",
@@ -45,7 +47,6 @@
"@radix-ui/react-toggle": "1.1.1",
"@radix-ui/react-toggle-group": "1.1.1",
"@radix-ui/react-tooltip": "1.1.6",
- "@vercel/analytics": "1.3.1",
"autoprefixer": "^10.4.20",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index b01d7b0..fe83c30 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -8,6 +8,12 @@ importers:
.:
dependencies:
+ '@fontsource-variable/inter':
+ specifier: ^5.2.5
+ version: 5.3.0
+ '@fontsource-variable/jetbrains-mono':
+ specifier: ^5.2.5
+ version: 5.3.0
'@hookform/resolvers':
specifier: ^3.10.0
version: 3.10.0(react-hook-form@7.80.0(react@19.2.0))
@@ -92,9 +98,6 @@ importers:
'@radix-ui/react-tooltip':
specifier: 1.1.6
version: 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
- '@vercel/analytics':
- specifier: 1.3.1
- version: 1.3.1(next@16.0.10(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)
autoprefixer:
specifier: ^10.4.20
version: 10.5.0(postcss@8.5.15)
@@ -433,6 +436,12 @@ packages:
'@floating-ui/utils@0.2.11':
resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==}
+ '@fontsource-variable/inter@5.3.0':
+ resolution: {integrity: sha512-OupL48va4JNofb97w6NYeF9S7W/kHNKM0Er8Dem5nqi4jeOLrVJDoE8tZEpnMJmtkvNbB1EIPPwHcdkF6b1oUA==}
+
+ '@fontsource-variable/jetbrains-mono@5.3.0':
+ resolution: {integrity: sha512-F32xpS2NsGYoQi2ADSkKTgpJj7ozajsGgDJ8woTnqjmIB+dxDIqImjl4pXZVEExu8UFZ2ndhmX18EBS/hdz3Lw==}
+
'@hookform/resolvers@3.10.0':
resolution: {integrity: sha512-79Dv+3mDF7i+2ajj7SkypSKHhl1cbln1OGavqrsF7p6mbUv11xpqpacPsGDCTRvCSjEEIez2ef1NveSVL3b0Ag==}
peerDependencies:
@@ -1643,17 +1652,6 @@ packages:
resolution: {integrity: sha512-8C71BQkGjiMmXtop7pHVJu1l2NNShFdkCyD6a2ezzs5vU/L3LRtb69EtcteFwz0mYMPzIgOw0n6OV4VBUWZd7A==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- '@vercel/analytics@1.3.1':
- resolution: {integrity: sha512-xhSlYgAuJ6Q4WQGkzYTLmXwhYl39sWjoMA3nHxfkvG+WdBT25c563a7QhwwKivEOZtPJXifYHR1m2ihoisbWyA==}
- peerDependencies:
- next: '>= 13'
- react: ^18 || ^19
- peerDependenciesMeta:
- next:
- optional: true
- react:
- optional: true
-
'@vitest/expect@3.2.7':
resolution: {integrity: sha512-E8eBXaKibuvH2pSZErOjdVb5vF4PbKYcrnluBTYxEk1l/VhhwZg1kZQsdtjq+CsF5CFydf2Rdkz7jDHKSisi3w==}
@@ -2423,9 +2421,6 @@ packages:
engines: {node: '>=10'}
hasBin: true
- server-only@0.0.1:
- resolution: {integrity: sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==}
-
sharp@0.34.5:
resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
@@ -2852,6 +2847,10 @@ snapshots:
'@floating-ui/utils@0.2.11': {}
+ '@fontsource-variable/inter@5.3.0': {}
+
+ '@fontsource-variable/jetbrains-mono@5.3.0': {}
+
'@hookform/resolvers@3.10.0(react-hook-form@7.80.0(react@19.2.0))':
dependencies:
react-hook-form: 7.80.0(react@19.2.0)
@@ -3992,13 +3991,6 @@ snapshots:
'@typescript-eslint/types': 8.65.0
eslint-visitor-keys: 5.0.1
- '@vercel/analytics@1.3.1(next@16.0.10(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)':
- dependencies:
- server-only: 0.0.1
- optionalDependencies:
- next: 16.0.10(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
- react: 19.2.0
-
'@vitest/expect@3.2.7':
dependencies:
'@types/chai': 5.2.3
@@ -4749,8 +4741,6 @@ snapshots:
semver@7.8.5: {}
- server-only@0.0.1: {}
-
sharp@0.34.5:
dependencies:
'@img/colour': 1.1.0
diff --git a/renovate.json b/renovate.json
index 5db72dd..ffa30e5 100644
--- a/renovate.json
+++ b/renovate.json
@@ -2,5 +2,22 @@
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended"
+ ],
+ "platform": "gitea",
+ "semanticCommits": "enabled",
+ "dependencyDashboard": true,
+ "schedule": ["before 6am on tuesday"],
+ "packageRules": [
+ {
+ "description": "Batch minor/patch updates of the v0-generated UI stack",
+ "matchDepNames": ["@radix-ui/*", "react", "react-dom", "next", "tailwindcss", "typescript"],
+ "groupName": "web-stack",
+ "separateMajorMinor": true
+ },
+ {
+ "description": "Do not auto-update the scraper stack (kept intact per deliberate user decision)",
+ "matchFiles": ["services/scrapers/requirements.txt", "services/api/requirements.txt"],
+ "enabled": false
+ }
]
}
diff --git a/services/scrapers/requirements.txt b/services/scrapers/requirements.txt
index c16119a..47a8da7 100644
--- a/services/scrapers/requirements.txt
+++ b/services/scrapers/requirements.txt
@@ -7,3 +7,4 @@ requests>=2.33.0
beautifulsoup4>=4.12.0
lxml>=5.3.0
boto3>=1.35.0 # MinIO S3 sync
+duckdb>=1.1.0 # DuckDBWriter alternative (lazy-imported in clickhouse_pipeline.py)