schema-base-donnees.md 11551 octets

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.

TableRôle
usersComptes utilisateurs
roles / permissions / role_permissions / user_rolesRBAC global
resources / resource_sharesRegistre générique de ressources et partages
refresh_tokens / jwt_blacklistGestion JWT
app_settingsConfiguration applicative clé-valeur
audit_logsJournal d'audit
user_totp / totp_challengesAuthentification 2FA TOTP
email_queue / email_delivery_statusFile d'emails asynchrone
password_reset_tokens / password_change_requestsFlux de changement de mot de passe

Tables gitrust-core

repositories

ColonneType Rust (SeaORM)Contrainte PGNotes
idUuidPK
owner_idUuidFK → users ON DELETE CASCADE
slugStringVARCHAR(64) NOT NULLNewtype RepoSlug à la frontière
descriptionOption<String>VARCHAR(500) NULL
disk_pathStringVARCHAR(512) NOT NULLChemin absolu du bare repo
default_branchStringVARCHAR(255) NOT NULL DEFAULT 'main'
is_emptyboolBOOLEAN NOT NULL DEFAULT truePasse à false après le premier push
created_atDateTimeUtcTIMESTAMPTZ NOT NULL
updated_atDateTimeUtcTIMESTAMPTZ 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

ColonneType RustContrainte PGNotes
idUuidPK
user_idUuidFK → users CASCADE
titleStringVARCHAR(255) NOT NULL
fingerprintStringVARCHAR(128) UNIQUE NOT NULLSHA256, format SHA256:xxx
key_typeStringVARCHAR(32) NOT NULLssh-ed25519, ssh-rsa, ecdsa-sha2-nistp256/384
key_dataStringTEXT NOT NULLFormat authorized_keys complet
last_used_atOption<DateTimeUtc>TIMESTAMPTZ NULLMis à jour par le serveur SSH
created_atDateTimeUtcTIMESTAMPTZ NOT NULL

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

teams et team_members

ColonneType RustNotes
teams.slugStringNewtype TeamSlug ; UNIQUE(owner_id, slug)
team_members.roleString"read" (défaut), "write", "admin"
team_repository_access.permissionString"read", "write", "admin"

personal_access_tokens

ColonneType RustNotes
token_hashStringSHA-256 du token en clair. Le token en clair n'est retourné qu'à la création.
scopesStringEspace-séparé : "repo:read repo:write issues:write"
expires_atOption<DateTimeUtc>NULL = pas d'expiration

issues

ColonneType RustNotes
numberi32Auto-incrémenté par dépôt (pas global). UNIQUE(repository_id, number)
stateString"open" (défaut) ou "closed"
bodyStringMarkdown brut

labels

ColonneType RustNotes
label_typeString"classification" (scope owner) ou "subject" (scope repo)
owner_idOption<Uuid>Non-null pour classification, null pour subject
repository_idOption<Uuid>Non-null pour subject, null pour classification
colorStringHex #RRGGBB, validé à l'insertion

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

pull_requests

ColonneType RustNotes
numberi32Auto-incrémenté par dépôt. UNIQUE(repository_id, number)
stateString"open", "closed", "merged"
merge_commit_shaOption<String>SHA40, null avant merge

import_jobs

ColonneType RustNotes
statusStringState machine : pendingrunningsuccess/failed/cancelled
phaseOption<String>"cloning", "resolving", "finalizing"
repository_idOption<Uuid>Null pendant le clonage, rempli au succès uniquement

Ordre des migrations

#NomTables créées
1m20260305_000001_initial_schemausers, refresh_tokens, jwt_blacklist, audit_logs (core)
2m20260306_000002_create_app_settings_tableapp_settings (core)
3m20260309_000003_create_permissions_tablesroles, permissions, role_permissions, user_roles (core)
4m20260309_000004_create_resources_tablesresources, resource_shares (core)
5m20260310_000005_create_oauth_accounts_tableoauth_accounts (core)
6m20260325_000001_create_repositoriesrepositories
7m20260325_000002_create_ssh_keysssh_keys
8m20260325_000003_create_teamsteams
9m20260325_000004_create_team_membersteam_members
10m20260325_000005_create_team_repository_accessteam_repository_access
11m20260327_000006_create_personal_access_tokenspersonal_access_tokens
12m20260327_000007_create_issuesissues
13m20260327_000008_create_issue_commentsissue_comments
14m20260327_000009_create_labelslabels, issue_labels
15m20260327_000010_add_label_typeALTER labels (label_type)
16m20260327_000011_labels_owner_scopeALTER labels (owner_id, repository_id nullable)
17m20260327_000012_create_pull_requestspull_requests
18m20260327_000013_create_pr_commentspr_comments
19m20260409_000006_create_totp_tablesuser_totp, totp_challenges (core)
20+m20260416_000022_create_import_jobsimport_jobs

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

Voir aussi