Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d7783badca | ||
|
|
6a586110e7 | ||
|
|
f9fd8d73a8 |
@@ -0,0 +1,88 @@
|
|||||||
|
import {
|
||||||
|
Column,
|
||||||
|
CreateDateColumn,
|
||||||
|
Entity,
|
||||||
|
JoinColumn,
|
||||||
|
ManyToOne,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
} from 'typeorm';
|
||||||
|
import { AmChildren } from './am_children.entity';
|
||||||
|
import { Users } from './users.entity';
|
||||||
|
|
||||||
|
export enum TypeAbsenceGardeType {
|
||||||
|
ABSENCE_ENFANT = 'absence_enfant',
|
||||||
|
CONGE_AM = 'conge_am',
|
||||||
|
ARRET_MALADIE_AM = 'arret_maladie_am',
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum StatutAbsenceGardeType {
|
||||||
|
EN_ATTENTE = 'en_attente',
|
||||||
|
ACCEPTE = 'accepte',
|
||||||
|
REFUSE = 'refuse',
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérité métier des absences / congés / arrêts par couple AM↔enfant.
|
||||||
|
* Les cartes (module ultérieur) collectent ; cette table stocke.
|
||||||
|
* Ticket #193.
|
||||||
|
*/
|
||||||
|
@Entity('absences_garde', { schema: 'public' })
|
||||||
|
export class AbsencesGarde {
|
||||||
|
@PrimaryGeneratedColumn('uuid')
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
@Column({ name: 'id_placement', type: 'uuid' })
|
||||||
|
id_placement: string;
|
||||||
|
|
||||||
|
@ManyToOne(() => AmChildren, { onDelete: 'CASCADE' })
|
||||||
|
@JoinColumn({ name: 'id_placement', referencedColumnName: 'id' })
|
||||||
|
placement: AmChildren;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
type: 'enum',
|
||||||
|
enum: TypeAbsenceGardeType,
|
||||||
|
enumName: 'type_absence_garde_type',
|
||||||
|
name: 'type',
|
||||||
|
})
|
||||||
|
type: TypeAbsenceGardeType;
|
||||||
|
|
||||||
|
@Column({ name: 'date_debut', type: 'date' })
|
||||||
|
date_debut: string;
|
||||||
|
|
||||||
|
@Column({ name: 'date_fin', type: 'date' })
|
||||||
|
date_fin: string;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
type: 'enum',
|
||||||
|
enum: StatutAbsenceGardeType,
|
||||||
|
enumName: 'statut_absence_garde_type',
|
||||||
|
name: 'statut',
|
||||||
|
default: StatutAbsenceGardeType.EN_ATTENTE,
|
||||||
|
})
|
||||||
|
statut: StatutAbsenceGardeType;
|
||||||
|
|
||||||
|
/** Purge auto pour en_attente/refuse ; accepte → infinity. */
|
||||||
|
@Column({ name: 'expire_at', type: 'timestamptz' })
|
||||||
|
expire_at: Date;
|
||||||
|
|
||||||
|
@Column({ name: 'cree_par', type: 'uuid', nullable: true })
|
||||||
|
cree_par?: string;
|
||||||
|
|
||||||
|
@ManyToOne(() => Users, { nullable: true, onDelete: 'SET NULL' })
|
||||||
|
@JoinColumn({ name: 'cree_par', referencedColumnName: 'id' })
|
||||||
|
createdBy?: Users;
|
||||||
|
|
||||||
|
/** Réf. carte de collecte (FK quand module Cartes existera). */
|
||||||
|
@Column({ name: 'id_card_instance', type: 'uuid', nullable: true })
|
||||||
|
id_card_instance?: string;
|
||||||
|
|
||||||
|
@Column({ name: 'motif', type: 'text', nullable: true })
|
||||||
|
motif?: string;
|
||||||
|
|
||||||
|
@CreateDateColumn({ name: 'cree_le', type: 'timestamptz' })
|
||||||
|
cree_le: Date;
|
||||||
|
|
||||||
|
@UpdateDateColumn({ name: 'modifie_le', type: 'timestamptz' })
|
||||||
|
modifie_le: Date;
|
||||||
|
}
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
import { Column, CreateDateColumn, Entity, JoinColumn, ManyToOne, PrimaryGeneratedColumn, UpdateDateColumn } from "typeorm";
|
|
||||||
import { Children } from "./children.entity";
|
|
||||||
import { Users } from "./users.entity";
|
|
||||||
import { Parents } from "./parents.entity";
|
|
||||||
|
|
||||||
export enum TypeEvenementType {
|
|
||||||
ABSENCE_ENFANT = 'absence_enfant',
|
|
||||||
CONGE_AM = 'conge_am',
|
|
||||||
CONGE_PARENT = 'conge_parent',
|
|
||||||
ARRET_MALADIE_AM = 'arret_maladie_am',
|
|
||||||
EVENEMENT_RPE = 'evenement_rpe',
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum StatutEvenementType {
|
|
||||||
PROPOSE = 'propose',
|
|
||||||
VALIDE = 'valide',
|
|
||||||
REFUSE = 'refuse',
|
|
||||||
}
|
|
||||||
|
|
||||||
@Entity('evenements')
|
|
||||||
export class Evenement {
|
|
||||||
// Define your columns and relationships here
|
|
||||||
@PrimaryGeneratedColumn('uuid')
|
|
||||||
id: string;
|
|
||||||
|
|
||||||
@Column({
|
|
||||||
type: 'enum',
|
|
||||||
enum: TypeEvenementType,
|
|
||||||
enumName: 'type_evenement_type',
|
|
||||||
name: 'type'
|
|
||||||
})
|
|
||||||
type: TypeEvenementType;
|
|
||||||
|
|
||||||
@ManyToOne(() => Children, { onDelete: 'CASCADE', nullable: true })
|
|
||||||
@JoinColumn({ name: 'id_enfant', referencedColumnName: 'id' })
|
|
||||||
child?: Children;
|
|
||||||
|
|
||||||
@ManyToOne(() => Users, { nullable: true })
|
|
||||||
@JoinColumn({ name: 'id_am', referencedColumnName: 'id' })
|
|
||||||
assistanteMaternelle?: Users;
|
|
||||||
|
|
||||||
@ManyToOne(() => Parents, { nullable: true })
|
|
||||||
@JoinColumn({ name: 'id_parent', referencedColumnName: 'user_id' })
|
|
||||||
parent?: Parents;
|
|
||||||
|
|
||||||
@ManyToOne(() => Users, { nullable: true })
|
|
||||||
@JoinColumn({ name: 'cree_par', referencedColumnName: 'id' })
|
|
||||||
created_by?: Users;
|
|
||||||
|
|
||||||
@Column({ type: 'timestamptz', nullable: true, name: 'date_debut' })
|
|
||||||
start_date?: Date;
|
|
||||||
|
|
||||||
@Column({ type: 'timestamptz', nullable: true, name: 'date_fin' })
|
|
||||||
end_date?: Date;
|
|
||||||
|
|
||||||
@Column({ type: 'text', nullable: true, name: 'commentaires' })
|
|
||||||
comments?: string;
|
|
||||||
|
|
||||||
@Column({
|
|
||||||
type: 'enum',
|
|
||||||
enum: StatutEvenementType,
|
|
||||||
enumName: 'statut_evenement_type',
|
|
||||||
name: 'statut',
|
|
||||||
default: StatutEvenementType.PROPOSE
|
|
||||||
})
|
|
||||||
status: StatutEvenementType;
|
|
||||||
|
|
||||||
@Column({type: 'timestamptz', nullable: true, name: 'delai_grace'})
|
|
||||||
grace_deadline?: Date;
|
|
||||||
|
|
||||||
@Column({type: 'boolean', default: false, name: 'urgent'})
|
|
||||||
urgent: boolean;
|
|
||||||
|
|
||||||
@CreateDateColumn({ name: 'cree_le', type: 'timestamptz' })
|
|
||||||
created_at: Date;
|
|
||||||
|
|
||||||
@UpdateDateColumn({ name: 'modifie_le', type: 'timestamptz' })
|
|
||||||
updated_at: Date;
|
|
||||||
}
|
|
||||||
+31
-20
@@ -35,13 +35,15 @@ DO $$ BEGIN
|
|||||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'statut_avenant_type') THEN
|
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'statut_avenant_type') THEN
|
||||||
CREATE TYPE statut_avenant_type AS ENUM ('propose', 'accepte', 'refuse');
|
CREATE TYPE statut_avenant_type AS ENUM ('propose', 'accepte', 'refuse');
|
||||||
END IF;
|
END IF;
|
||||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'type_evenement_type') THEN
|
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'type_absence_garde_type') THEN
|
||||||
CREATE TYPE type_evenement_type AS ENUM (
|
CREATE TYPE type_absence_garde_type AS ENUM (
|
||||||
'absence_enfant', 'conge_am', 'conge_parent', 'arret_maladie_am', 'evenement_rpe'
|
'absence_enfant', 'conge_am', 'arret_maladie_am'
|
||||||
);
|
);
|
||||||
END IF;
|
END IF;
|
||||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'statut_evenement_type') THEN
|
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'statut_absence_garde_type') THEN
|
||||||
CREATE TYPE statut_evenement_type AS ENUM ('propose', 'valide', 'refuse');
|
CREATE TYPE statut_absence_garde_type AS ENUM (
|
||||||
|
'en_attente', 'accepte', 'refuse'
|
||||||
|
);
|
||||||
END IF;
|
END IF;
|
||||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'statut_validation_type') THEN
|
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'statut_validation_type') THEN
|
||||||
CREATE TYPE statut_validation_type AS ENUM ('en_attente', 'valide', 'refuse');
|
CREATE TYPE statut_validation_type AS ENUM ('en_attente', 'valide', 'refuse');
|
||||||
@@ -307,25 +309,34 @@ CREATE TABLE avenants_contrats (
|
|||||||
);
|
);
|
||||||
|
|
||||||
-- ==========================================================
|
-- ==========================================================
|
||||||
-- Table : evenements
|
-- Table : absences_garde (vérité métier absences/congés/arrêt)
|
||||||
|
-- 1 ligne = 1 période ; rattachement = placement AM↔enfant (#193)
|
||||||
-- ==========================================================
|
-- ==========================================================
|
||||||
CREATE TABLE evenements (
|
CREATE TABLE absences_garde (
|
||||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
type type_evenement_type,
|
id_placement UUID NOT NULL
|
||||||
id_enfant UUID REFERENCES enfants(id) ON DELETE CASCADE,
|
REFERENCES enfants_assistantes_maternelles(id) ON DELETE CASCADE,
|
||||||
id_am UUID REFERENCES utilisateurs(id),
|
type type_absence_garde_type NOT NULL,
|
||||||
id_parent UUID REFERENCES parents(id_utilisateur),
|
date_debut DATE NOT NULL,
|
||||||
cree_par UUID REFERENCES utilisateurs(id),
|
date_fin DATE NOT NULL,
|
||||||
date_debut TIMESTAMPTZ,
|
statut statut_absence_garde_type NOT NULL DEFAULT 'en_attente',
|
||||||
date_fin TIMESTAMPTZ,
|
expire_at TIMESTAMPTZ NOT NULL,
|
||||||
commentaires TEXT,
|
cree_par UUID REFERENCES utilisateurs(id) ON DELETE SET NULL,
|
||||||
statut statut_evenement_type DEFAULT 'propose',
|
id_card_instance UUID,
|
||||||
delai_grace TIMESTAMPTZ,
|
motif TEXT,
|
||||||
urgent BOOLEAN DEFAULT false,
|
cree_le TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||||
cree_le TIMESTAMPTZ DEFAULT now(),
|
modifie_le TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||||
modifie_le TIMESTAMPTZ DEFAULT now()
|
CONSTRAINT chk_absences_garde_dates CHECK (date_fin >= date_debut)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE INDEX idx_absences_garde_placement_dates
|
||||||
|
ON absences_garde (id_placement, date_debut, date_fin);
|
||||||
|
CREATE INDEX idx_absences_garde_placement_type_statut
|
||||||
|
ON absences_garde (id_placement, type, statut);
|
||||||
|
CREATE INDEX idx_absences_garde_expire_at
|
||||||
|
ON absences_garde (expire_at)
|
||||||
|
WHERE statut IN ('en_attente', 'refuse');
|
||||||
|
|
||||||
-- ==========================================================
|
-- ==========================================================
|
||||||
-- Table : signalements_bugs
|
-- Table : signalements_bugs
|
||||||
-- ==========================================================
|
-- ==========================================================
|
||||||
|
|||||||
+10
-10
@@ -104,31 +104,31 @@ Ce document recense **toutes les valeurs énumérées** utilisées dans la base
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7) Type d’événement — `type`
|
## 7) Type d’absence de garde — `type`
|
||||||
|
|
||||||
**Tables/colonnes** : `evenements.type`
|
**Tables/colonnes** : `absences_garde.type`
|
||||||
**Valeurs autorisées** :
|
**Valeurs autorisées** :
|
||||||
|
|
||||||
| Valeur | Description |
|
| Valeur | Description |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `absence_enfant` | Enfant absent |
|
| `absence_enfant` | Absence déclarée par un parent |
|
||||||
| `conge_am` | Congé de l’assistante maternelle |
|
| `conge_am` | Congé de l’assistante maternelle |
|
||||||
| `conge_parent` | Congé du parent |
|
|
||||||
| `arret_maladie_am` | Arrêt maladie AM |
|
| `arret_maladie_am` | Arrêt maladie AM |
|
||||||
| `evenement_rpe` | Événement RPE |
|
|
||||||
|
> Remplace l’ancien enum `type_evenement_type` / table `evenements` (supprimés ticket #193).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 8) Statut d’événement — `statut`
|
## 8) Statut d’absence de garde — `statut`
|
||||||
|
|
||||||
**Tables/colonnes** : `evenements.statut`
|
**Tables/colonnes** : `absences_garde.statut`
|
||||||
**Valeurs autorisées** :
|
**Valeurs autorisées** :
|
||||||
|
|
||||||
| Valeur | Description |
|
| Valeur | Description |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `propose` | Événement proposé |
|
| `en_attente` | En attente de validation / ack |
|
||||||
| `valide` | Événement validé |
|
| `accepte` | Accepté / acté (conservé en historique métier) |
|
||||||
| `rejete` | Événement refusé |
|
| `refuse` | Refusé (temporaire ; purge TTL) |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -42,10 +42,8 @@ Documenter, de façon unique et partagée, les règles de suppression/mise à jo
|
|||||||
| **contrats(id_dossier)** → `dossiers(id)` | **CASCADE** | 1:1, contrat détruit si dossier supprimé |
|
| **contrats(id_dossier)** → `dossiers(id)` | **CASCADE** | 1:1, contrat détruit si dossier supprimé |
|
||||||
| **avenants_contrats(id_contrat)** → `contrats(id)` | **CASCADE** | Avenants détruits avec le contrat |
|
| **avenants_contrats(id_contrat)** → `contrats(id)` | **CASCADE** | Avenants détruits avec le contrat |
|
||||||
| **avenants_contrats(initie_par)** → `utilisateurs(id)` | **SET NULL** | Historiser l’avenant sans bloquer |
|
| **avenants_contrats(initie_par)** → `utilisateurs(id)` | **SET NULL** | Historiser l’avenant sans bloquer |
|
||||||
| **evenements(id_enfant)** → `enfants(id)` | **CASCADE** | Événements n’ont plus de sens |
|
| **absences_garde(id_placement)** → `enfants_assistantes_maternelles(id)` | **CASCADE** | Plus de couple = plus d’absences |
|
||||||
| **evenements(id_am)** → `utilisateurs(id)` | **SET NULL** | Garder la trace même si AM supprimée |
|
| **absences_garde(cree_par)** → `utilisateurs(id)` | **SET NULL** | Conserver la période si user supprimé |
|
||||||
| **evenements(id_parent)** → `parents(id_utilisateur)` | **SET NULL** | Garder la trace si parent supprimé |
|
|
||||||
| **evenements(cree_par)** → `utilisateurs(id)` | **SET NULL** | Conserver l’historique de création |
|
|
||||||
| **signalements_bugs(id_utilisateur)** → `utilisateurs(id)` | **SET NULL** | Conserver le ticket même si compte supprimé |
|
| **signalements_bugs(id_utilisateur)** → `utilisateurs(id)` | **SET NULL** | Conserver le ticket même si compte supprimé |
|
||||||
| **uploads(id_utilisateur)** → `utilisateurs(id)` | **SET NULL** | Fichier reste référencé sans l’auteur |
|
| **uploads(id_utilisateur)** → `utilisateurs(id)` | **SET NULL** | Fichier reste référencé sans l’auteur |
|
||||||
| **notifications(id_utilisateur)** → `utilisateurs(id)` | **CASCADE** | Notifications propres à l’utilisateur |
|
| **notifications(id_utilisateur)** → `utilisateurs(id)` | **CASCADE** | Notifications propres à l’utilisateur |
|
||||||
@@ -79,10 +77,8 @@ Documenter, de façon unique et partagée, les règles de suppression/mise à jo
|
|||||||
- `avenants_contrats.initie_par` → **SET NULL**
|
- `avenants_contrats.initie_par` → **SET NULL**
|
||||||
|
|
||||||
### Événements
|
### Événements
|
||||||
- `evenements.id_enfant` → **CASCADE**
|
- `absences_garde.id_placement` → **CASCADE**
|
||||||
- `evenements.id_am` → **SET NULL**
|
- `absences_garde.cree_par` → **SET NULL**
|
||||||
- `evenements.id_parent` → **SET NULL**
|
|
||||||
- `evenements.cree_par` → **SET NULL**
|
|
||||||
|
|
||||||
### Divers
|
### Divers
|
||||||
- `signalements_bugs.id_utilisateur` → **SET NULL**
|
- `signalements_bugs.id_utilisateur` → **SET NULL**
|
||||||
@@ -109,11 +105,11 @@ Documenter, de façon unique et partagée, les règles de suppression/mise à jo
|
|||||||
|
|
||||||
4. **Suppression d’un enfant**
|
4. **Suppression d’un enfant**
|
||||||
- Supprimer `enfants(id=childA)`
|
- Supprimer `enfants(id=childA)`
|
||||||
- Attendu : `enfants_parents` (CASCADE), `dossiers` du childA (CASCADE), `evenements` du childA (CASCADE).
|
- Attendu : `enfants_parents` (CASCADE), `dossiers` du childA (CASCADE), `absences_garde` des placements du childA (CASCADE via EAM).
|
||||||
|
|
||||||
5. **Suppression d’un utilisateur AM**
|
5. **Suppression d’un utilisateur AM**
|
||||||
- Supprimer `utilisateurs(id=amB)`
|
- Supprimer `utilisateurs(id=amB)`
|
||||||
- Attendu : `evenements.id_am` devient **NULL** (historique conservé).
|
- Attendu : absences liées via placement AM (CASCADE si le lien EAM est retiré).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
-- Ticket #193 — Back métier absences / congés / arrêt (périodes par placement)
|
||||||
|
-- Idempotent : safe à rejouer.
|
||||||
|
-- Remplace la table legacy `evenements` (mal conçue, non utilisée en API).
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
-- Enums
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'type_absence_garde_type') THEN
|
||||||
|
CREATE TYPE type_absence_garde_type AS ENUM (
|
||||||
|
'absence_enfant',
|
||||||
|
'conge_am',
|
||||||
|
'arret_maladie_am'
|
||||||
|
);
|
||||||
|
END IF;
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'statut_absence_garde_type') THEN
|
||||||
|
CREATE TYPE statut_absence_garde_type AS ENUM (
|
||||||
|
'en_attente',
|
||||||
|
'accepte',
|
||||||
|
'refuse'
|
||||||
|
);
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
-- Table absences_garde (1 ligne = 1 période)
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
CREATE TABLE IF NOT EXISTS absences_garde (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
id_placement UUID NOT NULL
|
||||||
|
REFERENCES enfants_assistantes_maternelles(id) ON DELETE CASCADE,
|
||||||
|
type type_absence_garde_type NOT NULL,
|
||||||
|
date_debut DATE NOT NULL,
|
||||||
|
date_fin DATE NOT NULL,
|
||||||
|
statut statut_absence_garde_type NOT NULL DEFAULT 'en_attente',
|
||||||
|
-- TTL purge : obligatoire ; pour statut=accepte utiliser 'infinity' (pas de purge métier)
|
||||||
|
expire_at TIMESTAMPTZ NOT NULL,
|
||||||
|
cree_par UUID REFERENCES utilisateurs(id) ON DELETE SET NULL,
|
||||||
|
id_card_instance UUID NULL,
|
||||||
|
motif TEXT,
|
||||||
|
cree_le TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||||
|
modifie_le TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||||
|
CONSTRAINT chk_absences_garde_dates CHECK (date_fin >= date_debut)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_absences_garde_placement_dates
|
||||||
|
ON absences_garde (id_placement, date_debut, date_fin);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_absences_garde_placement_type_statut
|
||||||
|
ON absences_garde (id_placement, type, statut);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_absences_garde_expire_at
|
||||||
|
ON absences_garde (expire_at)
|
||||||
|
WHERE statut IN ('en_attente', 'refuse');
|
||||||
|
|
||||||
|
COMMENT ON TABLE absences_garde IS
|
||||||
|
'Vérité métier des absences/congés/arrêts par couple AM↔enfant (placement). Les cartes collectent ; cette table stocke.';
|
||||||
|
COMMENT ON COLUMN absences_garde.expire_at IS
|
||||||
|
'Purge auto (job ultérieur) pour en_attente/refuse. accepte → infinity.';
|
||||||
|
COMMENT ON COLUMN absences_garde.id_card_instance IS
|
||||||
|
'Réf. carte de collecte (FK cards quand le module Cartes existera).';
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
-- Drop legacy evenements (+ enums si plus référencés)
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
DROP TABLE IF EXISTS evenements CASCADE;
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF EXISTS (SELECT 1 FROM pg_type WHERE typname = 'type_evenement_type')
|
||||||
|
AND NOT EXISTS (
|
||||||
|
SELECT 1 FROM information_schema.columns
|
||||||
|
WHERE udt_name = 'type_evenement_type'
|
||||||
|
) THEN
|
||||||
|
DROP TYPE type_evenement_type;
|
||||||
|
END IF;
|
||||||
|
IF EXISTS (SELECT 1 FROM pg_type WHERE typname = 'statut_evenement_type')
|
||||||
|
AND NOT EXISTS (
|
||||||
|
SELECT 1 FROM information_schema.columns
|
||||||
|
WHERE udt_name = 'statut_evenement_type'
|
||||||
|
) THEN
|
||||||
|
DROP TYPE statut_evenement_type;
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
@@ -161,23 +161,9 @@ VALUES (
|
|||||||
ON CONFLICT (id) DO NOTHING;
|
ON CONFLICT (id) DO NOTHING;
|
||||||
|
|
||||||
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
||||||
-- Événement (absence enfant)
|
-- Absences_garde : seeds quand placements EAM présents (API / ticket peuplement)
|
||||||
|
-- Legacy evenements supprimée (#193).
|
||||||
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
||||||
INSERT INTO evenements (id, type, id_enfant, id_am, id_parent, cree_par, date_debut, date_fin, commentaires, statut, urgence)
|
|
||||||
VALUES (
|
|
||||||
'e0000000-0000-0000-0000-000000000001',
|
|
||||||
'absence_enfant',
|
|
||||||
'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
|
|
||||||
'66666666-6666-6666-6666-666666666666',
|
|
||||||
'33333333-3333-3333-3333-333333333333',
|
|
||||||
'33333333-3333-3333-3333-333333333333',
|
|
||||||
'2025-09-12',
|
|
||||||
'2025-09-12',
|
|
||||||
'Enfant malade (rhume).',
|
|
||||||
'propose',
|
|
||||||
false
|
|
||||||
)
|
|
||||||
ON CONFLICT (id) DO NOTHING;
|
|
||||||
|
|
||||||
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
||||||
-- Upload (justificatif lié au dossier)
|
-- Upload (justificatif lié au dossier)
|
||||||
|
|||||||
@@ -79,12 +79,11 @@ LEFT JOIN avenants_contrats a ON a.id_contrat = c.id
|
|||||||
GROUP BY c.id, c.id_dossier, c.statut
|
GROUP BY c.id, c.id_dossier, c.statut
|
||||||
ORDER BY c.cree_le DESC;
|
ORDER BY c.cree_le DESC;
|
||||||
|
|
||||||
\echo '=== 9) Evénements par enfant (30 derniers jours) =============='
|
\echo '=== 9) Absences_garde (30 derniers jours) ====================='
|
||||||
SELECT ev.id, ev.type, ev.id_enfant, e.prenom AS enfant, ev.date_debut, ev.date_fin, ev.statut
|
SELECT ag.id, ag.type, ag.id_placement, ag.date_debut, ag.date_fin, ag.statut, ag.expire_at
|
||||||
FROM evenements ev
|
FROM absences_garde ag
|
||||||
JOIN enfants e ON e.id = ev.id_enfant
|
WHERE ag.date_debut >= (NOW()::date - INTERVAL '30 days')
|
||||||
WHERE ev.date_debut >= (NOW()::date - INTERVAL '30 days')
|
ORDER BY ag.date_debut DESC;
|
||||||
ORDER BY ev.date_debut DESC;
|
|
||||||
|
|
||||||
\echo '=== 10) Uploads & notifications récentes ======================='
|
\echo '=== 10) Uploads & notifications récentes ======================='
|
||||||
SELECT u.courriel, up.fichier_url, up.type_fichier, up.cree_le
|
SELECT u.courriel, up.fichier_url, up.type_fichier, up.cree_le
|
||||||
@@ -135,11 +134,11 @@ FROM avenants_contrats a
|
|||||||
LEFT JOIN contrats c ON c.id = a.id_contrat
|
LEFT JOIN contrats c ON c.id = a.id_contrat
|
||||||
WHERE c.id IS NULL;
|
WHERE c.id IS NULL;
|
||||||
|
|
||||||
-- Evénements sans enfant
|
-- Absences sans placement
|
||||||
SELECT ev.*
|
SELECT ag.*
|
||||||
FROM evenements ev
|
FROM absences_garde ag
|
||||||
LEFT JOIN enfants e ON e.id = ev.id_enfant
|
LEFT JOIN enfants_assistantes_maternelles eam ON eam.id = ag.id_placement
|
||||||
WHERE e.id IS NULL;
|
WHERE eam.id IS NULL;
|
||||||
|
|
||||||
\echo '=== 13) Performance : EXPLAIN sur requêtes clés ==============='
|
\echo '=== 13) Performance : EXPLAIN sur requêtes clés ==============='
|
||||||
|
|
||||||
@@ -151,12 +150,12 @@ WHERE m.id_dossier = 'dddddddd-dddd-dddd-dddd-dddddddddddd'
|
|||||||
ORDER BY m.cree_le DESC
|
ORDER BY m.cree_le DESC
|
||||||
LIMIT 20;
|
LIMIT 20;
|
||||||
|
|
||||||
-- Evénements par enfant et période (idx_evenements_id_enfant_date_debut)
|
-- Absences par placement et période (idx_absences_garde_placement_dates)
|
||||||
EXPLAIN ANALYZE
|
EXPLAIN ANALYZE
|
||||||
SELECT ev.*
|
SELECT ag.*
|
||||||
FROM evenements ev
|
FROM absences_garde ag
|
||||||
WHERE ev.id_enfant = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'
|
WHERE ag.id_placement IS NOT NULL
|
||||||
AND ev.date_debut >= '2025-01-01';
|
AND ag.date_debut >= '2025-01-01';
|
||||||
|
|
||||||
-- Notifications non lues (idx_notifications_user_lu_cree_le)
|
-- Notifications non lues (idx_notifications_user_lu_cree_le)
|
||||||
EXPLAIN ANALYZE
|
EXPLAIN ANALYZE
|
||||||
@@ -199,7 +198,7 @@ SELECT
|
|||||||
(SELECT COUNT(*) FROM messages) AS nb_messages,
|
(SELECT COUNT(*) FROM messages) AS nb_messages,
|
||||||
(SELECT COUNT(*) FROM contrats) AS nb_contrats,
|
(SELECT COUNT(*) FROM contrats) AS nb_contrats,
|
||||||
(SELECT COUNT(*) FROM avenants_contrats) AS nb_avenants,
|
(SELECT COUNT(*) FROM avenants_contrats) AS nb_avenants,
|
||||||
(SELECT COUNT(*) FROM evenements) AS nb_evenements,
|
(SELECT COUNT(*) FROM absences_garde) AS nb_absences_garde,
|
||||||
(SELECT COUNT(*) FROM uploads) AS nb_uploads,
|
(SELECT COUNT(*) FROM uploads) AS nb_uploads,
|
||||||
(SELECT COUNT(*) FROM notifications) AS nb_notifications,
|
(SELECT COUNT(*) FROM notifications) AS nb_notifications,
|
||||||
(SELECT COUNT(*) FROM validations) AS nb_validations;
|
(SELECT COUNT(*) FROM validations) AS nb_validations;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# 📋 Décisions Projet - P'titsPas
|
# 📋 Décisions Projet - P'titsPas
|
||||||
|
|
||||||
**Version** : 1.2
|
**Version** : 1.3
|
||||||
**Date** : 16 Juin 2026
|
**Date** : 24 Septembre 2026
|
||||||
**Auteur** : Équipe PtitsPas
|
**Auteur** : Équipe PtitsPas
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -465,19 +465,34 @@ docs/
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 26. Branches Git
|
### 26. Branches Git + merge squash (norme)
|
||||||
|
|
||||||
**Décision** : ✅ **Stratégie simple : master + feature branches**
|
**Décision** : ✅ **`develop` + `master` + `feature/*`, merges en squash**
|
||||||
|
|
||||||
**Justification** :
|
**Justification** :
|
||||||
- Simplicité (petite équipe)
|
- Simplicité (petite équipe)
|
||||||
- Flexibilité
|
- Historique lisible sur `develop` / `master` (1 commit = 1 ticket)
|
||||||
|
- Déploiement prod uniquement depuis `master`
|
||||||
|
|
||||||
**Branches** :
|
**Branches** :
|
||||||
- `master` : Production
|
- `master` : Production (déploiement auto)
|
||||||
- `archive/*` : Archives (ex: maquette initiale)
|
- `develop` : Intégration / recette
|
||||||
- `migration/*` : Migrations (ex: intégration YNOV)
|
- `feature/*` : Ticket en cours (depuis `develop`)
|
||||||
- `feature/*` : Nouvelles fonctionnalités
|
- `archive/*`, `migration/*` : Archives / migrations ponctuelles
|
||||||
|
|
||||||
|
**Flux (norme à partir de #169+)** :
|
||||||
|
1. Branche `feature/N-…` depuis `develop`
|
||||||
|
2. PR **feature → `develop`** : merge **squash** (`Do: squash` côté Gitea)
|
||||||
|
3. Quand un lot est prêt : PR **`develop` → `master`** : merge **squash** également
|
||||||
|
4. Message squash : `feat(#N): …` / `fix(#N): …` + `Closes #N` si applicable
|
||||||
|
|
||||||
|
**Exception** : les merges `--no-ff` déjà poussés (ex. #167, #168) restent tels quels — pas de réécriture d’historique.
|
||||||
|
|
||||||
|
**API Gitea** (rappel) :
|
||||||
|
```http
|
||||||
|
POST /repos/jmartin/petitspas/pulls/{index}/merge
|
||||||
|
{"Do":"squash","MergeTitleField":"feat(#N): …","MergeMessageField":"Closes #N"}
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -116,10 +116,17 @@ curl -s -H "Authorization: token $GITEA_TOKEN" \
|
|||||||
"https://git.ptits-pas.fr/api/v1/repos/jmartin/petitspas/pulls?state=open" | jq .
|
"https://git.ptits-pas.fr/api/v1/repos/jmartin/petitspas/pulls?state=open" | jq .
|
||||||
|
|
||||||
# Créer une PR (head = branche source, base = branche cible)
|
# Créer une PR (head = branche source, base = branche cible)
|
||||||
|
# Norme : feature/* → develop, puis develop → master
|
||||||
curl -s -X POST -H "Authorization: token $GITEA_TOKEN" \
|
curl -s -X POST -H "Authorization: token $GITEA_TOKEN" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{"head":"develop","base":"master","title":"Titre de la PR"}' \
|
-d '{"head":"feature/XX-nom","base":"develop","title":"feat(#XX): Titre","body":"Closes #XX"}' \
|
||||||
"https://git.ptits-pas.fr/api/v1/repos/jmartin/petitspas/pulls"
|
"https://git.ptits-pas.fr/api/v1/repos/jmartin/petitspas/pulls"
|
||||||
|
|
||||||
|
# Merger en squash (norme — voir 24_DECISIONS-PROJET.md §26)
|
||||||
|
curl -s -X POST -H "Authorization: token $GITEA_TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"Do":"squash","MergeTitleField":"feat(#XX): Titre","MergeMessageField":"Closes #XX"}' \
|
||||||
|
"https://git.ptits-pas.fr/api/v1/repos/jmartin/petitspas/pulls/{index}/merge"
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3.4 Branches
|
### 3.4 Branches
|
||||||
|
|||||||
@@ -194,6 +194,9 @@ frontend/lib/
|
|||||||
|
|
||||||
## Workflow Git
|
## Workflow Git
|
||||||
|
|
||||||
|
Norme projet : **squash merge** (voir [24_DECISIONS-PROJET.md](./24_DECISIONS-PROJET.md) §26).
|
||||||
|
Cible habituelle : `feature/*` → `develop` ; puis `develop` → `master` quand le lot est prêt.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1. Créer une branche feature
|
# 1. Créer une branche feature
|
||||||
git checkout develop
|
git checkout develop
|
||||||
@@ -204,15 +207,22 @@ git checkout -b feature/XX-nom-ticket
|
|||||||
git add .
|
git add .
|
||||||
git commit -m "feat(#XX): Description courte"
|
git commit -m "feat(#XX): Description courte"
|
||||||
|
|
||||||
# 3. Pousser et créer PR
|
# 3. Pousser et créer PR vers develop
|
||||||
git push -u origin feature/XX-nom-ticket
|
git push -u origin feature/XX-nom-ticket
|
||||||
|
|
||||||
# 4. Créer PR vers master via Gitea ou API
|
# 4. Créer PR (base = develop)
|
||||||
curl -X POST \
|
curl -X POST \
|
||||||
-H "Authorization: token giteabu_1796c6aace0e2ef7e4fdb49cdc3bc1bf8ee31fbc" \
|
-H "Authorization: token $GITEA_TOKEN" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{"title":"feat(#XX): Titre","body":"Description\n\nCloses #XX","head":"feature/XX-nom-ticket","base":"master"}' \
|
-d '{"title":"feat(#XX): Titre","body":"Description\n\nCloses #XX","head":"feature/XX-nom-ticket","base":"develop"}' \
|
||||||
"https://git.ptits-pas.fr/api/v1/repos/jmartin/petitspas/pulls"
|
"https://git.ptits-pas.fr/api/v1/repos/jmartin/petitspas/pulls"
|
||||||
|
|
||||||
|
# 5. Merger en squash (pas merge commit)
|
||||||
|
curl -X POST \
|
||||||
|
-H "Authorization: token $GITEA_TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"Do":"squash","MergeTitleField":"feat(#XX): Titre","MergeMessageField":"Closes #XX"}' \
|
||||||
|
"https://git.ptits-pas.fr/api/v1/repos/jmartin/petitspas/pulls/{index}/merge"
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
Reference in New Issue
Block a user