Nginx config, working deploy, basic theme, repo cleanup

This commit is contained in:
Théophile Gervreau-Mercier
2026-02-05 17:33:10 +01:00
parent 2cb5436647
commit f23fbb481b
30 changed files with 4536 additions and 760 deletions

View File

@@ -0,0 +1,887 @@
# Post-ERG Database Specification
Complete technical specification of the Post-ERG thesis database schema.
**Version:** 1.0
**Database:** SQLite
**Last Updated:** February 5, 2026
---
## 📋 Table of Contents
1. [Overview](#overview)
2. [Entity Relationship Diagram](#entity-relationship-diagram)
3. [Core Tables](#core-tables)
4. [Lookup Tables](#lookup-tables)
5. [Junction Tables](#junction-tables)
6. [Support Tables](#support-tables)
7. [Views](#views)
8. [Indexes](#indexes)
9. [Triggers](#triggers)
10. [Data Types Reference](#data-types-reference)
11. [Business Rules](#business-rules)
12. [Sample Queries](#sample-queries)
---
## Overview
### Purpose
Database for managing and publishing ERG final thesis projects (TFE - Travaux de Fin d'Études) and doctoral theses.
### Key Features
- Multi-author thesis support
- Multiple supervisors per thesis
- Flexible format types (web, audio, video, print, etc.)
- Access control (public, internal, restricted)
- File attachment management
- Keyword tagging system
- Full-text search capability
- Academic metadata tracking
### Database Size Estimates
- **Expected records**: 100-500 theses/year
- **Growth rate**: ~10-15% annually
- **Average record size**: ~5KB (metadata only)
- **File storage**: External (linked via file paths)
---
## Entity Relationship Diagram
```
┌─────────────┐ ┌──────────────────┐ ┌─────────────┐
│ authors │◄──────│ thesis_authors │──────►│ theses │
└─────────────┘ 1:N └──────────────────┘ N:1 └─────────────┘
┌─────────────┐ ┌──────────────────┐ │
│supervisors │◄──────│thesis_supervisors│──────────────┘
└─────────────┘ 1:N └──────────────────┘ N:1
┌─────────────┐ ┌──────────────────┐
│ keywords │◄──────│ thesis_keywords │──────────────┐
└─────────────┘ 1:N └──────────────────┘ N:1 │
┌─────────────┐ ┌──────────────────┐ │
│ languages │◄──────│ thesis_languages │──────────────┤
└─────────────┘ 1:N └──────────────────┘ N:1 │
┌─────────────┐ ┌──────────────────┐ │
│format_types │◄──────│ thesis_formats │──────────────┤
└─────────────┘ 1:N └──────────────────┘ N:1 │
┌─────────────┐ │
│orientations │──────────────────────────────────────────┤
└─────────────┘ 1:N N:1 │
┌─────────────┐ │
│ ap_programs │──────────────────────────────────────────┤
└─────────────┘ 1:N N:1 │
┌─────────────┐ │
│finality_types│─────────────────────────────────────────┤
└─────────────┘ 1:N N:1 │
┌─────────────┐ │
│access_types │──────────────────────────────────────────┤
└─────────────┘ 1:N N:1 │
┌─────────────┐ │
│license_types│──────────────────────────────────────────┤
└─────────────┘ 1:N N:1 │
┌─────────────┐ │
│thesis_files │──────────────────────────────────────────┘
└─────────────┘ N:1
```
---
## Core Tables
### `theses`
**Purpose:** Main table storing thesis/dissertation information.
| Column | Type | Null | Default | Description |
|--------|------|------|---------|-------------|
| `id` | INTEGER | NO | AUTOINCREMENT | Primary key |
| `identifier` | TEXT | YES | NULL | Unique identifier (e.g., "2025-002") |
| `title` | TEXT | NO | - | Thesis title |
| `subtitle` | TEXT | YES | NULL | Optional subtitle |
| `year` | INTEGER | NO | - | Academic year of submission |
| `is_doctoral` | BOOLEAN | NO | 0 | 0 = TFE (Master), 1 = Doctoral thesis |
| `orientation_id` | INTEGER | YES | NULL | FK to `orientations` |
| `ap_program_id` | INTEGER | YES | NULL | FK to `ap_programs` (Ateliers Pratiques) |
| `finality_id` | INTEGER | YES | NULL | FK to `finality_types` |
| `synopsis` | TEXT | YES | NULL | ~200 word summary |
| `context_note` | TEXT | YES | NULL | Note by jury president (max 150 words) |
| `remarks` | TEXT | YES | NULL | Internal administrative remarks |
| `duration_minutes` | INTEGER | YES | NULL | For audio/video works |
| `duration_pages` | INTEGER | YES | NULL | For written works |
| `file_size_info` | TEXT | YES | NULL | Human-readable size (e.g., "128 pages + 45 minutes") |
| `access_type_id` | INTEGER | YES | NULL | FK to `access_types` |
| `license_id` | INTEGER | YES | NULL | FK to `license_types` |
| `jury_points` | DECIMAL(4,2) | YES | NULL | Grade out of 20 |
| `jury_note_added` | BOOLEAN | NO | 0 | Whether jury added a context note |
| `submitted_at` | DATETIME | YES | NULL | Student submission timestamp |
| `defense_date` | DATETIME | YES | NULL | Date of thesis defense |
| `published_at` | DATETIME | YES | NULL | Public publication timestamp |
| `is_published` | BOOLEAN | NO | 0 | Publication status |
| `baiu_link` | TEXT | YES | NULL | Link to institutional repository (BAIU) |
| `created_at` | DATETIME | NO | CURRENT_TIMESTAMP | Record creation time |
| `updated_at` | DATETIME | NO | CURRENT_TIMESTAMP | Last update time |
**Indexes:**
- `idx_theses_year` ON `year`
- `idx_theses_published` ON `is_published`
- `idx_theses_identifier` ON `identifier`
- `idx_theses_orientation` ON `orientation_id`
- `idx_theses_ap_program` ON `ap_program_id`
- `idx_theses_access_type` ON `access_type_id`
**Constraints:**
- `identifier` must be UNIQUE
- `year` must be > 1950 (implicit validation)
- `jury_points` must be between 0 and 20 (implicit validation)
---
### `authors`
**Purpose:** Store student/author information.
| Column | Type | Null | Default | Description |
|--------|------|------|---------|-------------|
| `id` | INTEGER | NO | AUTOINCREMENT | Primary key |
| `name` | TEXT | NO | - | Author full name |
| `email` | TEXT | YES | NULL | Contact email |
| `created_at` | DATETIME | NO | CURRENT_TIMESTAMP | Record creation time |
| `updated_at` | DATETIME | NO | CURRENT_TIMESTAMP | Last update time |
**Indexes:**
- `idx_authors_email` ON `email`
**Notes:**
- Same author can have multiple theses
- Email is optional (privacy)
- No uniqueness constraint on name (same names possible)
---
### `supervisors`
**Purpose:** Store thesis supervisor/promoter information.
| Column | Type | Null | Default | Description |
|--------|------|------|---------|-------------|
| `id` | INTEGER | NO | AUTOINCREMENT | Primary key |
| `name` | TEXT | NO | - | Supervisor full name |
| `created_at` | DATETIME | NO | CURRENT_TIMESTAMP | Record creation time |
| `updated_at` | DATETIME | NO | CURRENT_TIMESTAMP | Last update time |
**Notes:**
- Reusable across multiple theses
- No email/contact info stored (administrative data)
---
## Lookup Tables
### `orientations`
**Purpose:** Predefined list of artistic orientations.
| Column | Type | Null | Default | Description |
|--------|------|------|---------|-------------|
| `id` | INTEGER | NO | AUTOINCREMENT | Primary key |
| `name` | TEXT | NO | - | Orientation name |
| `created_at` | DATETIME | NO | CURRENT_TIMESTAMP | Record creation time |
**Predefined Values:**
1. Arts Numériques
2. Dessin
3. Cinéma d'animation
4. Installation-Performance
5. Peinture
6. Photographie
7. Sculpture
8. Vidéographie
9. Graphisme
10. Typographie
11. Design Numérique
12. Illustration
13. Bande-Dessinée
14. Sérigraphie
15. Gravure
**Constraints:**
- `name` must be UNIQUE
---
### `ap_programs`
**Purpose:** Practical workshops programs (Ateliers Pratiques).
| Column | Type | Null | Default | Description |
|--------|------|------|---------|-------------|
| `id` | INTEGER | NO | AUTOINCREMENT | Primary key |
| `name` | TEXT | NO | - | Program full name |
| `code` | TEXT | YES | NULL | Short code/acronym |
| `created_at` | DATETIME | NO | CURRENT_TIMESTAMP | Record creation time |
**Predefined Values:**
1. Narration Spéculative (no code)
2. Design et Politique du Multiple (DPM)
3. Atelier Pratiques Situées (APS)
4. Lieux, Interdisciplinarités, Écologie, Nécessité, Systèmes (LIENS)
**Constraints:**
- `name` must be UNIQUE
---
### `finality_types`
**Purpose:** Master degree finality types.
| Column | Type | Null | Default | Description |
|--------|------|------|---------|-------------|
| `id` | INTEGER | NO | AUTOINCREMENT | Primary key |
| `name` | TEXT | NO | - | Finality type name |
| `created_at` | DATETIME | NO | CURRENT_TIMESTAMP | Record creation time |
**Predefined Values:**
1. Approfondi (Research-focused)
2. Enseignement (Teaching)
3. Spécialisé (Specialized)
**Constraints:**
- `name` must be UNIQUE
---
### `languages`
**Purpose:** Languages used in thesis.
| Column | Type | Null | Default | Description |
|--------|------|------|---------|-------------|
| `id` | INTEGER | NO | AUTOINCREMENT | Primary key |
| `name` | TEXT | NO | - | Language name |
| `created_at` | DATETIME | NO | CURRENT_TIMESTAMP | Record creation time |
**Predefined Values:**
1. Français
2. Anglais
**Notes:**
- Expandable if needed (Dutch, etc.)
- Thesis can be multilingual (junction table)
**Constraints:**
- `name` must be UNIQUE
---
### `format_types`
**Purpose:** Physical/digital format types.
| Column | Type | Null | Default | Description |
|--------|------|------|---------|-------------|
| `id` | INTEGER | NO | AUTOINCREMENT | Primary key |
| `name` | TEXT | NO | - | Format type name |
| `created_at` | DATETIME | NO | CURRENT_TIMESTAMP | Record creation time |
**Predefined Values:**
1. Site web
2. Audio
3. Vidéo
4. Performance
5. Objet éditorial (printed matter)
6. Installation
7. Autre (other)
**Notes:**
- Multiple formats per thesis allowed
- "Autre" for edge cases
**Constraints:**
- `name` must be UNIQUE
---
### `access_types`
**Purpose:** Define thesis accessibility levels.
| Column | Type | Null | Default | Description |
|--------|------|------|---------|-------------|
| `id` | INTEGER | NO | AUTOINCREMENT | Primary key |
| `name` | TEXT | NO | - | Access type name |
| `description` | TEXT | YES | NULL | Detailed description |
| `created_at` | DATETIME | NO | CURRENT_TIMESTAMP | Record creation time |
**Predefined Values:**
| ID | Name | Description |
|----|------|-------------|
| 1 | Libre | Full access online and in library |
| 2 | Interne | Physical access only; descriptive note online |
| 3 | Interdit | No access; descriptive note online only |
**Constraints:**
- `name` must be UNIQUE
---
### `license_types`
**Purpose:** Creative Commons and other license types.
| Column | Type | Null | Default | Description |
|--------|------|------|---------|-------------|
| `id` | INTEGER | NO | AUTOINCREMENT | Primary key |
| `name` | TEXT | NO | - | License name (e.g., "CC BY-SA 4.0") |
| `description` | TEXT | YES | NULL | License description |
| `created_at` | DATETIME | NO | CURRENT_TIMESTAMP | Record creation time |
**Expected Values:**
- CC BY 4.0
- CC BY-SA 4.0
- CC BY-NC 4.0
- CC BY-NC-SA 4.0
- CC0 1.0
- All Rights Reserved
- Custom (text description)
**Constraints:**
- `name` must be UNIQUE
---
### `keywords`
**Purpose:** Expandable keyword/tag list.
| Column | Type | Null | Default | Description |
|--------|------|------|---------|-------------|
| `id` | INTEGER | NO | AUTOINCREMENT | Primary key |
| `keyword` | TEXT | NO | - | Keyword/tag text |
| `created_at` | DATETIME | NO | CURRENT_TIMESTAMP | Record creation time |
**Notes:**
- Keywords are case-insensitive (normalized to lowercase)
- Maximum 10 keywords per thesis (enforced in application)
- Auto-created when first used
- Can be reused across theses
**Constraints:**
- `keyword` must be UNIQUE
---
## Junction Tables
### `thesis_authors`
**Purpose:** Many-to-many relationship between theses and authors.
| Column | Type | Null | Default | Description |
|--------|------|------|---------|-------------|
| `thesis_id` | INTEGER | NO | - | FK to `theses.id` |
| `author_id` | INTEGER | NO | - | FK to `authors.id` |
| `author_order` | INTEGER | NO | 1 | Display order (1, 2, 3...) |
**Primary Key:** (`thesis_id`, `author_id`)
**Cascade Rules:**
- ON DELETE CASCADE (both FKs)
**Notes:**
- Single author: `author_order = 1`
- Multiple authors: ordered by `author_order`
---
### `thesis_supervisors`
**Purpose:** Many-to-many relationship between theses and supervisors.
| Column | Type | Null | Default | Description |
|--------|------|------|---------|-------------|
| `thesis_id` | INTEGER | NO | - | FK to `theses.id` |
| `supervisor_id` | INTEGER | NO | - | FK to `supervisors.id` |
| `supervisor_order` | INTEGER | NO | 1 | Display order |
**Primary Key:** (`thesis_id`, `supervisor_id`)
**Cascade Rules:**
- ON DELETE CASCADE (both FKs)
---
### `thesis_languages`
**Purpose:** Many-to-many relationship between theses and languages.
| Column | Type | Null | Default | Description |
|--------|------|------|---------|-------------|
| `thesis_id` | INTEGER | NO | - | FK to `theses.id` |
| `language_id` | INTEGER | NO | - | FK to `languages.id` |
**Primary Key:** (`thesis_id`, `language_id`)
**Cascade Rules:**
- ON DELETE CASCADE (both FKs)
---
### `thesis_formats`
**Purpose:** Many-to-many relationship between theses and format types.
| Column | Type | Null | Default | Description |
|--------|------|------|---------|-------------|
| `thesis_id` | INTEGER | NO | - | FK to `theses.id` |
| `format_id` | INTEGER | NO | - | FK to `format_types.id` |
**Primary Key:** (`thesis_id`, `format_id`)
**Cascade Rules:**
- ON DELETE CASCADE (both FKs)
---
### `thesis_keywords`
**Purpose:** Many-to-many relationship between theses and keywords.
| Column | Type | Null | Default | Description |
|--------|------|------|---------|-------------|
| `thesis_id` | INTEGER | NO | - | FK to `theses.id` |
| `keyword_id` | INTEGER | NO | - | FK to `keywords.id` |
**Primary Key:** (`thesis_id`, `keyword_id`)
**Indexes:**
- `idx_thesis_keywords_thesis` ON `thesis_id`
- `idx_thesis_keywords_keyword` ON `keyword_id`
**Cascade Rules:**
- ON DELETE CASCADE (both FKs)
**Business Rules:**
- Maximum 10 keywords per thesis (enforced in application layer)
---
## Support Tables
### `thesis_files`
**Purpose:** Store file attachments for theses.
| Column | Type | Null | Default | Description |
|--------|------|------|---------|-------------|
| `id` | INTEGER | NO | AUTOINCREMENT | Primary key |
| `thesis_id` | INTEGER | NO | - | FK to `theses.id` |
| `file_type` | TEXT | NO | - | Type: 'main', 'annex', 'written_part', 'other' |
| `file_path` | TEXT | NO | - | Relative path to file |
| `file_name` | TEXT | NO | - | Original filename |
| `file_size` | INTEGER | YES | NULL | Size in bytes |
| `mime_type` | TEXT | YES | NULL | MIME type (e.g., 'application/pdf') |
| `description` | TEXT | YES | NULL | File description |
| `uploaded_at` | DATETIME | NO | CURRENT_TIMESTAMP | Upload timestamp |
**Cascade Rules:**
- ON DELETE CASCADE on `thesis_id`
**File Types:**
- **main**: Primary thesis document (PDF, HTML, etc.)
- **annex**: Supplementary materials
- **written_part**: Written component of practice-based thesis
- **other**: Additional files
**Notes:**
- Files stored in `/var/www/html/formulaire/data/theses/`
- Cover images stored in `/var/www/html/formulaire/data/covers/`
---
### `pages`
**Purpose:** Static content management (About, Licenses, Contact, etc.).
| Column | Type | Null | Default | Description |
|--------|------|------|---------|-------------|
| `id` | INTEGER | NO | AUTOINCREMENT | Primary key |
| `slug` | TEXT | NO | - | URL-friendly identifier |
| `title` | TEXT | NO | - | Page title |
| `content` | TEXT | YES | NULL | Page content (Markdown/HTML) |
| `is_published` | BOOLEAN | NO | 1 | Publish status |
| `created_at` | DATETIME | NO | CURRENT_TIMESTAMP | Record creation time |
| `updated_at` | DATETIME | NO | CURRENT_TIMESTAMP | Last update time |
**Predefined Pages:**
- `charte` - Site charter/policy
- `about` - About page
- `licenses` - License information
- `contact` - Contact page
**Constraints:**
- `slug` must be UNIQUE
---
## Views
### `v_theses_full`
**Purpose:** Complete thesis information with all relationships joined.
**Columns:**
- All columns from `theses`
- `orientation` (TEXT) - Orientation name
- `ap_program` (TEXT) - AP program name
- `finality_type` (TEXT) - Finality type name
- `access_type` (TEXT) - Access type name
- `license_type` (TEXT) - License name
- `authors` (TEXT) - Comma-separated author names
- `supervisors` (TEXT) - Comma-separated supervisor names
- `languages` (TEXT) - Comma-separated language names
- `formats` (TEXT) - Comma-separated format names
- `keywords` (TEXT) - Comma-separated keywords
**Usage:**
```sql
SELECT * FROM v_theses_full WHERE id = 123;
```
**Notes:**
- Uses `GROUP_CONCAT` for many-to-many relationships
- Results are comma-delimited strings
- May need post-processing for proper arrays
---
### `v_theses_public`
**Purpose:** Published theses only (for public website).
**Definition:**
```sql
SELECT * FROM v_theses_full WHERE is_published = 1;
```
**Usage:**
```sql
SELECT * FROM v_theses_public ORDER BY year DESC, title;
```
---
## Indexes
### Performance Indexes
| Index Name | Table | Columns | Purpose |
|------------|-------|---------|---------|
| `idx_theses_year` | `theses` | `year` | Filter by year |
| `idx_theses_published` | `theses` | `is_published` | Public/private filtering |
| `idx_theses_identifier` | `theses` | `identifier` | Unique lookup |
| `idx_theses_orientation` | `theses` | `orientation_id` | Filter by orientation |
| `idx_theses_ap_program` | `theses` | `ap_program_id` | Filter by AP program |
| `idx_theses_access_type` | `theses` | `access_type_id` | Access control |
| `idx_authors_email` | `authors` | `email` | Author lookup |
| `idx_thesis_authors_thesis` | `thesis_authors` | `thesis_id` | Join optimization |
| `idx_thesis_authors_author` | `thesis_authors` | `author_id` | Join optimization |
| `idx_thesis_keywords_thesis` | `thesis_keywords` | `thesis_id` | Join optimization |
| `idx_thesis_keywords_keyword` | `thesis_keywords` | `keyword_id` | Keyword search |
---
## Triggers
### Timestamp Update Triggers
**`update_theses_timestamp`**
```sql
AFTER UPDATE ON theses
UPDATE theses SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id;
```
**`update_authors_timestamp`**
```sql
AFTER UPDATE ON authors
UPDATE authors SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id;
```
**`update_supervisors_timestamp`**
```sql
AFTER UPDATE ON supervisors
UPDATE supervisors SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id;
```
**`update_pages_timestamp`**
```sql
AFTER UPDATE ON pages
UPDATE pages SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id;
```
---
## Data Types Reference
### SQLite Data Types Used
| Type | SQLite Affinity | Description | Example Values |
|------|----------------|-------------|----------------|
| `INTEGER` | INTEGER | Signed integer | 1, 42, 2025 |
| `TEXT` | TEXT | Variable-length text | "Title", "Name" |
| `BOOLEAN` | INTEGER | 0 or 1 | 0 (false), 1 (true) |
| `DATETIME` | TEXT | ISO8601 timestamp | "2025-02-05 12:00:00" |
| `DECIMAL(4,2)` | REAL | Decimal number | 15.50, 18.75 |
### Boolean Convention
- `FALSE` = 0
- `TRUE` = 1
- NULL = undefined/not set
---
## Business Rules
### Thesis Submission Workflow
1. **Draft Creation** (`is_published = 0`)
- Student creates initial entry
- Required fields: title, year, at least one author
2. **Complete Metadata**
- Add orientation, AP program, finality
- Upload files
- Add keywords (max 10)
- Set languages, formats
3. **Submission** (`submitted_at` set)
- Student marks as ready for review
- Email notification to administrators
4. **Defense** (`defense_date` set)
- After thesis defense
- Jury adds grade (`jury_points`)
- Optional context note by jury president
5. **Publication** (`is_published = 1`, `published_at` set)
- Administrator approves
- Appears on public website
- Respects `access_type` rules
### Data Validation Rules
**Required Fields (for publication):**
- `title`
- `year`
- At least one author (via `thesis_authors`)
- `orientation_id`
- `access_type_id`
**Optional but Recommended:**
- `synopsis` (~200 words)
- `keywords` (3-10 recommended)
- At least one file attachment
- `license_id`
**Constraints:**
- `year`: Must be ≥ 1950
- `jury_points`: 0.00 to 20.00
- `keywords`: Maximum 10 per thesis
- `author_order`: Must be sequential (1, 2, 3...)
- `identifier`: Unique across all theses
### Access Control Rules
| Access Type | Public View | Library Access | File Download |
|-------------|-------------|----------------|---------------|
| **Libre** | Full metadata + abstract | Yes | Yes |
| **Interne** | Metadata + descriptive note | Physical only | No |
| **Interdit** | Metadata + descriptive note | No | No |
---
## Sample Queries
### Common Queries
**Get all published theses from 2025:**
```sql
SELECT * FROM v_theses_public
WHERE year = 2025
ORDER BY title;
```
**Find theses by author name:**
```sql
SELECT t.* FROM theses t
JOIN thesis_authors ta ON t.id = ta.thesis_id
JOIN authors a ON ta.author_id = a.id
WHERE a.name LIKE '%Dupont%'
AND t.is_published = 1;
```
**Get thesis with all relationships:**
```sql
SELECT * FROM v_theses_full WHERE id = 42;
```
**List theses by orientation:**
```sql
SELECT t.title, t.year, o.name as orientation
FROM theses t
JOIN orientations o ON t.orientation_id = o.id
WHERE o.name = 'Arts Numériques'
AND t.is_published = 1
ORDER BY t.year DESC;
```
**Full-text search in titles and synopses:**
```sql
SELECT * FROM v_theses_public
WHERE title LIKE '%design%'
OR synopsis LIKE '%design%'
ORDER BY year DESC;
```
**Get theses by keyword:**
```sql
SELECT DISTINCT t.* FROM theses t
JOIN thesis_keywords tk ON t.id = tk.thesis_id
JOIN keywords k ON tk.keyword_id = k.id
WHERE k.keyword = 'écologie'
AND t.is_published = 1;
```
**Count theses per year:**
```sql
SELECT year, COUNT(*) as count
FROM theses
WHERE is_published = 1
GROUP BY year
ORDER BY year DESC;
```
**Get theses with files:**
```sql
SELECT t.title, tf.file_name, tf.file_type
FROM theses t
JOIN thesis_files tf ON t.id = tf.thesis_id
WHERE t.is_published = 1
ORDER BY t.title;
```
**Find theses without keywords:**
```sql
SELECT t.* FROM theses t
LEFT JOIN thesis_keywords tk ON t.id = tk.thesis_id
WHERE tk.thesis_id IS NULL
AND t.is_published = 1;
```
### Administrative Queries
**Recently submitted theses (pending review):**
```sql
SELECT title, submitted_at
FROM theses
WHERE submitted_at IS NOT NULL
AND is_published = 0
ORDER BY submitted_at DESC;
```
**Theses missing required metadata:**
```sql
SELECT id, title, year
FROM theses
WHERE (orientation_id IS NULL
OR access_type_id IS NULL
OR id NOT IN (SELECT thesis_id FROM thesis_authors))
AND is_published = 0;
```
**Most used keywords:**
```sql
SELECT k.keyword, COUNT(*) as usage_count
FROM keywords k
JOIN thesis_keywords tk ON k.id = tk.keyword_id
GROUP BY k.keyword
ORDER BY usage_count DESC
LIMIT 20;
```
**Theses by supervisor:**
```sql
SELECT s.name as supervisor, COUNT(*) as thesis_count
FROM supervisors s
JOIN thesis_supervisors ts ON s.id = ts.supervisor_id
JOIN theses t ON ts.thesis_id = t.id
WHERE t.is_published = 1
GROUP BY s.name
ORDER BY thesis_count DESC;
```
---
## Making Schema Changes
### How to Request Changes
When requesting schema changes, please specify:
1. **What needs to change**
- Table name
- Column name(s)
- Relationship
2. **Type of change**
- Add new table
- Add new column
- Modify existing column
- Remove column/table
- Change relationship
3. **Why it's needed**
- Use case
- Business requirement
- Performance issue
4. **Example data**
- Sample values
- Expected format
### Example Change Request
```
**Change Request:** Add support for thesis awards/distinctions
**Type:** Add new table + relationship
**Reason:** Need to track prizes and awards given to theses
(e.g., "Best TFE 2025", "Jury Prize")
**Proposed Structure:**
- Table: `awards`
- id (INT, PK)
- name (TEXT) - Award name
- description (TEXT) - Award description
- year (INT) - Year established
- Table: `thesis_awards`
- thesis_id (INT, FK)
- award_id (INT, FK)
- awarded_date (DATETIME)
**Example Data:**
- "Prix du Jury 2025"
- "Meilleur TFE Arts Numériques"
- "Prix de l'Innovation"
```
---
## Version History
| Version | Date | Changes |
|---------|------|---------|
| 1.0 | 2026-02-05 | Initial specification document |
---
**For questions or change requests, reference this document and provide:**
- Section name
- Table/column affected
- Desired outcome
- Example use case

Binary file not shown.

View File

@@ -0,0 +1,206 @@
# Database Quick Reference
Quick lookup for the Post-ERG database schema.
## 📊 Table Summary
| Table | Type | Records | Description |
|-------|------|---------|-------------|
| `theses` | Core | ~500/year | Main thesis records |
| `authors` | Core | ~600 | Student/author info |
| `supervisors` | Core | ~50 | Thesis supervisors |
| `thesis_authors` | Junction | ~550/year | Thesis ↔ Authors |
| `thesis_supervisors` | Junction | ~600/year | Thesis ↔ Supervisors |
| `thesis_languages` | Junction | ~550/year | Thesis ↔ Languages |
| `thesis_formats` | Junction | ~700/year | Thesis ↔ Formats |
| `thesis_keywords` | Junction | ~3000/year | Thesis ↔ Keywords |
| `thesis_files` | Support | ~800/year | File attachments |
| `orientations` | Lookup | 15 | Art orientations |
| `ap_programs` | Lookup | 4 | Workshop programs |
| `finality_types` | Lookup | 3 | Master finalities |
| `languages` | Lookup | 2+ | Languages |
| `format_types` | Lookup | 7 | Media formats |
| `access_types` | Lookup | 3 | Access levels |
| `license_types` | Lookup | ~10 | Creative Commons |
| `keywords` | Lookup | ~500+ | Tag system |
| `pages` | Support | 4 | Static pages |
## 🔑 Key Relationships
```
theses ──┬── 1:N ──► thesis_authors ──► N:1 ── authors
├── 1:N ──► thesis_supervisors ──► N:1 ── supervisors
├── 1:N ──► thesis_keywords ──► N:1 ── keywords
├── 1:N ──► thesis_languages ──► N:1 ── languages
├── 1:N ──► thesis_formats ──► N:1 ── format_types
├── 1:N ──► thesis_files
├── N:1 ──► orientations
├── N:1 ──► ap_programs
├── N:1 ──► finality_types
├── N:1 ──► access_types
└── N:1 ──► license_types
```
## 📝 Core Fields Reference
### `theses` (Main Table)
**Identity:**
- `id` - Primary key
- `identifier` - Human-readable ID (e.g., "2025-002")
**Basic Info:**
- `title` - Thesis title (required)
- `subtitle` - Optional subtitle
- `year` - Academic year (required)
- `is_doctoral` - TFE (0) or Doctoral (1)
**Academic:**
- `orientation_id` - Art orientation
- `ap_program_id` - Workshop program
- `finality_id` - Master finality type
**Content:**
- `synopsis` - ~200 word summary
- `context_note` - Jury note (max 150 words)
- `duration_minutes` - For audio/video
- `duration_pages` - For written works
**Access:**
- `access_type_id` - Public/Internal/Restricted
- `license_id` - Creative Commons, etc.
**Workflow:**
- `submitted_at` - Student submission
- `defense_date` - Defense date
- `is_published` - Public visibility
- `published_at` - Publication date
- `jury_points` - Grade (0-20)
## 🏷️ Lookup Values
### Orientations (15)
Arts Numériques, Dessin, Cinéma d'animation, Installation-Performance, Peinture, Photographie, Sculpture, Vidéographie, Graphisme, Typographie, Design Numérique, Illustration, Bande-Dessinée, Sérigraphie, Gravure
### AP Programs (4)
- Narration Spéculative
- Design et Politique du Multiple (DPM)
- Atelier Pratiques Situées (APS)
- Lieux, Interdisciplinarités, Écologie, Nécessité, Systèmes (LIENS)
### Finality Types (3)
Approfondi, Enseignement, Spécialisé
### Languages (2+)
Français, Anglais
### Format Types (7)
Site web, Audio, Vidéo, Performance, Objet éditorial, Installation, Autre
### Access Types (3)
- **Libre**: Full access online + library
- **Interne**: Library only, note online
- **Interdit**: No access, note only
## 🔍 Common Queries
### Get Published Theses
```sql
SELECT * FROM v_theses_public ORDER BY year DESC;
```
### Get Thesis by ID
```sql
SELECT * FROM v_theses_full WHERE id = ?;
```
### Search by Title
```sql
SELECT * FROM v_theses_public
WHERE title LIKE '%keyword%'
ORDER BY year DESC;
```
### Filter by Year
```sql
SELECT * FROM v_theses_public
WHERE year = 2025
ORDER BY title;
```
### Filter by Orientation
```sql
SELECT t.* FROM theses t
JOIN orientations o ON t.orientation_id = o.id
WHERE o.name = 'Arts Numériques'
AND t.is_published = 1;
```
### Get Author's Theses
```sql
SELECT t.* FROM theses t
JOIN thesis_authors ta ON t.id = ta.thesis_id
JOIN authors a ON ta.author_id = a.id
WHERE a.name LIKE '%name%'
AND t.is_published = 1;
```
### Get Keywords for Thesis
```sql
SELECT k.keyword FROM keywords k
JOIN thesis_keywords tk ON k.id = tk.keyword_id
WHERE tk.thesis_id = ?;
```
### Count by Year
```sql
SELECT year, COUNT(*) as count
FROM theses
WHERE is_published = 1
GROUP BY year
ORDER BY year DESC;
```
## 📌 Important Constraints
- **Unique:** `theses.identifier`, `authors.email`, all lookup table names
- **Required:** `theses.title`, `theses.year`, at least one author
- **Max:** 10 keywords per thesis
- **Range:** `jury_points` 0.00 - 20.00
- **Cascade:** All junction tables DELETE CASCADE
## 🎯 Views
### `v_theses_full`
Complete thesis data with all relationships (comma-separated).
### `v_theses_public`
Only published theses (`is_published = 1`).
## 🔧 Making Changes
**Format for change requests:**
```
Table: [table_name]
Change: [add/modify/remove]
Column: [column_name]
Type: [data_type]
Reason: [why needed]
Example: [sample data]
```
**Example:**
```
Table: theses
Change: add
Column: external_url
Type: TEXT
Reason: Link to external project website
Example: https://example.com/project
```
## 📚 Full Documentation
See `DATABASE_SPECIFICATION.md` for complete details.

View File

@@ -1,244 +1,222 @@
# Post-ERG Thesis Database Schema
# Database Documentation
SQLite database schema for managing final thesis projects (TFE) and doctoral theses at ERG.
Complete documentation for the Post-ERG thesis database.
## Overview
## 📚 Available Documentation
This schema supports all requirements from the technical specifications (`posterg_fiche-technique.md`):
### 1. **[DATABASE_SPECIFICATION.md](DATABASE_SPECIFICATION.md)** ⭐
**Complete technical specification** - 25KB comprehensive document
- Multiple metadata categories (orientation, AP, finality, languages, formats, keywords)
- Multiple authors and supervisors per thesis
- Access control (Libre/Interne/Interdit)
- Licensing management
- File uploads (main TFE, annexes, written parts)
- Jury notes and points
- Publication workflow (submission → defense → publication)
- Editable static pages (charte, about, licenses, contact)
- Distinction between TFEs and doctoral theses
**Contents:**
- Complete table definitions with all columns
- Entity relationship diagrams
- Junction table specifications
- Lookup table values
- Business rules and workflows
- Sample queries and use cases
- Instructions for requesting schema changes
## Database Structure
**Use when:** You need complete technical details about the database structure.
### Core Tables
---
**`theses`** - Main thesis information
- Basic metadata (title, subtitle, year, identifier)
- Academic details (orientation, AP program, finality)
- Content (synopsis, jury notes, duration/size)
- Access control and licensing
- Publication workflow status
### 2. **[QUICK_SCHEMA_REFERENCE.md](QUICK_SCHEMA_REFERENCE.md)** 🚀
**Quick reference guide** - 5KB at-a-glance reference
**`authors`** - Student/author information
- Name and contact email
**Contents:**
- Table summary
- Key relationships diagram
- Core fields reference
- Predefined lookup values
- Common SQL queries
- Constraint summary
**`supervisors`** - Thesis promoters
- Name of supervisor/promoter
**Use when:** You need quick lookup or common query examples.
**`thesis_files`** - Uploaded files
- Main TFE, annexes, written parts
- File metadata (path, size, MIME type)
---
**`pages`** - Static content pages
- Charte, about, licenses, contact pages
- Easily editable content
### 3. **[schema.sql](schema.sql)** 💾
**The actual SQL schema** - Executable SQL file
### Reference Tables (Predefined Lists)
**Contents:**
- Complete CREATE TABLE statements
- Indexes and triggers
- Predefined data (orientations, AP programs, etc.)
- Views for common queries
- `orientations` - Arts Numériques, Dessin, Cinéma d'animation, etc.
- `ap_programs` - Narration Spéculative, DPM, APS, LIENS
- `finality_types` - Approfondi, Enseignement, Spécialisé
- `languages` - Français, Anglais, etc. (expandable)
- `format_types` - Site web, Audio, Vidéo, Performance, etc.
- `keywords` - Dynamic, expandable keyword list (max 10 per thesis)
- `access_types` - Libre, Interne, Interdit
- `license_types` - To be defined
**Use when:** Setting up or resetting the database.
### Junction Tables (Many-to-Many)
---
- `thesis_authors` - Links theses to authors
- `thesis_supervisors` - Links theses to supervisors
- `thesis_languages` - Multiple languages per thesis
- `thesis_formats` - Multiple formats per thesis
- `thesis_keywords` - Max 10 keywords per thesis
## 🚀 Quick Start
## Key Features
### View Database Schema
```bash
# Read the quick reference
cat database/QUICK_SCHEMA_REFERENCE.md
### 1. Flexible Metadata
- Multiple authors, supervisors, languages, formats, and keywords per thesis
- Predefined lists with ability to add new entries
- Proper normalization to avoid data duplication
### 2. Access Control
Three levels of access as specified:
- **Libre**: Freely accessible online and in library
- **Interne**: Physical access only, descriptive note online
- **Interdit**: No physical/online access, descriptive note only
**Important**: Access can be restricted but never opened (as per specs)
### 3. Publication Workflow
The schema tracks the complete lifecycle:
1. **Submission** (`submitted_at`) - Student submits TFE
2. **Defense** (`defense_date`) - Soutenance takes place
3. **Jury Review** (`jury_note_added`, `jury_points`, `context_note`)
4. **Publication** (`published_at`, `is_published = 1`)
**Important**: TFEs are NOT published immediately upon submission. They must wait for:
- Defense to occur
- Jury to add optional context note (max 150 words)
- Jury points to be recorded
### 4. File Management
Support for multiple file types per thesis:
- Main TFE work
- Annexes
- Written part
- Other supporting files
### 5. Views for Easy Querying
**`v_theses_full`** - Complete thesis information with all related data
- Joins all tables
- Concatenates multiple values (authors, supervisors, keywords, etc.)
- Use for backend/admin interfaces
**`v_theses_public`** - Only published theses
- Filtered to `is_published = 1`
- Use for public-facing website
## Usage
# Or full specification
cat database/DATABASE_SPECIFICATION.md
```
### Initialize Database
```bash
sqlite3 posterg.db < schema.sql
# Create test database from schema
just init-test-db
# Create with sample data
just create-fixtures
```
### Example Queries
### Query Database
```bash
# Open SQLite prompt
just query-db
#### Get all published theses from 2025
```sql
SELECT * FROM v_theses_public WHERE year = 2025;
# Show specific thesis
just show-thesis 42
```
#### Get theses by orientation
```sql
SELECT * FROM v_theses_full
WHERE orientation = 'Vidéographie';
## 📝 Making Schema Changes
### Step 1: Document Your Request
Format:
```
**Table:** [table_name]
**Change Type:** [add/modify/remove]
**What:** [description]
**Why:** [reason/use case]
**Example Data:** [samples]
```
#### Get theses with specific keyword
```sql
SELECT t.* FROM v_theses_full t
JOIN thesis_keywords tk ON t.id = tk.thesis_id
JOIN keywords k ON tk.keyword_id = k.id
WHERE k.keyword = 'performance';
### Step 2: Specify Details
For **new columns**:
- Column name
- Data type (TEXT, INTEGER, BOOLEAN, DATETIME)
- NULL/NOT NULL
- Default value
- Indexes needed?
For **new tables**:
- Table name
- All columns
- Relationships to existing tables
- Sample data
### Step 3: Provide Context
Include:
- Use case scenario
- Who will use it?
- How will it be displayed?
- Any constraints?
### Example Request
```
**Table:** theses
**Change Type:** add column
**What:** Add column to track if thesis won an award
**Why:** Need to highlight award-winning theses on homepage
**Column Name:** has_award
**Data Type:** BOOLEAN
**Default:** 0 (false)
**Example:** 1 for "Prix du Jury 2025" winner
```
#### Get theses awaiting publication (submitted but not published)
```sql
SELECT * FROM theses
WHERE submitted_at IS NOT NULL
AND is_published = 0;
## 🗂️ Database Structure Overview
```
┌─────────────┐
│ theses │ ◄── Main table (500+ records/year)
└──────┬──────┘
├──► authors (via thesis_authors)
├──► supervisors (via thesis_supervisors)
├──► keywords (via thesis_keywords)
├──► languages (via thesis_languages)
├──► formats (via thesis_formats)
├──► thesis_files (attachments)
└──► Lookup tables:
• orientations
• ap_programs
• finality_types
• access_types
• license_types
```
#### Update access type (can only restrict, not open)
```sql
-- Allowed: from Libre to Interne
UPDATE theses SET access_type_id = 2 WHERE id = 1;
## 📊 Key Statistics
-- Not allowed per specs: from Interdit to Libre
-- This should be enforced in application logic
- **Core tables:** 3 (theses, authors, supervisors)
- **Junction tables:** 5 (many-to-many relationships)
- **Lookup tables:** 7 (predefined values)
- **Support tables:** 2 (files, pages)
- **Views:** 2 (full data, public only)
- **Indexes:** 11 (for performance)
- **Triggers:** 4 (auto-update timestamps)
## 🔍 Common Scenarios
### Scenario 1: Student Submits Thesis
1. Create record in `theses` (is_published=0)
2. Add author to `authors`, link via `thesis_authors`
3. Add supervisor(s) to `supervisors`, link via `thesis_supervisors`
4. Set `orientation_id`, `ap_program_id`, `finality_id`
5. Upload file to `thesis_files`
6. Add keywords via `thesis_keywords`
7. Set `submitted_at` timestamp
### Scenario 2: Admin Publishes Thesis
1. Verify all required fields present
2. Set `defense_date`
3. Set `jury_points`
4. Optional: add `context_note`
5. Set `is_published = 1`
6. Set `published_at = CURRENT_TIMESTAMP`
### Scenario 3: Public User Searches
Query `v_theses_public` view with filters:
- By year
- By orientation
- By keyword
- By author name
- Full-text search in title/synopsis
## 🛠️ Development Workflow
### Local Development
1. Use `test.db` for development
2. Create via `just init-test-db`
3. Populate with `just create-fixtures`
4. Test queries before deployment
### Schema Changes
1. Update `schema.sql`
2. Update `DATABASE_SPECIFICATION.md`
3. Test on `test.db`
4. Deploy to production (manual migration)
### Testing
```bash
# Run tests on local database
just test-public-all
# Check database stats
just stats-public
```
## Data Import Notes
## 📞 Need Help?
Based on `Database_TFE_test.csv`:
1. **Quick lookup** → Read `QUICK_SCHEMA_REFERENCE.md`
2. **Complete details** → Read `DATABASE_SPECIFICATION.md`
3. **Schema changes** → Follow format in this README
4. **SQL examples** → Check `QUICK_SCHEMA_REFERENCE.md`
### Current CSV Structure
- Identifiant (e.g., "2025-002")
- Titre, Sous-titre
- Auteur·ice(s) - comma-separated if multiple
- Contact - email
- Promoteur·ice(s) - comma-separated if multiple
- Format - comma-separated if multiple
- Année
- AP - abbreviation (DPM, LIENS, etc.)
- Orientation - abbreviation (SC, VI, CA, etc.)
- Finalité
- Mots-clés - comma-separated, max 10
- Synopsis
- Contexte - jury context note
- Remarques - internal notes
- Langue - language(s)
- Autorisation - access type
- License - license type
- taille - duration/size info
- Points sur 20 - jury points
- lien BAIU - institutional repository link
## 🔗 Related Documentation
### Import Considerations
1. **Parse comma-separated values** for:
- Authors (split and create entries in `authors` table)
- Supervisors (split and create entries in `supervisors` table)
- Formats (map to `format_types`)
- Keywords (split and create/link in `keywords`)
- Languages (split and map to `languages`)
2. **Map abbreviations**:
- Orientations: SC → Sculpture, VI → Vidéographie, CA → Cinéma d'animation, etc.
- AP: DPM, LIENS, APS (exact match)
3. **Handle missing data**:
- Some fields in CSV are empty (AP, Orientation for some entries)
- Use NULL in database
4. **Parse duration/size**:
- Examples: "128 pages", "78 pages + ?? minutes", "68 minutes"
- Extract numeric values for `duration_pages` and `duration_minutes`
- Store original string in `file_size_info`
## Schema Design Decisions
### Why SQLite?
- Self-contained, serverless
- Easy to backup (single file)
- Good performance for this use case
- Simple to integrate with various tools
### Normalization Level
- 3rd Normal Form (3NF) for most tables
- Denormalized views for read performance
- Balance between flexibility and simplicity
### Extensibility
- New languages can be added via `languages` table
- Keywords are dynamic and grow with content
- License types can be defined later
- Static pages can be added via `pages` table
### Constraints
- CASCADE deletes on junction tables
- UNIQUE constraints on lookup table names
- NOT NULL on critical fields
- Automatic timestamps via triggers
## Important Business Rules
1. **No immediate publication**: TFEs must go through defense before publication
2. **Access restriction is one-way**: Can restrict but not open access
3. **Max 10 keywords** per thesis (enforce in application)
4. **Jury context note max 150 words** (enforce in application)
5. **Synopsis ~200 words** (guideline, not hard limit)
6. **Multiple selections allowed** for: languages, formats, authors, supervisors, keywords
7. **Doctoral theses**: Use `is_doctoral = 1` to distinguish from TFEs
## Next Steps
1. Create import script to load CSV data
2. Define license types
3. Build backend API for CRUD operations
4. Implement authorization checks
5. Create admin interface for easy editing
6. Build public-facing website using views
- [Deployment Guide](../nginx/DEPLOYMENT_COMPLETE.md)
- [Repository Structure](../REPOSITORY_STRUCTURE_ANALYSIS.md)
- [Test Database Guide](../nginx/TEST_DATABASE_SETUP.md)

Binary file not shown.