Schéma de la base de données — Référence développeur

Ce document décrit le schéma complet de la base de données gitrust, orienté développeur : types SeaORM côté Rust, enums, contraintes de modèle, et ordre des migrations.

Pour la vue admin (sauvegardes, supervision), consultez le manuel d'administration.

ERD — Diagramme entité-relation

erDiagram
    %% ===== Tables rustwarden-core =====
    users {
        uuid id PK
        string username UK
        string email UK
        string password_hash
        boolean must_change_password
        boolean email_verified
        timestamptz last_login_at
        timestamptz created_at
        timestamptz updated_at
    }

    resources {
        uuid id PK
        string resource_type
        uuid resource_id
        uuid owner_id FK
        boolean is_public
        timestamptz created_at
    }

    resource_shares {
        uuid id PK
        uuid resource_id FK
        uuid shared_with_user_id FK
        string permission_level
        uuid shared_by_user_id FK
        timestamptz created_at
    }

    user_totp {
        uuid id PK
        uuid user_id FK
        text encrypted_secret
        boolean enabled
        text backup_codes_json
        timestamptz enabled_at
        timestamptz created_at
        timestamptz updated_at
    }

    %% ===== Tables gitrust-core =====
    repositories {
        uuid id PK
        uuid owner_id FK
        string slug
        string description
        string disk_path
        string default_branch
        boolean is_empty
        timestamptz created_at
        timestamptz updated_at
    }

    ssh_keys {
        uuid id PK
        uuid user_id FK
        string title
        string fingerprint UK
        string key_type
        text key_data
        timestamptz last_used_at
        timestamptz created_at
    }

    teams {
        uuid id PK
        uuid owner_id FK
        string slug
        string description
        timestamptz created_at
        timestamptz updated_at
    }

    team_members {
        uuid id PK
        uuid team_id FK
        uuid user_id FK
        string role
        timestamptz created_at
    }

    team_repository_access {
        uuid id PK
        uuid team_id FK
        uuid repository_id FK
        string permission
        timestamptz created_at
    }

    personal_access_tokens {
        uuid id PK
        uuid user_id FK
        string name
        string token_hash UK
        string scopes
        timestamptz expires_at
        timestamptz last_used_at
        timestamptz created_at
    }

    issues {
        uuid id PK
        uuid repository_id FK
        integer number
        uuid author_id FK
        string title
        text body
        string state
        uuid closed_by FK
        timestamptz created_at
        timestamptz updated_at
    }

    issue_comments {
        uuid id PK
        uuid issue_id FK
        uuid author_id FK
        text body
        timestamptz created_at
        timestamptz updated_at
    }

    labels {
        uuid id PK
        uuid owner_id FK
        uuid repository_id FK
        string name
        string color
        string description
        string label_type
        timestamptz created_at
    }

    issue_labels {
        uuid id PK
        uuid issue_id FK
        uuid label_id FK
        timestamptz created_at
    }

    pull_requests {
        uuid id PK
        uuid repository_id FK
        integer number
        uuid author_id FK
        string title
        text body
        string source_branch
        string target_branch
        string state
        timestamptz merged_at
        uuid merged_by FK
        string merge_commit_sha
        timestamptz created_at
        timestamptz updated_at
    }

    pr_comments {
        uuid id PK
        uuid pull_request_id FK
        uuid author_id FK
        text body
        timestamptz created_at
    }

    import_jobs {
        uuid id PK
        uuid repository_id FK
        uuid owner_id FK
        text source_url
        text target_slug
        string status
        string phase
        int received_objects
        int total_objects
        bigint received_bytes
        text error_message
        timestamptz started_at
        timestamptz finished_at
        int duration_ms
        timestamptz created_at
        timestamptz updated_at
    }

    %% Relations
    users ||--o{ repositories : "possède"
    users ||--o{ ssh_keys : "enregistre"
    users ||--o{ teams : "crée"
    users ||--o{ resources : "possède"
    users ||--o| user_totp : "configure"
    repositories ||--o| resources : "enregistre dans"
    resources ||--o{ resource_shares : "partage"
    teams ||--o{ team_members : "contient"
    teams ||--o{ team_repository_access : "accède à"
    repositories ||--o{ team_repository_access : "accessible par"
    repositories ||--o{ issues : "contient"
    issues ||--o{ issue_comments : "a"
    issues ||--o{ issue_labels : "étiquetée"
    labels ||--o{ issue_labels : "appliquée"
    repositories ||--o{ pull_requests : "contient"
    pull_requests ||--o{ pr_comments : "a"
    users ||--o{ personal_access_tokens : "crée"
    users ||--o{ import_jobs : "lance"

Tables rustwarden-core (framework — read-only pour gitrust)

Ces tables sont gérées exclusivement par le framework rustwarden-core. Ne les modifiez jamais directement depuis gitrust.

Table Rôle
users Comptes utilisateurs
roles / permissions / role_permissions / user_roles RBAC global
resources / resource_shares Registre générique de ressources et partages
refresh_tokens / jwt_blacklist Gestion JWT
app_settings Configuration applicative clé-valeur
audit_logs Journal d'audit
user_totp / totp_challenges Authentification 2FA TOTP
email_queue / email_delivery_status File d'emails asynchrone
password_reset_tokens / password_change_requests Flux de changement de mot de passe

Tables gitrust-core

repositories

Colonne Type Rust (SeaORM) Contrainte PG Notes
id Uuid PK
owner_id Uuid FK → users ON DELETE CASCADE
slug String VARCHAR(64) NOT NULL Newtype RepoSlug à la frontière
description Option<String> VARCHAR(500) NULL
disk_path String VARCHAR(512) NOT NULL Chemin absolu du bare repo
default_branch String VARCHAR(255) NOT NULL DEFAULT 'main'
is_empty bool BOOLEAN NOT NULL DEFAULT true Passe à false après le premier push
created_at DateTimeUtc TIMESTAMPTZ NOT NULL
updated_at DateTimeUtc TIMESTAMPTZ NOT NULL

Index : UNIQUE(owner_id, slug), INDEX(owner_id)

Lien ResourceService : chaque dépôt est enregistré dans resources avec resource_type = "repository" et resource_id = repositories.id.

ssh_keys

Colonne Type Rust Contrainte PG Notes
id Uuid PK
user_id Uuid FK → users CASCADE
title String VARCHAR(255) NOT NULL
fingerprint String VARCHAR(128) UNIQUE NOT NULL SHA256, format SHA256:xxx
key_type String VARCHAR(32) NOT NULL ssh-ed25519, ssh-rsa, ecdsa-sha2-nistp256/384
key_data String TEXT NOT NULL Format authorized_keys complet
last_used_at Option<DateTimeUtc> TIMESTAMPTZ NULL Mis à jour par le serveur SSH
created_at DateTimeUtc TIMESTAMPTZ NOT NULL

Validation : RSA ≥ 4096 bits obligatoire. Fingerprint calculé à l'insertion.

teams et team_members

Colonne Type Rust Notes
teams.slug String Newtype TeamSlug ; UNIQUE(owner_id, slug)
team_members.role String "read" (défaut), "write", "admin"
team_repository_access.permission String "read", "write", "admin"

personal_access_tokens

Colonne Type Rust Notes
token_hash String SHA-256 du token en clair. Le token en clair n'est retourné qu'à la création.
scopes String Espace-séparé : "repo:read repo:write issues:write"
expires_at Option<DateTimeUtc> NULL = pas d'expiration

issues

Colonne Type Rust Notes
number i32 Auto-incrémenté par dépôt (pas global). UNIQUE(repository_id, number)
state String "open" (défaut) ou "closed"
body String Markdown brut

labels

Colonne Type Rust Notes
label_type String "classification" (scope owner) ou "subject" (scope repo)
owner_id Option<Uuid> Non-null pour classification, null pour subject
repository_id Option<Uuid> Non-null pour subject, null pour classification
color String Hex #RRGGBB, validé à l'insertion

Index : UNIQUE(owner_id, repository_id, name, label_type)

pull_requests

Colonne Type Rust Notes
number i32 Auto-incrémenté par dépôt. UNIQUE(repository_id, number)
state String "open", "closed", "merged"
merge_commit_sha Option<String> SHA40, null avant merge

import_jobs

Colonne Type Rust Notes
status String State machine : pendingrunningsuccess/failed/cancelled
phase Option<String> "cloning", "resolving", "finalizing"
repository_id Option<Uuid> Null pendant le clonage, rempli au succès uniquement

Ordre des migrations

# Nom Tables créées
1 m20260305_000001_initial_schema users, refresh_tokens, jwt_blacklist, audit_logs (core)
2 m20260306_000002_create_app_settings_table app_settings (core)
3 m20260309_000003_create_permissions_tables roles, permissions, role_permissions, user_roles (core)
4 m20260309_000004_create_resources_tables resources, resource_shares (core)
5 m20260310_000005_create_oauth_accounts_table oauth_accounts (core)
6 m20260325_000001_create_repositories repositories
7 m20260325_000002_create_ssh_keys ssh_keys
8 m20260325_000003_create_teams teams
9 m20260325_000004_create_team_members team_members
10 m20260325_000005_create_team_repository_access team_repository_access
11 m20260327_000006_create_personal_access_tokens personal_access_tokens
12 m20260327_000007_create_issues issues
13 m20260327_000008_create_issue_comments issue_comments
14 m20260327_000009_create_labels labels, issue_labels
15 m20260327_000010_add_label_type ALTER labels (label_type)
16 m20260327_000011_labels_owner_scope ALTER labels (owner_id, repository_id nullable)
17 m20260327_000012_create_pull_requests pull_requests
18 m20260327_000013_create_pr_comments pr_comments
19 m20260409_000006_create_totp_tables user_totp, totp_challenges (core)
20+ m20260416_000022_create_import_jobs import_jobs

Toutes les migrations sont exécutées par AppMigrator (combine core + gitrust) dans gitrust_core::migrations::run_migrations().

Voir aussi