diff --git a/drizzle/0000_ancient_silver_surfer.sql b/drizzle/0000_ancient_silver_surfer.sql new file mode 100644 index 0000000..42dc7ea --- /dev/null +++ b/drizzle/0000_ancient_silver_surfer.sql @@ -0,0 +1,187 @@ +CREATE TYPE "public"."document_classification" AS ENUM('c0', 'c1', 'c2', 'c3', 'c4');--> statement-breakpoint +CREATE TYPE "public"."goal_status" AS ENUM('not_started', 'on_track', 'at_risk', 'achieved', 'abandoned');--> statement-breakpoint +CREATE TYPE "public"."membership_role" AS ENUM('owner', 'admin', 'member');--> statement-breakpoint +CREATE TYPE "public"."task_status" AS ENUM('open', 'in_progress', 'blocked', 'done', 'cancelled');--> statement-breakpoint +CREATE TYPE "public"."transaction_evidence_status" AS ENUM('missing', 'partial', 'complete', 'not_required');--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "ai_requests" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "tenant_id" uuid NOT NULL, + "requested_by_user_id" uuid NOT NULL, + "purpose" text NOT NULL, + "context_manifest_hash" text NOT NULL, + "model" text NOT NULL, + "template_version" text, + "cost_usd_minor_units" integer, + "result_status" text DEFAULT 'pending' NOT NULL, + "created_at" timestamp DEFAULT now() NOT NULL, + "completed_at" timestamp +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "audit_log" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "tenant_id" uuid NOT NULL, + "actor_id" uuid, + "action" text NOT NULL, + "resource" text NOT NULL, + "reason" text, + "correlation_id" uuid, + "created_at" timestamp DEFAULT now() NOT NULL +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "consent_records" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "tenant_id" uuid NOT NULL, + "user_id" uuid NOT NULL, + "purpose" text NOT NULL, + "granted_at" timestamp DEFAULT now() NOT NULL, + "revoked_at" timestamp +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "decisions" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "tenant_id" uuid NOT NULL, + "owner_user_id" uuid NOT NULL, + "context" text NOT NULL, + "options" jsonb DEFAULT '[]'::jsonb NOT NULL, + "assumptions" jsonb DEFAULT '[]'::jsonb NOT NULL, + "evidence" jsonb DEFAULT '[]'::jsonb NOT NULL, + "selected_option" text, + "outcome_review" text, + "review_due_at" timestamp, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "documents" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "tenant_id" uuid NOT NULL, + "organization_id" uuid, + "owner_user_id" uuid NOT NULL, + "classification" "document_classification" DEFAULT 'c2' NOT NULL, + "paperless_id" text, + "filename" text NOT NULL, + "checksum" text, + "expires_at" timestamp, + "retention_policy" text, + "ocr_status" text, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL, + "deleted_at" timestamp, + "version" integer DEFAULT 1 NOT NULL +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "goals" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "tenant_id" uuid NOT NULL, + "owner_user_id" uuid NOT NULL, + "horizon" text NOT NULL, + "metric" text NOT NULL, + "target" text NOT NULL, + "milestones" jsonb DEFAULT '[]'::jsonb NOT NULL, + "status" "goal_status" DEFAULT 'not_started' NOT NULL, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL, + "deleted_at" timestamp, + "version" integer DEFAULT 1 NOT NULL +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "memberships" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "tenant_id" uuid NOT NULL, + "user_id" uuid NOT NULL, + "role" "membership_role" DEFAULT 'member' NOT NULL, + "created_at" timestamp DEFAULT now() NOT NULL +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "observations" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "tenant_id" uuid NOT NULL, + "subject_type" text NOT NULL, + "subject_id" text NOT NULL, + "metric" text NOT NULL, + "value" text NOT NULL, + "unit" text, + "source" text NOT NULL, + "observed_at" timestamp DEFAULT now() NOT NULL, + "confidence" numeric(5, 4) +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "opportunities" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "tenant_id" uuid NOT NULL, + "source" text NOT NULL, + "entity_type" text, + "entity_id" text, + "value_range_min" numeric(18, 0), + "value_range_max" numeric(18, 0), + "probability" numeric(5, 4), + "next_action" text, + "expires_at" timestamp, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "organizations" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "tenant_id" uuid NOT NULL, + "name" text NOT NULL, + "legal_name" text, + "country" text, + "registry_id" text, + "domain" text, + "external_ids" jsonb DEFAULT '{}'::jsonb NOT NULL, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL, + "deleted_at" timestamp, + "version" integer DEFAULT 1 NOT NULL +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "outbox_events" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "tenant_id" uuid NOT NULL, + "event_type" text NOT NULL, + "event_version" integer DEFAULT 1 NOT NULL, + "subject_id" uuid, + "payload" jsonb NOT NULL, + "correlation_id" uuid, + "created_at" timestamp DEFAULT now() NOT NULL, + "processed_at" timestamp +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "tasks" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "tenant_id" uuid NOT NULL, + "owner_user_id" uuid NOT NULL, + "title" text NOT NULL, + "priority" integer DEFAULT 3 NOT NULL, + "due_at" timestamp, + "source_entity_type" text, + "source_entity_id" uuid, + "status" "task_status" DEFAULT 'open' NOT NULL, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL, + "deleted_at" timestamp, + "version" integer DEFAULT 1 NOT NULL +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "tenants" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "name" text NOT NULL, + "created_at" timestamp DEFAULT now() NOT NULL +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "transactions" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "tenant_id" uuid NOT NULL, + "organization_id" uuid NOT NULL, + "type" text NOT NULL, + "amount_minor_units" numeric(18, 0) NOT NULL, + "currency" text NOT NULL, + "transaction_date" timestamp NOT NULL, + "evidence_status" "transaction_evidence_status" DEFAULT 'missing' NOT NULL, + "source" text, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL, + "deleted_at" timestamp, + "version" integer DEFAULT 1 NOT NULL +); diff --git a/drizzle/meta/0000_snapshot.json b/drizzle/meta/0000_snapshot.json new file mode 100644 index 0000000..fa41d45 --- /dev/null +++ b/drizzle/meta/0000_snapshot.json @@ -0,0 +1,1158 @@ +{ + "id": "de8a2199-0127-49a7-a7fc-ff01319efbff", + "prevId": "00000000-0000-0000-0000-000000000000", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.ai_requests": { + "name": "ai_requests", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "tenant_id": { + "name": "tenant_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "requested_by_user_id": { + "name": "requested_by_user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "purpose": { + "name": "purpose", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "context_manifest_hash": { + "name": "context_manifest_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "model": { + "name": "model", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "template_version": { + "name": "template_version", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cost_usd_minor_units": { + "name": "cost_usd_minor_units", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "result_status": { + "name": "result_status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.audit_log": { + "name": "audit_log", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "tenant_id": { + "name": "tenant_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "actor_id": { + "name": "actor_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resource": { + "name": "resource", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "correlation_id": { + "name": "correlation_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.consent_records": { + "name": "consent_records", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "tenant_id": { + "name": "tenant_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "purpose": { + "name": "purpose", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "granted_at": { + "name": "granted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "revoked_at": { + "name": "revoked_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.decisions": { + "name": "decisions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "tenant_id": { + "name": "tenant_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "owner_user_id": { + "name": "owner_user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "context": { + "name": "context", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "options": { + "name": "options", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "assumptions": { + "name": "assumptions", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "evidence": { + "name": "evidence", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "selected_option": { + "name": "selected_option", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "outcome_review": { + "name": "outcome_review", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "review_due_at": { + "name": "review_due_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.documents": { + "name": "documents", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "tenant_id": { + "name": "tenant_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "owner_user_id": { + "name": "owner_user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "classification": { + "name": "classification", + "type": "document_classification", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'c2'" + }, + "paperless_id": { + "name": "paperless_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "filename": { + "name": "filename", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "checksum": { + "name": "checksum", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "retention_policy": { + "name": "retention_policy", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ocr_status": { + "name": "ocr_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.goals": { + "name": "goals", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "tenant_id": { + "name": "tenant_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "owner_user_id": { + "name": "owner_user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "horizon": { + "name": "horizon", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "metric": { + "name": "metric", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "target": { + "name": "target", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "milestones": { + "name": "milestones", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "status": { + "name": "status", + "type": "goal_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'not_started'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.memberships": { + "name": "memberships", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "tenant_id": { + "name": "tenant_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "membership_role", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'member'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.observations": { + "name": "observations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "tenant_id": { + "name": "tenant_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "subject_type": { + "name": "subject_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "subject_id": { + "name": "subject_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "metric": { + "name": "metric", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "unit": { + "name": "unit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "observed_at": { + "name": "observed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "confidence": { + "name": "confidence", + "type": "numeric(5, 4)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.opportunities": { + "name": "opportunities", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "tenant_id": { + "name": "tenant_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entity_type": { + "name": "entity_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "entity_id": { + "name": "entity_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "value_range_min": { + "name": "value_range_min", + "type": "numeric(18, 0)", + "primaryKey": false, + "notNull": false + }, + "value_range_max": { + "name": "value_range_max", + "type": "numeric(18, 0)", + "primaryKey": false, + "notNull": false + }, + "probability": { + "name": "probability", + "type": "numeric(5, 4)", + "primaryKey": false, + "notNull": false + }, + "next_action": { + "name": "next_action", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organizations": { + "name": "organizations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "tenant_id": { + "name": "tenant_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "legal_name": { + "name": "legal_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "country": { + "name": "country", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "registry_id": { + "name": "registry_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "domain": { + "name": "domain", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "external_ids": { + "name": "external_ids", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.outbox_events": { + "name": "outbox_events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "tenant_id": { + "name": "tenant_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "event_type": { + "name": "event_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "event_version": { + "name": "event_version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "subject_id": { + "name": "subject_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "payload": { + "name": "payload", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "correlation_id": { + "name": "correlation_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "processed_at": { + "name": "processed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.tasks": { + "name": "tasks", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "tenant_id": { + "name": "tenant_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "owner_user_id": { + "name": "owner_user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "priority": { + "name": "priority", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 3 + }, + "due_at": { + "name": "due_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "source_entity_type": { + "name": "source_entity_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_entity_id": { + "name": "source_entity_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "task_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'open'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.tenants": { + "name": "tenants", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.transactions": { + "name": "transactions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "tenant_id": { + "name": "tenant_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "amount_minor_units": { + "name": "amount_minor_units", + "type": "numeric(18, 0)", + "primaryKey": false, + "notNull": true + }, + "currency": { + "name": "currency", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "transaction_date": { + "name": "transaction_date", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "evidence_status": { + "name": "evidence_status", + "type": "transaction_evidence_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'missing'" + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.document_classification": { + "name": "document_classification", + "schema": "public", + "values": [ + "c0", + "c1", + "c2", + "c3", + "c4" + ] + }, + "public.goal_status": { + "name": "goal_status", + "schema": "public", + "values": [ + "not_started", + "on_track", + "at_risk", + "achieved", + "abandoned" + ] + }, + "public.membership_role": { + "name": "membership_role", + "schema": "public", + "values": [ + "owner", + "admin", + "member" + ] + }, + "public.task_status": { + "name": "task_status", + "schema": "public", + "values": [ + "open", + "in_progress", + "blocked", + "done", + "cancelled" + ] + }, + "public.transaction_evidence_status": { + "name": "transaction_evidence_status", + "schema": "public", + "values": [ + "missing", + "partial", + "complete", + "not_required" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json new file mode 100644 index 0000000..040eb51 --- /dev/null +++ b/drizzle/meta/_journal.json @@ -0,0 +1,13 @@ +{ + "version": "7", + "dialect": "postgresql", + "entries": [ + { + "idx": 0, + "version": "7", + "when": 1784655760242, + "tag": "0000_ancient_silver_surfer", + "breakpoints": true + } + ] +} \ No newline at end of file diff --git a/src/db/schema.ts b/src/db/schema.ts index 17ce048..321bd57 100644 --- a/src/db/schema.ts +++ b/src/db/schema.ts @@ -1,10 +1,87 @@ -import { pgTable, pgEnum, uuid, text, timestamp, jsonb, integer } from 'drizzle-orm/pg-core'; +import { pgTable, pgEnum, uuid, text, timestamp, jsonb, integer, numeric } from 'drizzle-orm/pg-core'; + +// --- Business Engine (blueprint sectiunea 5, 12): companii, tranzactii, documente, taskuri --- +// Organizations e sursa de adevar in CEO Postgres pentru companii private (blueprint sectiunea 9); +// ERPNext devine sursa de adevar doar pentru "Accounting official", dupa activare -- vezi +// Blueprint v4.0 sectiunea 9 si Anexa I decizia #3. export const organizations = pgTable('organizations', { id: uuid('id').defaultRandom().primaryKey(), tenantId: uuid('tenant_id').notNull(), name: text('name').notNull(), + legalName: text('legal_name'), + country: text('country'), + registryId: text('registry_id'), + domain: text('domain'), + externalIds: jsonb('external_ids').notNull().default({}), createdAt: timestamp('created_at').defaultNow().notNull(), + updatedAt: timestamp('updated_at').defaultNow().notNull(), + deletedAt: timestamp('deleted_at'), + version: integer('version').notNull().default(1), +}); + +export const transactionEvidenceStatus = pgEnum('transaction_evidence_status', [ + 'missing', + 'partial', + 'complete', + 'not_required', +]); + +// amounts in minor units (cents), niciodata float, per blueprint 12.1 +export const transactions = pgTable('transactions', { + id: uuid('id').defaultRandom().primaryKey(), + tenantId: uuid('tenant_id').notNull(), + organizationId: uuid('organization_id').notNull(), + type: text('type').notNull(), + amountMinorUnits: numeric('amount_minor_units', { precision: 18, scale: 0 }).notNull(), + currency: text('currency').notNull(), + transactionDate: timestamp('transaction_date').notNull(), + evidenceStatus: transactionEvidenceStatus('evidence_status').notNull().default('missing'), + source: text('source'), + createdAt: timestamp('created_at').defaultNow().notNull(), + updatedAt: timestamp('updated_at').defaultNow().notNull(), + deletedAt: timestamp('deleted_at'), + version: integer('version').notNull().default(1), +}); + +export const documentClassification = pgEnum('document_classification', ['c0', 'c1', 'c2', 'c3', 'c4']); + +// CEO OS pastreaza doar metadata/ownership/permission decisions (blueprint sectiunea 13); +// binarul si OCR-ul raman in Paperless-ngx, legate prin paperlessId +export const documents = pgTable('documents', { + id: uuid('id').defaultRandom().primaryKey(), + tenantId: uuid('tenant_id').notNull(), + organizationId: uuid('organization_id'), + ownerUserId: uuid('owner_user_id').notNull(), + classification: documentClassification('classification').notNull().default('c2'), + paperlessId: text('paperless_id'), + filename: text('filename').notNull(), + checksum: text('checksum'), + expiresAt: timestamp('expires_at'), + retentionPolicy: text('retention_policy'), + ocrStatus: text('ocr_status'), + createdAt: timestamp('created_at').defaultNow().notNull(), + updatedAt: timestamp('updated_at').defaultNow().notNull(), + deletedAt: timestamp('deleted_at'), + version: integer('version').notNull().default(1), +}); + +export const taskStatus = pgEnum('task_status', ['open', 'in_progress', 'blocked', 'done', 'cancelled']); + +export const tasks = pgTable('tasks', { + id: uuid('id').defaultRandom().primaryKey(), + tenantId: uuid('tenant_id').notNull(), + ownerUserId: uuid('owner_user_id').notNull(), + title: text('title').notNull(), + priority: integer('priority').notNull().default(3), + dueAt: timestamp('due_at'), + sourceEntityType: text('source_entity_type'), + sourceEntityId: uuid('source_entity_id'), + status: taskStatus('status').notNull().default('open'), + createdAt: timestamp('created_at').defaultNow().notNull(), + updatedAt: timestamp('updated_at').defaultNow().notNull(), + deletedAt: timestamp('deleted_at'), + version: integer('version').notNull().default(1), }); // --- Identity Engine (blueprint sectiunea 11, 8.2, 8.3) --- @@ -36,6 +113,92 @@ export const consentRecords = pgTable('consent_records', { revokedAt: timestamp('revoked_at'), }); +// --- Life Engine (blueprint sectiunea 5): obiective personale, rutine, KPI --- + +export const goalStatus = pgEnum('goal_status', ['not_started', 'on_track', 'at_risk', 'achieved', 'abandoned']); + +export const goals = pgTable('goals', { + id: uuid('id').defaultRandom().primaryKey(), + tenantId: uuid('tenant_id').notNull(), + ownerUserId: uuid('owner_user_id').notNull(), + horizon: text('horizon').notNull(), + metric: text('metric').notNull(), + target: text('target').notNull(), + milestones: jsonb('milestones').notNull().default([]), + status: goalStatus('status').notNull().default('not_started'), + createdAt: timestamp('created_at').defaultNow().notNull(), + updatedAt: timestamp('updated_at').defaultNow().notNull(), + deletedAt: timestamp('deleted_at'), + version: integer('version').notNull().default(1), +}); + +// --- Intelligence Engine (blueprint sectiunea 5): decizii, oportunitati, cereri AI --- + +export const decisions = pgTable('decisions', { + id: uuid('id').defaultRandom().primaryKey(), + tenantId: uuid('tenant_id').notNull(), + ownerUserId: uuid('owner_user_id').notNull(), + context: text('context').notNull(), + options: jsonb('options').notNull().default([]), + assumptions: jsonb('assumptions').notNull().default([]), + evidence: jsonb('evidence').notNull().default([]), + selectedOption: text('selected_option'), + outcomeReview: text('outcome_review'), + reviewDueAt: timestamp('review_due_at'), + createdAt: timestamp('created_at').defaultNow().notNull(), + updatedAt: timestamp('updated_at').defaultNow().notNull(), +}); + +export const opportunities = pgTable('opportunities', { + id: uuid('id').defaultRandom().primaryKey(), + tenantId: uuid('tenant_id').notNull(), + source: text('source').notNull(), + entityType: text('entity_type'), + entityId: text('entity_id'), + valueRangeMin: numeric('value_range_min', { precision: 18, scale: 0 }), + valueRangeMax: numeric('value_range_max', { precision: 18, scale: 0 }), + probability: numeric('probability', { precision: 5, scale: 4 }), + nextAction: text('next_action'), + expiresAt: timestamp('expires_at'), + createdAt: timestamp('created_at').defaultNow().notNull(), + updatedAt: timestamp('updated_at').defaultNow().notNull(), +}); + +// context_manifest_hash leaga cererea de Context Manifest-ul trimis catre AI Gateway +// (blueprint sectiunea 14.1) -- payload-ul complet nu se stocheaza aici, doar hash-ul, +// pentru audit fara a pastra continut sensibil in Postgres +export const aiRequests = pgTable('ai_requests', { + id: uuid('id').defaultRandom().primaryKey(), + tenantId: uuid('tenant_id').notNull(), + requestedByUserId: uuid('requested_by_user_id').notNull(), + purpose: text('purpose').notNull(), + contextManifestHash: text('context_manifest_hash').notNull(), + model: text('model').notNull(), + templateVersion: text('template_version'), + costUsdMinorUnits: integer('cost_usd_minor_units'), + resultStatus: text('result_status').notNull().default('pending'), + createdAt: timestamp('created_at').defaultNow().notNull(), + completedAt: timestamp('completed_at'), +}); + +// --- Trust Engine (blueprint sectiunea 5): dovezi, observatii, reputation factors --- + +// subiectul poate fi orice entitate (user, organization, device) -- identificat prin +// subjectType+subjectId in loc de FK rigid, ca sa ramana generic pe tot ce alimenteaza +// scoruri de incredere/reputatie +export const observations = pgTable('observations', { + id: uuid('id').defaultRandom().primaryKey(), + tenantId: uuid('tenant_id').notNull(), + subjectType: text('subject_type').notNull(), + subjectId: text('subject_id').notNull(), + metric: text('metric').notNull(), + value: text('value').notNull(), + unit: text('unit'), + source: text('source').notNull(), + observedAt: timestamp('observed_at').defaultNow().notNull(), + confidence: numeric('confidence', { precision: 5, scale: 4 }), +}); + // --- Event Fabric / Outbox (blueprint sectiunea 9.1, principiul 2.1 "Events before intelligence") --- export const outboxEvents = pgTable('outbox_events', {