SyncModels.kt
404 lignes · 11549 octets
package fr.ebii.card2vcf.sync import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonNamingStrategy /** JSON config partagée : snake_case serveur Projectiaon, champs inconnus ignorés. */ @OptIn(ExperimentalSerializationApi::class) val syncJson: Json = Json { ignoreUnknownKeys = true namingStrategy = JsonNamingStrategy.SnakeCase encodeDefaults = true } // ---- Auth clé ---- @Serializable data class AuthCleRequest( val nom: String, val motDePasse: String, ) @Serializable data class AuthCleResponse( val nom: String, val cleChiffree: String, val sel: String, val kdf: String, val cipher: String, ) // ---- Sync status / pull ---- @Serializable data class SyncChanges( val contacts: Int = 0, val entreprises: Int = 0, val projets: Int = 0, val taches: Int = 0, val interactions: Int = 0, val rdv: Int = 0, val reservations: Int = 0, val indisponibilites: Int = 0, val tombstones: Int = 0, ) @Serializable data class SyncStatusResponse( val serverTime: String, val changes: SyncChanges, val total: Int, ) @Serializable data class SyncPullResponse( val serverTime: String, val contacts: List<ContactDto> = emptyList(), val entreprises: List<EntrepriseDto> = emptyList(), val projets: List<ProjetDto> = emptyList(), val taches: List<TacheSyncDto> = emptyList(), val interactions: List<InteractionDto> = emptyList(), val rdv: List<RendezVousDto> = emptyList(), val reservations: List<ReservationDto> = emptyList(), val indisponibilites: List<IndisponibiliteDto> = emptyList(), val tombstones: List<TombstoneDto> = emptyList(), val workflows: List<WorkflowDto> = emptyList(), /** Notes markdown des projets ; défaut `emptyList()` = compat anciens serveurs sans ce champ. */ val notes: List<NoteProjetDto> = emptyList(), ) @Serializable data class TombstoneDto( @SerialName("type") val entityType: String, val id: String, val projetId: String? = null, val cibleType: String? = null, val cibleId: String? = null, val utilisateur: String? = null, val supprimeLe: String, ) // ---- Entités sync (champs minimaux pour LWW / merge) ---- @Serializable data class ContactDto( val id: String, val prenom: String = "", val nom: String = "", val entrepriseId: String? = null, val fonction: String = "", val statut: String = "prospect", val etape: String = "nouveau", val tags: List<String> = emptyList(), val creePar: String = "", val creeLe: String, val misAJourLe: String? = null, /** Nom de fichier serveur (`carte.jpg`), pas les octets. */ val carteVisite: String? = null, /** Nom de fichier serveur (`photo.jpg`), pas les octets. */ val photo: String? = null, ) @Serializable data class EntrepriseDto( val id: String, val nom: String, val secteur: String = "", val creePar: String = "", val creeLe: String, val misAJourLe: String? = null, ) @Serializable data class MembreProjetDto( val utilisateur: String, val niveau: String = "lecteur", ) @Serializable data class ProjetDto( val id: String, val nom: String, val description: String = "", val workflowId: String, val creePar: String = "", val creeLe: String, val membres: List<MembreProjetDto> = emptyList(), /** Le projet utilise-t-il la planification ? Défaut faux = serveur antérieur. */ val planification: Boolean = false, val echeance: String? = null, /** 5 = lun-ven, 6 = lun-sam, 7 = tous les jours. */ val joursOuvres: Int = 7, val misAJourLe: String? = null, ) /** Élément de checklist d'une tâche (miroir Rust `SousTache`). */ @Serializable data class SousTacheDto( val id: String, val titre: String, val fait: Boolean = false, ) /** Tâche aplatie : `projet_id` + champs Tache au même niveau (miroir Rust `TacheSync`). */ @Serializable data class TacheSyncDto( val projetId: String, val id: String, val titre: String, val description: String = "", val colonneId: String, val ordre: Int = 0, val auteur: String = "", val creeLe: String, val assigneA: String? = null, /** Premier jour planifié, `AAAA-MM-JJ`. */ val debut: String? = null, /** Durée en jours **ouvrés** selon le rythme du projet. */ val dureeJours: Int? = null, val etiquette: String? = null, /** Transportés et stockés pour ne pas les perdre à l'écriture, non éditables. */ val dependDe: List<String> = emptyList(), val parentId: String? = null, val sousTaches: List<SousTacheDto> = emptyList(), val misAJourLe: String? = null, ) @Serializable data class InteractionDto( val id: String, val contactId: String, val typeInteraction: String = "note", val sujet: String = "", val description: String = "", val creePar: String = "", val creeLe: String, val misAJourLe: String? = null, /** Nom de fichier audio côté serveur (ex. `interaction_uuid.wav`). */ val pieceJointe: String? = null, /** Statut de transcription : "en_attente" | "terminee" | "echec" | null. */ val transcription: String? = null, /** Message d'erreur de transcription côté serveur (null si pas d'erreur). */ val transcriptionErreur: String? = null, ) @Serializable data class ColonneDto( val id: String, val nom: String, val ordre: Int = 0, ) /** Cible d'une réservation/indisponibilité (miroir enum Rust `CibleRessource`, tag `type` + `id`). */ @Serializable data class CibleRessourceDto( val type: String, val id: String, ) @Serializable data class RendezVousDto( val id: String, val titre: String = "", val description: String = "", val utilisateur: String = "", val contactIds: List<String> = emptyList(), val lieu: String = "", val debut: String, val fin: String, val projetId: String? = null, val creePar: String = "", val creeLe: String, val misAJourLe: String? = null, ) @Serializable data class ReservationDto( val id: String, val cible: CibleRessourceDto, val debut: String, val fin: String, val motif: String = "", val projetId: String? = null, val rdvId: String? = null, val statut: String = "active", val reservePar: String = "", val creeLe: String, val misAJourLe: String? = null, ) @Serializable data class IndisponibiliteDto( val id: String, val cible: CibleRessourceDto, val nature: String, val debut: String, val fin: String, val commentaire: String = "", val creePar: String = "", val creeLe: String, val misAJourLe: String? = null, ) /** Note markdown d'un projet (contrat P1-S1 / P1-A2 / P2-A3). */ @Serializable data class NoteProjetDto( val id: String, val projetId: String, val titre: String, val contenu: String, val auteur: String = "", val creeLe: String, val majLe: String? = null, /** Nom de fichier audio côté serveur (ex. `note_uuid.wav`), null si aucun audio. */ val audio: String? = null, /** Statut de transcription : "en_attente" | "terminee" | "echec" | null. */ val transcription: String? = null, /** Message d'erreur de transcription côté serveur (null si pas d'erreur). */ val transcriptionErreur: String? = null, ) /** Ressource catalogue allégée (salle/matériel/véhicule) : champs communs uniquement. */ @Serializable data class RessourceItemDto( val id: String, val nom: String, val description: String = "", val lieu: String = "", val actif: Boolean = true, ) @Serializable data class RessourcesCatalogueDto( val salles: List<RessourceItemDto> = emptyList(), val materiels: List<RessourceItemDto> = emptyList(), val vehicules: List<RessourceItemDto> = emptyList(), ) @Serializable data class WorkflowDto( val id: String, val nom: String, val description: String = "", val colonnes: List<ColonneDto> = emptyList(), val creePar: String = "", val creeLe: String, ) // ---- Requêtes de mutation locales (payload des SyncOp, miroir des `*Input` serveur) ---- @Serializable data class CreateTacheRequest( val titre: String, val description: String = "", val colonneId: String = "", val assigneA: String? = null, val debut: String? = null, val dureeJours: Int? = null, val etiquette: String? = null, ) /** * Mise à jour d'une tâche. * * Le serveur applique une sémantique partielle : un champ **absent** du JSON * est laissé tel quel, `null` l'efface. Cette classe ne déclare donc que ce que * le téléphone édite — sous-tâches, dépendances et regroupement en sont * volontairement exclus pour ne pas être écrasés. * * `syncJson` encode les valeurs par défaut, y compris les nuls : vider le champ * date dans le dialogue efface bien la date côté serveur. */ @Serializable data class UpdateTacheRequest( val titre: String, val description: String = "", val assigneA: String? = null, @SerialName("assigne_a_pose") val assigneAPose: Boolean = true, val debut: String? = null, val dureeJours: Int? = null, val etiquette: String? = null, ) @Serializable data class MoveTacheRequest( val colonneId: String, ) @Serializable data class CreateInteractionRequest( val sujet: String, val description: String = "", val typeInteraction: String = "note", val demandeTranscription: Boolean = false, ) @Serializable data class ContactValeurDto( val valeur: String, val categorie: String = "pro", ) /** Payload create/update contact (miroir serveur `ContactInput`). */ @Serializable data class CreateContactRequest( val prenom: String = "", val nom: String = "", val entrepriseId: String? = null, val entrepriseNom: String? = null, val fonction: String = "", val emails: List<ContactValeurDto> = emptyList(), val telephones: List<ContactValeurDto> = emptyList(), val notes: String = "", val statut: String = "prospect", val etape: String = "nouveau", val tags: List<String> = emptyList(), ) /** Payload create projet (miroir serveur `ProjetInput`, body `/api/projets`). */ @Serializable data class CreateProjetRequest( val nom: String, val description: String = "", val workflowId: String, ) /** Payload create/update RDV (miroir serveur, body `/api/rdv`). */ @Serializable data class RdvUpsertRequest( val titre: String = "", val description: String = "", val lieu: String = "", val debut: String, val fin: String, val contactIds: List<String> = emptyList(), val projetId: String? = null, ) /** Payload create/update réservation (miroir serveur, body `/api/ressources/:genre/:id/reservations`). */ @Serializable data class ReservationUpsertRequest( val debut: String, val fin: String, val motif: String = "", val projetId: String? = null, val rdvId: String? = null, ) /** Payload création note projet (body `POST /api/projets/:id/notes`). */ @Serializable data class CreateNoteProjetRequest( val titre: String, val contenu: String = "", val demandeTranscription: Boolean = false, ) /** Payload mise à jour note projet (body `PUT /api/projets/:id/notes/:nid`). */ @Serializable data class UpdateNoteProjetRequest( val titre: String, val contenu: String = "", )
GitRust