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.