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.
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"
Ces tables sont gérées exclusivement par le framework rustwarden-core. Ne les modifiez jamais directement depuis gitrust.
Table Rô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
Colonne Type Rust (SeaORM) Contrainte PG Notes
idUuidPK
owner_idUuidFK → users ON DELETE CASCADE
slugStringVARCHAR(64) NOT NULL Newtype RepoSlug à la frontière
descriptionOption<String>VARCHAR(500) NULL
disk_pathStringVARCHAR(512) NOT NULL Chemin absolu du bare repo
default_branchStringVARCHAR(255) NOT NULL DEFAULT ‘main’
is_emptyboolBOOLEAN NOT NULL DEFAULT true Passe à 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.
Colonne Type Rust Contrainte PG Notes
idUuidPK
user_idUuidFK → users CASCADE
titleStringVARCHAR(255) NOT NULL
fingerprintStringVARCHAR(128) UNIQUE NOT NULL SHA256, format SHA256:xxx
key_typeStringVARCHAR(32) NOT NULL ssh-ed25519, ssh-rsa, ecdsa-sha2-nistp256/384
key_dataStringTEXT NOT NULL Format authorized_keys complet
last_used_atOption<DateTimeUtc>TIMESTAMPTZ NULL Mis à jour par le serveur SSH
created_atDateTimeUtcTIMESTAMPTZ NOT NULL
Validation : RSA ≥ 4096 bits obligatoire. Fingerprint calculé à l’insertion.
Colonne Type Rust Notes
teams.slugStringNewtype TeamSlug ; UNIQUE(owner_id, slug)
team_members.roleString"read" (défaut), "write", "admin"
team_repository_access.permissionString"read", "write", "admin"
Colonne Type Rust Notes
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
Colonne Type Rust Notes
numberi32Auto-incrémenté par dépôt (pas global). UNIQUE(repository_id, number)
stateString"open" (défaut) ou "closed"
bodyStringMarkdown brut
Colonne Type Rust Notes
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)
Colonne Type Rust Notes
numberi32Auto-incrémenté par dépôt. UNIQUE(repository_id, number)
stateString"open", "closed", "merged"
merge_commit_shaOption<String>SHA40, null avant merge
Colonne Type Rust Notes
statusStringState machine : pending → running → success/failed/cancelled
phaseOption<String>"cloning", "resolving", "finalizing"
repository_idOption<Uuid>Null pendant le clonage, rempli au succès uniquement
# Nom Tables créées
1 m20260305_000001_initial_schemausers, refresh_tokens, jwt_blacklist, audit_logs (core)
2 m20260306_000002_create_app_settings_tableapp_settings (core)
3 m20260309_000003_create_permissions_tablesroles, permissions, role_permissions, user_roles (core)
4 m20260309_000004_create_resources_tablesresources, resource_shares (core)
5 m20260310_000005_create_oauth_accounts_tableoauth_accounts (core)
6 m20260325_000001_create_repositoriesrepositories
7 m20260325_000002_create_ssh_keysssh_keys
8 m20260325_000003_create_teamsteams
9 m20260325_000004_create_team_membersteam_members
10 m20260325_000005_create_team_repository_accessteam_repository_access
11 m20260327_000006_create_personal_access_tokenspersonal_access_tokens
12 m20260327_000007_create_issuesissues
13 m20260327_000008_create_issue_commentsissue_comments
14 m20260327_000009_create_labelslabels , issue_labels
15 m20260327_000010_add_label_typeALTER labels (label_type)
16 m20260327_000011_labels_owner_scopeALTER labels (owner_id, repository_id nullable)
17 m20260327_000012_create_pull_requestspull_requests
18 m20260327_000013_create_pr_commentspr_comments
19 m20260409_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().