Schéma de la base de données

Référence des tables PostgreSQL de gitrust, avec colonnes, index, contraintes et relations. Cette page concerne les tables visibles par un administrateur — pour les détails internes du code (migrations SeaORM, patterns de contribution), voir le manuel développeur.


Diagramme entité-relation

erDiagram
    users {
        uuid id PK
        string username UK
        string email UK
        string password_hash
        boolean must_change_password
        timestamptz last_login_at
        boolean email_verified
        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
    }

    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
    }

    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
    }

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

    app_settings {
        uuid id PK
        string key UK
        text value
        text description
        uuid updated_by FK
        timestamptz updated_at
    }

    audit_log {
        uuid id PK
        uuid actor_id FK
        string action
        string resource_type
        uuid resource_id
        string ip_address
        text details
        timestamptz created_at
    }

    users ||--o{ repositories : "possède"
    users ||--o{ ssh_keys : "enregistre"
    users ||--o{ teams : "crée"
    users ||--o{ resources : "possède"
    users ||--o{ resource_shares : "partage avec"
    users ||--o{ personal_access_tokens : "crée"
    users ||--o{ audit_log : "acteur"
    repositories ||--o| resources : "enregistré dans"
    resources ||--o{ resource_shares : "partagé"
    teams ||--o{ team_members : "contient"
    users ||--o{ team_members : "membre de"
    teams ||--o{ team_repository_access : "accède à"
    repositories ||--o{ team_repository_access : "accessible par"
    repositories ||--o{ issues : "contient"
    repositories ||--o{ pull_requests : "contient"

Tables rustwarden-core (framework)

Ces tables sont gérées par le framework. Ne les modifiez pas directement.

Table Rôle
users Comptes utilisateurs (authentification, profil)
roles / permissions / role_permissions / user_roles RBAC global (admin, user)
resources Registre générique de ressources (ownership, visibilité publique/privée)
resource_shares Partage de ressources avec niveaux (read/write/admin)
refresh_tokens Refresh tokens JWT
jwt_blacklist Tokens JWT révoqués (invalidation après déconnexion)
app_settings Configuration dynamique de l'application
audit_log Journal d'audit de toutes les actions significatives
oauth_accounts Comptes OAuth liés

Tables gitrust

repositories

Dépôts Git hébergés sur la plateforme.

Colonne Type Contraintes Description
id UUID PK Identifiant unique
owner_id UUID FK → users.id CASCADE, NOT NULL Propriétaire du dépôt
slug VARCHAR(64) NOT NULL Nom URL du dépôt (ex. mon-projet)
description VARCHAR(500) NULL Description affichée dans l'UI
disk_path VARCHAR(512) NOT NULL Chemin absolu du bare repo sur disque
default_branch VARCHAR(255) NOT NULL, DEFAULT 'main' Branche par défaut
is_empty BOOLEAN NOT NULL, DEFAULT true Vrai si aucun commit poussé
created_at TIMESTAMPTZ NOT NULL Date de création
updated_at TIMESTAMPTZ NOT NULL Date de dernière modification

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

Chaque dépôt est aussi enregistré dans resources avec resource_type = "repository" pour gérer la visibilité (public/privé) et le partage via resource_shares.

ssh_keys

Clés publiques SSH des utilisateurs pour l'authentification Git.

Colonne Type Contraintes Description
id UUID PK Identifiant unique
user_id UUID FK → users.id CASCADE, NOT NULL Propriétaire de la clé
title VARCHAR(255) NOT NULL Libellé (ex. MacBook Pro)
fingerprint VARCHAR(128) UNIQUE, NOT NULL Fingerprint SHA256 calculé à l'insertion
key_type VARCHAR(32) NOT NULL Type : ssh-ed25519, ssh-rsa, ecdsa-*
key_data TEXT NOT NULL Clé au format authorized_keys
last_used_at TIMESTAMPTZ NULL Dernière utilisation SSH
created_at TIMESTAMPTZ NOT NULL Date d'ajout

Validation : types autorisés — Ed25519, RSA ≥ 4096 bits, ECDSA P-256/P-384.

teams

Groupes d'utilisateurs pour le partage d'accès aux dépôts.

Colonne Type Contraintes Description
id UUID PK Identifiant unique
owner_id UUID FK → users.id CASCADE, NOT NULL Créateur / administrateur de l'équipe
slug VARCHAR(64) NOT NULL Nom URL de l'équipe
description VARCHAR(500) NULL Description
created_at TIMESTAMPTZ NOT NULL Date de création
updated_at TIMESTAMPTZ NOT NULL Date de dernière modification

Index : UNIQUE(owner_id, slug)

team_members

Appartenance d'un utilisateur à une équipe avec un rôle.

Colonne Type Contraintes Description
id UUID PK Identifiant unique
team_id UUID FK → teams.id CASCADE, NOT NULL Équipe
user_id UUID FK → users.id CASCADE, NOT NULL Membre
role VARCHAR(20) NOT NULL, DEFAULT 'read' Rôle dans l'équipe
created_at TIMESTAMPTZ NOT NULL Date d'ajout

Index : UNIQUE(team_id, user_id), INDEX(user_id)

team_repository_access

Permissions d'accès d'une équipe sur un dépôt.

Colonne Type Contraintes Description
id UUID PK Identifiant unique
team_id UUID FK → teams.id CASCADE, NOT NULL Équipe
repository_id UUID FK → repositories.id CASCADE, NOT NULL Dépôt
permission VARCHAR(20) NOT NULL, DEFAULT 'read' Niveau : read, write, admin
created_at TIMESTAMPTZ NOT NULL Date d'attribution

Index : UNIQUE(team_id, repository_id), INDEX(repository_id)

personal_access_tokens

Jetons d'accès personnels pour l'authentification API et Git HTTPS.

Colonne Type Contraintes Description
id UUID PK Identifiant unique
user_id UUID FK → users.id CASCADE, NOT NULL Propriétaire du jeton
name VARCHAR(255) NOT NULL Nom descriptif (ex. CI pipeline)
token_hash VARCHAR(128) UNIQUE, NOT NULL Hash SHA-256 du jeton (le jeton brut n'est jamais stocké)
scopes VARCHAR(255) NOT NULL Portées autorisées (séparées par espace)
expires_at TIMESTAMPTZ NULL Expiration (NULL = sans expiration)
last_used_at TIMESTAMPTZ NULL Dernière utilisation
created_at TIMESTAMPTZ NOT NULL Date de création

issues

Tickets de suivi (bugs, tâches, demandes de fonctionnalité).

Colonne Type Contraintes Description
id UUID PK Identifiant unique
repository_id UUID FK → repositories.id CASCADE Dépôt propriétaire
number INTEGER NOT NULL (auto-incrémenté par dépôt) Numéro affiché (#1, #2…)
author_id UUID FK → users.id CASCADE Auteur
title VARCHAR(255) NOT NULL Titre
body TEXT NOT NULL DEFAULT '' Corps (Markdown)
state VARCHAR(20) NOT NULL DEFAULT 'open' État : open, closed
closed_by UUID FK → users.id NULL Utilisateur qui a fermé l'issue
created_at TIMESTAMPTZ NOT NULL Date de création
updated_at TIMESTAMPTZ NOT NULL Date de dernière modification

Index : UNIQUE(repository_id, number), INDEX(repository_id, state)

pull_requests

Propositions de merge d'une branche source vers une branche cible.

Colonne Type Contraintes Description
id UUID PK Identifiant unique
repository_id UUID FK → repositories.id CASCADE Dépôt
number INTEGER NOT NULL (auto-incrémenté par dépôt) Numéro affiché
author_id UUID FK → users.id CASCADE Auteur
title VARCHAR(255) NOT NULL Titre
body TEXT NOT NULL DEFAULT '' Description
source_branch VARCHAR(255) NOT NULL Branche source
target_branch VARCHAR(255) NOT NULL Branche cible (ex. main)
state VARCHAR(20) NOT NULL DEFAULT 'open' État : open, merged, closed
merged_at TIMESTAMPTZ NULL Date de merge
merged_by UUID FK → users.id NULL Utilisateur qui a mergé
merge_commit_sha VARCHAR(40) NULL SHA du commit de merge
created_at TIMESTAMPTZ NOT NULL Date de création
updated_at TIMESTAMPTZ NOT NULL Date de dernière modification

Index : UNIQUE(repository_id, number), INDEX(repository_id, state)

labels

Étiquettes à deux niveaux : classification (scope owner) et subject (scope dépôt).

Colonne Type Contraintes Description
id UUID PK Identifiant unique
owner_id UUID FK → users.id NULL Propriétaire (labels de classification)
repository_id UUID FK → repositories.id NULL Dépôt (labels de sujet)
name VARCHAR(50) NOT NULL Nom du label
color VARCHAR(7) NOT NULL Couleur hexadécimale (ex. #e11d48)
description VARCHAR(255) NULL Description
label_type VARCHAR(20) NOT NULL 'classification' ou 'subject'
created_at TIMESTAMPTZ NOT NULL Date de création

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

app_settings

Configuration dynamique de l'application (modifiable à chaud via /admin/settings).

Colonne Type Contraintes Description
id UUID PK Identifiant unique
key VARCHAR(100) UNIQUE, NOT NULL Clé de configuration (ex. allow_registration)
value TEXT NOT NULL Valeur sous forme de texte
description TEXT NULL Description affichée dans l'UI admin
updated_by UUID FK → users.id ON DELETE SET NULL Dernier administrateur ayant modifié
updated_at TIMESTAMPTZ NOT NULL Date de dernière modification

audit_log

Journal d'audit de toutes les actions significatives.

Colonne Type Contraintes Description
id UUID PK Identifiant unique
actor_id UUID FK → users.id NULL Utilisateur auteur de l'action
action VARCHAR(50) NOT NULL Type d'action (create, update, delete, reset_password…)
resource_type VARCHAR(50) NULL Type de ressource concernée
resource_id UUID NULL Identifiant de la ressource
ip_address VARCHAR(45) NULL Adresse IP source
details TEXT NULL Détails supplémentaires (JSON)
created_at TIMESTAMPTZ NOT NULL Horodatage

Modèle de permissions

graph TB
    subgraph "Accès individuel"
        Owner["Owner (resources.owner_id)"]
        Share["resource_shares (read/write/admin)"]
        Public["Accès public (resources.is_public)"]
    end

    subgraph "Accès équipe"
        TM["team_members (rôle dans l'équipe)"]
        TRA["team_repository_access (permission sur le dépôt)"]
    end

    subgraph "Rôle effectif"
        Eff["max(individuel, équipe)"]
    end

    Owner -->|"Owner (full)"| Eff
    Share -->|"read/write/admin"| Eff
    Public -->|"read only"| Eff
    TM --> TRA
    TRA -->|"read/write/admin"| Eff
Rôle Permissions
Reader Clone, navigation (lecture seule)
Developer Reader + push
Maintainer Developer + paramètres, collaborateurs, protections de branche
Owner Maintainer + suppression, transfert

Ordre des migrations

# Migration Tables créées
1 m20260305_000001_initial_schema users, refresh_tokens, jwt_blacklist… (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
16 m20260327_000011_labels_owner_scope alter labels
17 m20260327_000012_create_pull_requests pull_requests
18 m20260327_000013_create_pr_comments pr_comments

Toutes les migrations sont appliquées automatiquement au démarrage par AppMigrator. Elles sont idempotentes.


Pour aller plus loin