-
-
Notifications
You must be signed in to change notification settings - Fork 0
Data Model
The Research Platform uses a comprehensive relational database schema built with Prisma ORM. The schema consists of 30+ models covering all aspects of research center operations, from user management to scientific data collection.
- Database: PostgreSQL 14+
- ORM: Prisma 5.19.0
- Geospatial Extension: PostGIS (for geographic data)
-
Schema Location:
prisma/schema.prisma
The database schema is organized into logical domains:
- User Management & Sessions
- Human Resources
- Finance & Accounting
- Equipment & Logistics
- Missions & Field Campaigns
- Scientific Database (Species)
- Environmental Data
- GIS & Cartography
- Document Management
- Publication & Editing
- Audit & Security
- Notifications
Purpose: User accounts and authentication
Key Fields:
-
id: Unique identifier (CUID) -
email: Unique email address -
password: Hashed password (bcrypt) -
firstName,lastName: User name -
role: UserRole enum (15 predefined roles) -
isActive: Account status
Relationships:
- One-to-many:
sessions,loginLogs,permissions - One-to-one:
employee(optional) - One-to-many:
createdMissions,missionTeams,documents,auditLogs,notifications
Indexes:
-
email(unique) - Implicit indexes on foreign keys
Purpose: Active user sessions (JWT-based)
Key Fields:
-
id: Unique identifier -
sessionToken: Unique session token -
userId: Foreign key to User -
expires: Session expiration date
Relationships:
- Many-to-one:
user
Purpose: Login attempt history for security auditing
Key Fields:
-
id: Unique identifier -
userId: Foreign key to User -
ipAddress: Client IP address -
userAgent: Browser user agent -
success: Login success status -
timestamp: Login attempt time
Indexes:
userIdtimestamp
Purpose: Granular permissions per module
Key Fields:
-
id: Unique identifier -
userId: Foreign key to User -
module: Module name (string) -
permission: Permission enum (READ, WRITE, VALIDATE, DELETE, ADMIN)
Constraints:
- Unique on
[userId, module, permission]
Purpose: Employee records and HR management
Key Fields:
-
id: Unique identifier -
userId: Optional foreign key to User (linked account) -
employeeNumber: Unique employee number -
hireDate: Employment start date -
contractType: Contract type (CDI, CDD, Stage, etc.) -
contractStart,contractEnd: Contract dates -
baseSalary: Base salary (Decimal) -
isActive: Employment status
Relationships:
- One-to-one:
user(optional) - One-to-many:
salaries,bonuses,leaves,evaluations,missionAssignments
Purpose: Monthly salary payments
Key Fields:
-
id: Unique identifier -
employeeId: Foreign key to Employee -
amount: Salary amount (Decimal) -
month,year: Payment period -
paidAt: Payment date (optional)
Constraints:
- Unique on
[employeeId, month, year]
Purpose: Additional compensation (terrain, mer, risques)
Key Fields:
-
id: Unique identifier -
employeeId: Foreign key to Employee -
type: Bonus type (terrain, mer, risques) -
amount: Bonus amount (Decimal) -
month,year: Payment period -
reason: Optional reason
Purpose: Leave requests and management
Key Fields:
-
id: Unique identifier -
employeeId: Foreign key to Employee -
type: Leave type (congé, maladie, etc.) -
startDate,endDate: Leave period -
status: Approval status (pending, approved, rejected) -
reason: Optional reason
Purpose: Employee performance evaluations
Key Fields:
-
id: Unique identifier -
employeeId: Foreign key to Employee -
evaluatorId: Evaluator user ID -
period: Evaluation period (Q1, Q2, Q3, Q4, Annual) -
year: Evaluation year -
score: Performance score (1-10, optional) -
comments: Evaluation comments
Purpose: Annual budget planning
Key Fields:
-
id: Unique identifier -
year: Budget year (unique) -
totalAmount: Total budget (Decimal) -
description: Optional description
Relationships:
- One-to-many:
allocations,expenses
Purpose: Budget category allocations
Key Fields:
-
id: Unique identifier -
budgetId: Foreign key to Budget -
category: Allocation category -
amount: Allocated amount (Decimal) -
description: Optional description
Purpose: Research grants and funding
Key Fields:
-
id: Unique identifier -
name: Grant name -
provider: Grant provider -
amount: Grant amount (Decimal) -
startDate,endDate: Grant period -
status: Grant status (active, completed, cancelled)
Relationships:
- One-to-many:
expenses
Purpose: Financial expense tracking
Key Fields:
-
id: Unique identifier -
budgetId: Optional foreign key to Budget -
grantId: Optional foreign key to Grant -
projectId: Optional foreign key to Project -
category: Expense category -
amount: Expense amount (Decimal) -
description: Expense description -
date: Expense date -
invoiceId: Optional foreign key to Invoice
Relationships:
- Many-to-one:
budget,grant,project,invoice
Indexes:
-
budgetId,grantId,projectId,date
Purpose: Supplier invoice management
Key Fields:
-
id: Unique identifier -
number: Unique invoice number -
supplierId: Optional foreign key to Supplier -
amount: Invoice amount (Decimal) -
date: Invoice date -
dueDate: Payment due date -
status: Payment status (pending, paid, overdue) -
fileUrl: Optional file URL
Relationships:
- Many-to-one:
supplier - One-to-many:
expenses,payments
Purpose: Invoice payment records
Key Fields:
-
id: Unique identifier -
invoiceId: Foreign key to Invoice -
amount: Payment amount (Decimal) -
date: Payment date -
method: Payment method (bank transfer, check, cash) -
reference: Optional payment reference
Purpose: Supplier/vendor information
Key Fields:
-
id: Unique identifier -
name: Supplier name -
contact: Contact person -
email,phone: Contact information -
address: Physical address
Relationships:
- One-to-many:
invoices
Purpose: Research projects
Key Fields:
-
id: Unique identifier -
name: Project name -
description: Project description -
startDate,endDate: Project period -
status: Project status (active, completed, cancelled) -
budget: Project budget (Decimal, optional)
Relationships:
- One-to-many:
expenses
Purpose: Equipment inventory management
Key Fields:
-
id: Unique identifier -
name: Equipment name -
category: EquipmentCategory enum (VEHICULE, BATEAU, EQUIPEMENT_SCIENTIFIQUE, INFORMATIQUE, CAMPING_TERRAIN, LABORATOIRE) -
serialNumber: Optional unique serial number -
purchaseDate: Purchase date (optional) -
purchasePrice: Purchase price (Decimal, optional) -
lifespan: Expected lifespan in years (optional) -
status: EquipmentStatus enum (AVAILABLE, IN_USE, MAINTENANCE, RETIRED) -
location: Current location -
description: Optional description
Relationships:
- One-to-many:
maintenances,missionEquipment
Indexes:
-
category,status -
serialNumber(unique)
Purpose: Equipment maintenance records
Key Fields:
-
id: Unique identifier -
equipmentId: Foreign key to Equipment -
type: Maintenance type (preventive, corrective) -
description: Maintenance description -
cost: Maintenance cost (Decimal, optional) -
date: Maintenance date -
nextDueDate: Next maintenance due date (optional)
Purpose: Field research missions
Key Fields:
-
id: Unique identifier -
title: Mission title -
description: Mission description -
creatorId: Foreign key to User (mission creator) -
startDate,endDate: Mission period -
location: Mission location (text) -
latitude,longitude: GPS coordinates (optional) -
objectives: Mission objectives -
status: Mission status (planned, in_progress, completed, cancelled)
Relationships:
- Many-to-one:
creator - One-to-many:
teams,equipment,documents,speciesObservations - One-to-one:
report
Indexes:
-
creatorId,status,startDate
Purpose: Team member assignments
Key Fields:
-
id: Unique identifier -
missionId: Foreign key to Mission -
userId: Foreign key to User -
employeeId: Optional foreign key to Employee -
role: Team member role
Constraints:
- Unique on
[missionId, userId]
Purpose: Equipment assignments to missions
Key Fields:
-
id: Unique identifier -
missionId: Foreign key to Mission -
equipmentId: Foreign key to Equipment -
quantity: Quantity assigned (default: 1)
Constraints:
- Unique on
[missionId, equipmentId]
Purpose: Post-mission reports
Key Fields:
-
id: Unique identifier -
missionId: Foreign key to Mission (unique, one report per mission) -
content: Report content (Markdown or HTML) -
summary: Report summary -
findings: Key findings -
recommendations: Recommendations
Purpose: Species catalog
Key Fields:
-
id: Unique identifier -
scientificName: Scientific name -
commonName: Common name (optional) -
type: SpeciesType enum (FLORE_TERRESTRE, FAUNE_TERRESTRE, FAUNE_MARINE, ESPECE_EAU_DOUCE) -
iucnStatus: IUCNStatus enum (LC, NT, VU, EN, CR, EW, EX, DD, NE, optional) -
habitat: Habitat description -
description: Species description
Relationships:
- One-to-many:
observations,locations,photos,references
Indexes:
-
scientificName,type,iucnStatus
Purpose: Field observations of species
Key Fields:
-
id: Unique identifier -
speciesId: Foreign key to Species -
date: Observation date -
location: Location description -
latitude,longitude: GPS coordinates (optional) -
quantity: Observed quantity (optional) -
notes: Observation notes -
observerId: Observer user ID (optional) -
missionId: Optional foreign key to Mission
Relationships:
- Many-to-one:
species,mission
Indexes:
-
speciesId,date
Purpose: Geographic distribution of species
Key Fields:
-
id: Unique identifier -
speciesId: Foreign key to Species -
latitude,longitude: GPS coordinates -
location: Location description -
observedAt: Observation date -
observerId: Observer user ID (optional) -
notes: Optional notes
Indexes:
speciesId- Composite index on
[latitude, longitude]for spatial queries
Purpose: Species photographs
Key Fields:
-
id: Unique identifier -
speciesId: Foreign key to Species -
url: Photo URL -
caption: Photo caption (optional) -
takenAt: Photo date (optional)
Purpose: Scientific references for species
Key Fields:
-
id: Unique identifier -
speciesId: Foreign key to Species -
title: Reference title -
authors: Authors (optional) -
journal: Journal name (optional) -
year: Publication year (optional) -
url: Reference URL (optional)
Purpose: Water quality measurements
Key Fields:
-
id: Unique identifier -
type: WaterType enum (MER, SOURCE, BARRAGE) -
location: Measurement location -
latitude,longitude: GPS coordinates (optional) -
date: Measurement date -
ph: pH value (optional) -
temperature: Temperature (optional) -
dissolvedO2: Dissolved oxygen (optional) -
turbidity: Turbidity (optional) -
salinity: Salinity (optional) -
notes: Optional notes
Indexes:
-
type,date - Composite index on
[latitude, longitude]
Purpose: Air quality measurements
Key Fields:
-
id: Unique identifier -
location: Measurement location -
latitude,longitude: GPS coordinates (optional) -
date: Measurement date -
pm25,pm10: Particulate matter (optional) -
no2: Nitrogen dioxide (optional) -
o3: Ozone (optional) -
co: Carbon monoxide (optional) -
notes: Optional notes
Indexes:
date- Composite index on
[latitude, longitude]
Purpose: Climate/weather data
Key Fields:
-
id: Unique identifier -
stationId: Weather station ID (optional) -
location: Station location -
latitude,longitude: GPS coordinates (optional) -
date: Measurement date -
temperature: Temperature (optional) -
humidity: Humidity (optional) -
pressure: Atmospheric pressure (optional) -
windSpeed: Wind speed (optional) -
windDirection: Wind direction (optional) -
precipitation: Precipitation (optional) -
notes: Optional notes
Indexes:
date- Composite index on
[latitude, longitude]
Purpose: Geological and soil data
Key Fields:
-
id: Unique identifier -
location: Sample location -
latitude,longitude: GPS coordinates (optional) -
date: Sample date -
soilType: Soil type (optional) -
rockType: Rock type (optional) -
composition: Composition (optional) -
notes: Optional notes
Indexes:
date- Composite index on
[latitude, longitude]
Purpose: IoT sensor readings
Key Fields:
-
id: Unique identifier -
sensorId: Sensor identifier -
sensorType: Sensor type -
location: Sensor location (optional) -
latitude,longitude: GPS coordinates (optional) -
timestamp: Measurement timestamp -
value: Sensor value (Float) -
unit: Measurement unit (optional) -
metadata: Additional metadata (JSON, optional)
Indexes:
-
sensorId,timestamp
Purpose: Map layer definitions
Key Fields:
-
id: Unique identifier -
name: Layer name -
type: LayerType enum (HABITAT, SPECIES, STATION_METEO, POINT_EAU, GEOLOGIE, MISSION) -
description: Layer description -
geojson: GeoJSON data (optional, stored as string) -
style: Style configuration (JSON, optional) -
isVisible: Visibility flag
Indexes:
type
Purpose: Document records with versioning
Key Fields:
-
id: Unique identifier -
title: Document title -
type: DocumentType enum (RAPPORT_SCIENTIFIQUE, RAPPORT_ADMINISTRATIF, DONNEE_BRUTE, PUBLICATION, AUTRE) -
description: Document description -
fileUrl: File URL -
fileName: File name -
fileSize: File size in bytes (optional) -
mimeType: MIME type (optional) -
version: Version number (default: 1) -
parentId: Parent document ID for versioning (optional) -
authorId: Foreign key to User (document author) -
missionId: Optional foreign key to Mission -
isPublic: Public access flag
Relationships:
- Many-to-one:
author,mission,parent(for versioning) - One-to-many:
versions(child versions)
Indexes:
-
type,authorId,missionId
Purpose: Scientific publications and annual books
Key Fields:
-
id: Unique identifier -
title: Publication title -
year: Publication year -
type: Publication type (livre_annuel, article, rapport) -
content: Publication content (Markdown or HTML, optional) -
coverImage: Cover image URL (optional) -
isPublished: Publication status -
publishedAt: Publication date (optional)
Relationships:
- One-to-many:
chapters
Purpose: Publication chapters
Key Fields:
-
id: Unique identifier -
publicationId: Foreign key to Publication -
title: Chapter title -
order: Chapter order -
content: Chapter content (Markdown or HTML, optional)
Indexes:
publicationId
Purpose: Audit trail for all critical actions
Key Fields:
-
id: Unique identifier -
userId: Foreign key to User (optional, for system actions) -
action: Action type (CREATE, UPDATE, DELETE, etc.) -
entity: Entity type (Mission, Species, etc.) -
entityId: Entity identifier (optional) -
changes: Change details (JSON, optional) -
ipAddress: Client IP address (optional) -
userAgent: Browser user agent (optional) -
timestamp: Action timestamp
Indexes:
userId- Composite index on
[entity, entityId] timestamp
Purpose: User notifications
Key Fields:
-
id: Unique identifier -
userId: Foreign key to User -
type: Notification type (success, error, info, warning) -
title: Notification title -
message: Notification message (optional) -
link: Optional link URL -
read: Read status (default: false) -
readAt: Read timestamp (optional) -
createdAt: Creation timestamp
Relationships:
- Many-to-one:
user
Indexes:
-
userId,read,createdAt
15 predefined roles:
DIRECTEUR_SCIENTIFIQUEDIRECTEUR_ADMINISTRATIF_FINANCIERBOTANISTEZOOLOGISTE_TERRESTREBIOLOGISTE_MARINHYDROBIOLOGISTEGEOLOGUECLIMATOLOGUEDATA_SCIENTIST_SIGINGENIEUR_PLATEFORMESTECHNICIEN_LABORATOIRETECHNICIEN_TERRAINMARIN_PILOTE_BATEAULOGISTICIENCOMMUNICATION_EDITION
READWRITEVALIDATEDELETEADMIN
VEHICULEBATEAUEQUIPEMENT_SCIENTIFIQUEINFORMATIQUECAMPING_TERRAINLABORATOIRE
AVAILABLEIN_USEMAINTENANCERETIRED
FLORE_TERRESTREFAUNE_TERRESTREFAUNE_MARINEESPECE_EAU_DOUCE
-
LC(Least Concern) -
NT(Near Threatened) -
VU(Vulnerable) -
EN(Endangered) -
CR(Critically Endangered) -
EW(Extinct in the Wild) -
EX(Extinct) -
DD(Data Deficient) -
NE(Not Evaluated)
MERSOURCEBARRAGE
HABITATSPECIESSTATION_METEOPOINT_EAUGEOLOGIEMISSION
RAPPORT_SCIENTIFIQUERAPPORT_ADMINISTRATIFDONNEE_BRUTEPUBLICATIONAUTRE
The schema is designed to support PostGIS for geospatial queries, though full integration is pending:
-
Coordinates:
latitudeandlongitudefields stored asFloat -
Future Enhancement: Convert to PostGIS
Pointgeometry type -
Spatial Indexes: Composite indexes on
[latitude, longitude]for efficient queries - Use Cases: Species locations, mission locations, monitoring stations, sensor locations
All location-based entities include:
-
latitude: Float (optional) -
longitude: Float (optional) -
location: String (text description)
Entities with Geographic Data:
- Mission
- SpeciesObservation
- SpeciesLocation
- WaterQuality
- AirQuality
- ClimateData
- GeologyData
- SensorData
- User → Sessions, LoginLogs, Permissions, Missions (creator), Documents, AuditLogs, Notifications
- Employee → Salaries, Bonuses, Leaves, Evaluations, MissionAssignments
- Budget → Allocations, Expenses
- Grant → Expenses
- Project → Expenses
- Equipment → Maintenances, MissionEquipment
- Mission → Teams, Equipment, Documents, SpeciesObservations, Report
- Species → Observations, Locations, Photos, References
- Publication → Chapters
- Supplier → Invoices
- Invoice → Expenses, Payments
- User ↔ Employee (optional)
- Mission ↔ MissionReport
- Mission ↔ User (via MissionTeam)
- Mission ↔ Equipment (via MissionEquipment)
- All models have
idas primary key (CUID)
- User.email
- Employee.employeeNumber
- Equipment.serialNumber
- Budget.year
- Invoice.number
- MissionTeam:
[missionId, userId] - MissionEquipment:
[missionId, equipmentId] - UserPermission:
[userId, module, permission] - Salary:
[employeeId, month, year]
- Foreign keys (automatic)
- Frequently queried fields (status, dates, categories)
- Composite indexes for spatial queries (
[latitude, longitude]) - Time-based indexes (
timestamp,date,createdAt)
- CUID: Used for all primary keys (Prisma default)
- String: For unique identifiers like email, employeeNumber
-
Decimal: For monetary values (salaries, expenses, budgets) -
@db.Decimal(10, 2)or@db.Decimal(12, 2) - Float: For measurements (coordinates, sensor values, environmental data)
- Int: For counts, years, months, quantities
- String: For names, descriptions, text fields
- String?: Optional text fields
- DateTime: For timestamps, dates
- DateTime?: Optional dates
- Boolean: For flags (isActive, isPublic, read, etc.)
- String?: Stored as JSON string (for metadata, style configurations)
- Schema defined in
prisma/schema.prisma - Migrations generated with
prisma migrate dev - Schema pushed directly with
prisma db push(development) - Migration history tracked in
prisma/migrations/
- Seed script:
prisma/seed.ts - Generates realistic sample data
- Run with:
npm run db:seed
This data model provides a comprehensive foundation for all research center operations, with clear relationships, proper indexing, and support for future enhancements like PostGIS integration.
Last Updated: January 2025