spb/airiskindex Public
The most methodologically rigorous, fully transparent AI job-exposure index.
TypeScript 88%
Python 6.1%
SQL 2.7%
CSS 1.2%
JavaScript 0.9%
Shell 0.8%
1// File: schema.prisma2// Path: packages/db/prisma/schema.prisma3// Project: AI Risk Index — airiskindex.io4// Author: Simon-Pierre Boucher5// Contact: contact@spboucher.ai6// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.7//8// Description: Database schema: occupations, tasks, rating audit trail, immutable score runs.910// AI Risk Index — database schema.11// Methodology integrity (CLAUDE.md §9): every published score traces to a12// ScoreRun; runs are immutable — recomputations create new runs.1314generator client {15 provider = "prisma-client-js"16}1718datasource db {19 provider = "postgresql"20 url = env("DATABASE_URL")21}2223model Occupation {24 code String @id // O*NET-SOC 2019, e.g. "15-1252.00"25 title String26 description String?27 // Crosswalks (METHODOLOGY.md §2); crosswalk loss flagged per occupation28 escoUri String?29 romeCode String?30 crosswalkNote String?31 // Wages as integer cents + ISO currency (CLAUDE.md §5)32 medianWageCents Int?33 wageCurrency String @default("USD")34 employment Int?3536 tasks Task[]37 scores OccupationScore[]38}3940model Task {41 id String @id // O*NET Task ID42 occupationCode String43 statement String44 /// O*NET Task Ratings importance (IM, 1–5)45 importance Float?4647 occupation Occupation @relation(fields: [occupationCode], references: [code])48 ratings TaskRating[]49 overrides ExpertOverride[]50 scores TaskScore[]5152 @@index([occupationCode])53}5455/// One LLM rating of one task on one dimension by one model — full audit56/// trail (CLAUDE.md §6): model, prompt version, raw response, parsed score.57model TaskRating {58 id String @id @default(cuid())59 taskId String60 /// DimensionKey from packages/scoring, or "augmentation"61 dimension String62 model String63 promptVersion String64 sampleIndex Int @default(0)65 rating Int // 1–566 rationale String?67 rawResponse Json68 ratedAt DateTime @default(now())6970 task Task @relation(fields: [taskId], references: [id])7172 @@unique([taskId, dimension, model, promptVersion, sampleIndex])73 @@index([taskId, dimension])74 @@index([promptVersion])75}7677/// Expert (Delphi) override: replaces the LLM rating band for a task ×78/// dimension. Flagged in API output (METHODOLOGY.md §3).79model ExpertOverride {80 id String @id @default(cuid())81 taskId String82 dimension String83 ratingLow Int84 ratingMid Float85 ratingHigh Int86 reviewer String87 note String?88 createdAt DateTime @default(now())8990 task Task @relation(fields: [taskId], references: [id])9192 @@unique([taskId, dimension])93}9495/// Immutable computation run. Old runs remain queryable forever.96model ScoreRun {97 id String @id @default(cuid())98 indexVersion String99 raterPromptVersion String100 raterModels String[]101 notes String?102 createdAt DateTime @default(now())103104 occupationScores OccupationScore[]105 taskScores TaskScore[]106107 @@index([indexVersion])108}109110model OccupationScore {111 id String @id @default(cuid())112 runId String113 occupationCode String114 substitutionLow Float115 substitution Float116 substitutionHigh Float117 exposureLow Float118 exposure Float119 exposureHigh Float120 augmentationLow Float121 augmentation Float122 augmentationHigh Float123 highlyExposedTaskShare Float124125 run ScoreRun @relation(fields: [runId], references: [id])126 occupation Occupation @relation(fields: [occupationCode], references: [code])127128 @@unique([runId, occupationCode])129 @@index([occupationCode])130}131132model TaskScore {133 id String @id @default(cuid())134 runId String135 taskId String136 substitutionLow Float137 substitution Float138 substitutionHigh Float139 exposureLow Float140 exposure Float141 exposureHigh Float142 augmentationLow Float143 augmentation Float144 augmentationHigh Float145146 run ScoreRun @relation(fields: [runId], references: [id])147 task Task @relation(fields: [taskId], references: [id])148149 @@unique([runId, taskId])150 @@index([taskId])151}152153model ApiKey {154 id String @id @default(cuid())155 hashedKey String @unique156 name String157 rateLimitPerMin Int @default(600)158 createdAt DateTime @default(now())159}160