Mise en place d'un installeur pour la version bureau sans passer par Docker.
Some checks failed
E2E Tests / e2e (push) Has been cancelled
Build & Push Images / build (brain) (push) Successful in 1m25s
Build & Push Images / build (core) (push) Successful in 2m55s
Build & Push Images / build (web) (push) Successful in 1m49s
Build & Push Images / build-switcher (push) Successful in 39s

Permet d'utiliser Loremind sans passer par Docker et sans lancer tous les conteneurs
Passage en v0.15.0
This commit is contained in:
2026-06-17 18:04:33 +02:00
parent f1c68634f7
commit 48baa08cfb
26 changed files with 1832 additions and 20 deletions

View File

@@ -0,0 +1,86 @@
# ============================================================================
# Profil "local" — mode local-first (application de bureau, sans Docker)
# ============================================================================
# Active via : --spring.profiles.active=local (ou SPRING_PROFILES_ACTIVE=local)
#
# Objectif : faire tourner le Core sur le poste de l'utilisateur SANS aucune
# infrastructure externe (ni Postgres, ni MinIO, ni Docker). Toutes les donnees
# vivent sous loremind.home (defaut : ~/.loremind).
#
# Surcharge UNIQUEMENT ce qui differe du profil par defaut (application.properties) :
# le reste (timeouts, multipart, licensing...) est herite tel quel.
# --- Base de donnees : H2 en mode fichier, compatibilite PostgreSQL ---------
# MODE=PostgreSQL : H2 interprete le SQL PostgreSQL -> les MEMES migrations
# Flyway (ecrites en SQL Postgres) tournent ici comme sur la prod Postgres.
# Aligne aussi la casse des identifiants (minuscules, comme PG).
# DB_CLOSE_ON_EXIT=FALSE : Spring/Hikari pilote la fermeture (pas le shutdown
# hook H2). AUTO_SERVER volontairement absent (interdit avec DB_CLOSE_ON_EXIT,
# et inutile pour un process unique).
# NON_KEYWORDS=VALUE : PostgreSQL accepte `value` comme nom de colonne non-quote
# (colonne de playthrough_flag), mais H2 le reserve par defaut -> on le relache
# pour que le baseline SQL Postgres (non-quote) passe aussi sur H2. Ajouter
# d'autres mots ici si une migration future utilise un identifiant reserve H2.
spring.datasource.url=jdbc:h2:file:${loremind.home}/db/loremind;MODE=PostgreSQL;DB_CLOSE_ON_EXIT=FALSE;NON_KEYWORDS=VALUE
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.h2.Driver
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
# Schema gere par Flyway (cf. application.properties) ; Hibernate valide seulement.
spring.jpa.hibernate.ddl-auto=validate
spring.jpa.show-sql=false
# --- Stockage des images : systeme de fichiers -----------------------------
storage.backend=filesystem
storage.filesystem.path=${loremind.home}/images
# --- Brain : service IA Python lance en sidecar sur le poste ---------------
brain.base-url=http://localhost:8000
# Secret partage Core <-> Brain. En local il n'a pas de role securitaire fort
# (tout est sur localhost, mono-utilisateur) mais le Brain est fail-closed :
# il DOIT etre defini des deux cotes. Le lanceur de sidecar (BrainSidecar)
# propage cette meme valeur au process Brain via la variable BRAIN_INTERNAL_SECRET.
brain.internal-secret=${BRAIN_INTERNAL_SECRET:loremind-local-secret}
# --- Brain en sidecar (lance par le Core) ----------------------------------
# Le Core demarre lui-meme le process Brain (pas de Docker en local).
brain.sidecar.enabled=${BRAIN_SIDECAR_ENABLED:true}
# Le Brain ecrit son dossier data/ (index vectoriel, settings) sous ce dossier.
brain.sidecar.working-dir=${loremind.home}/brain
# Commande de lancement. VIDE par defaut : le dev qui lance le Brain a la main
# n'est pas perturbe. Le packaging (jpackage) la renseigne vers l'exe PyInstaller.
# - Empaquete : chemin de l'exe, ex. C:/Program Files/LoreMind/brain/loremind-brain.exe
# - Dev : python,-m,uvicorn,app.main:app,--host,127.0.0.1,--port,8000
# (avec brain.sidecar.working-dir pointant sur le dossier brain/)
brain.sidecar.command=${BRAIN_SIDECAR_COMMAND:}
# --- Admin (localhost uniquement) ------------------------------------------
# Application mono-utilisateur sur le poste : l'utilisateur EST l'admin.
# Identifiants par defaut surchargables ; non exposes hors de la machine.
admin.username=${ADMIN_USERNAME:admin}
admin.password=${ADMIN_PASSWORD:admin}
# --- Front servi par le Core (meme origine) --------------------------------
# Le front Angular est servi en statique par le Core (cf. LocalWebConfig),
# donc tout est sur http://localhost:8080 : CORS sans objet, mais on autorise
# l'origine locale par securite si un dev lance Angular separement.
spring.web.cors.allowed-origins=http://localhost:8080,http://localhost:4200
# Mode demo desactive (instance personnelle complete).
app.demo-mode=false
# --- Licensing / Patreon : desactive en mode bureau ------------------------
# Le gating par IMAGE Docker (canal beta tire d'un registry prive) n'a aucun
# sens hors Docker. On coupe toute la machinerie : daemon de refresh no-op,
# /api/license/* renvoie enabled=false, et l'UI masque la section Patreon.
# La distribution beta desktop se fait par installeur beta via Patreon, pas
# par une connexion in-app.
licensing.enabled=false
# --- Verification des mises a jour (bureau) --------------------------------
# Interroge l'API GitHub Releases (derniere release STABLE) au demarrage ; si
# une version plus recente existe, l'icone systray le signale (bulle + item
# « Telecharger »). Pas de mise a jour auto : l'utilisateur telecharge et lance
# le nouvel installeur. Mettre a false pour desactiver toute requete sortante.
desktop.update.enabled=${DESKTOP_UPDATE_CHECK:true}
desktop.update.releases-api-url=https://api.github.com/repos/IGMLcreation/LoreMind/releases/latest

View File

@@ -22,10 +22,26 @@ spring.datasource.driver-class-name=org.postgresql.Driver
# Configuration JPA / Hibernate
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=update
# Le schema est desormais gere par Flyway (migrations versionnees), plus par
# Hibernate. ddl-auto=validate : Hibernate ne MODIFIE plus le schema, il verifie
# juste au demarrage que les entites correspondent au schema cree par Flyway
# (filet de securite contre les derives entites<->migrations).
spring.jpa.hibernate.ddl-auto=validate
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
# ============================================================================
# Flyway : migrations de schema versionnees (src/main/resources/db/migration).
# ============================================================================
# baseline-on-migrate : sur une base EXISTANTE (prod deja peuplee, sans table
# d'historique Flyway), Flyway l'estampille a la version baseline SANS rejouer
# V1 -> les donnees existantes sont preservees. Sur une base VIDE (install
# neuve), Flyway joue V1__baseline.sql normalement pour creer le schema.
spring.flyway.enabled=true
spring.flyway.baseline-on-migrate=true
spring.flyway.baseline-version=1
spring.flyway.baseline-description=Baseline (schema pre-Flyway, gere jusque-la par ddl-auto)
# Configuration CORS pour autoriser le Frontend Angular
spring.web.cors.allowed-origins=${CORS_ALLOWED_ORIGINS:http://localhost:4200}
spring.web.cors.allowed-methods=GET,POST,PUT,DELETE,OPTIONS
@@ -48,6 +64,17 @@ brain.internal-secret=${BRAIN_INTERNAL_SECRET:}
admin.username=${ADMIN_USERNAME:admin}
admin.password=${ADMIN_PASSWORD:}
# Repertoire de base de l'instance (donnees locales hors Docker).
# Utilise par le profil "local" (H2 fichier, stockage images filesystem...).
loremind.home=${LOREMIND_HOME:${user.home}/.loremind}
# Backend de stockage des binaires d'images (port ImageStorage) :
# - minio : MinIO/S3 (defaut — deploiement Docker/serveur)
# - filesystem : systeme de fichiers local (mode local-first / jpackage)
storage.backend=${STORAGE_BACKEND:minio}
# Racine du stockage filesystem (ignoree si storage.backend=minio).
storage.filesystem.path=${STORAGE_FS_PATH:${loremind.home}/images}
# Configuration MinIO (Shared Kernel images - Object Storage)
# Le bucket est cree automatiquement par le service minio-init (docker-compose up -d).
# Defaults OK pour dev local ; overrides en prod via env.

View File

@@ -0,0 +1,424 @@
create table arcs (
"order" integer not null,
campaign_id bigint not null,
created_at timestamp(6) not null,
id bigint generated by default as identity,
updated_at timestamp(6) not null,
type varchar(16) default 'LINEAR' not null check (type in ('LINEAR','HUB')),
description TEXT,
gm_notes TEXT,
icon varchar(255),
illustration_image_ids TEXT,
map_image_ids TEXT,
name varchar(255) not null,
related_page_ids TEXT,
resolution TEXT,
rewards TEXT,
stakes TEXT,
themes TEXT,
primary key (id)
);
create table campaigns (
arcs_count integer not null,
created_at timestamp(6) not null,
id bigint generated by default as identity,
updated_at timestamp(6) not null,
description TEXT,
game_system_id varchar(255),
lore_id varchar(255),
name varchar(255) not null,
primary key (id)
);
create table catalog_items (
position integer not null,
catalog_id bigint not null,
id bigint generated by default as identity,
price varchar(64),
category varchar(128),
description TEXT,
name varchar(255) not null,
primary key (id)
);
create table chapters (
"order" integer not null,
arc_id bigint not null,
created_at timestamp(6) not null,
id bigint generated by default as identity,
updated_at timestamp(6) not null,
description TEXT,
gm_notes TEXT,
icon varchar(255),
illustration_image_ids TEXT,
map_image_ids TEXT,
name varchar(255) not null,
narrative_stakes TEXT,
player_objectives TEXT,
prerequisites TEXT,
related_page_ids TEXT,
primary key (id)
);
create table characters (
"order" integer not null,
campaign_id bigint,
created_at timestamp(6) not null,
id bigint generated by default as identity,
playthrough_id bigint,
updated_at timestamp(6) not null,
field_values TEXT,
header_image_id varchar(255),
image_values TEXT,
key_value_values TEXT,
name varchar(255) not null,
portrait_image_id varchar(255),
primary key (id)
);
create table conversation_messages (
conversation_id bigint not null,
created_at timestamp(6) not null,
id bigint generated by default as identity,
role varchar(16) not null,
content TEXT not null,
primary key (id)
);
create table conversations (
created_at timestamp(6) not null,
id bigint generated by default as identity,
updated_at timestamp(6) not null,
campaign_id varchar(255),
entity_id varchar(255),
entity_type varchar(255),
lore_id varchar(255),
title varchar(255) not null,
primary key (id)
);
create table enemies (
"order" integer not null,
campaign_id bigint not null,
created_at timestamp(6) not null,
id bigint generated by default as identity,
updated_at timestamp(6) not null,
field_values TEXT,
folder varchar(255),
header_image_id varchar(255),
image_values TEXT,
key_value_values TEXT,
level varchar(255),
name varchar(255) not null,
portrait_image_id varchar(255),
primary key (id)
);
create table game_systems (
is_public boolean not null,
created_at timestamp(6) not null,
id bigint generated by default as identity,
updated_at timestamp(6) not null,
author varchar(255),
character_template TEXT,
description TEXT,
enemy_template TEXT,
name varchar(255) not null,
npc_template TEXT,
rules_markdown TEXT,
primary key (id)
);
create table images (
id bigint generated by default as identity,
size_bytes bigint not null,
uploaded_at timestamp(6) not null,
content_type varchar(255) not null,
filename varchar(255) not null,
storage_key varchar(255) not null unique,
primary key (id)
);
create table item_catalogs (
"order" integer not null,
campaign_id bigint not null,
created_at timestamp(6) not null,
id bigint generated by default as identity,
updated_at timestamp(6) not null,
icon varchar(64),
description TEXT,
name varchar(255) not null,
primary key (id)
);
create table licenses (
beta_channel_enabled boolean not null,
last_refresh_succeeded boolean not null,
created_at timestamp(6) with time zone not null,
expires_at timestamp(6) with time zone not null,
issued_at timestamp(6) with time zone not null,
last_refresh_attempt_at timestamp(6) with time zone,
updated_at timestamp(6) with time zone not null,
id varchar(255) not null,
instance_id varchar(255) not null,
patreon_user_id varchar(255) not null,
raw_jwt TEXT not null,
tier_id varchar(255) not null,
primary key (id)
);
create table lore_nodes (
created_at timestamp(6) not null,
id bigint generated by default as identity,
lore_id bigint not null,
parent_id bigint,
updated_at timestamp(6) not null,
icon varchar(64),
name varchar(255) not null,
primary key (id)
);
create table lores (
node_count integer not null,
page_count integer not null,
created_at timestamp(6) not null,
id bigint generated by default as identity,
updated_at timestamp(6) not null,
description TEXT,
name varchar(255) not null,
primary key (id)
);
create table notebook_messages (
archived_at timestamp(6),
created_at timestamp(6) not null,
id bigint generated by default as identity,
notebook_id bigint not null,
role varchar(16) not null,
content TEXT not null,
primary key (id)
);
create table notebook_sources (
chunk_count integer not null,
page_count integer not null,
created_at timestamp(6) not null,
id bigint generated by default as identity,
notebook_id bigint not null,
status varchar(16) not null,
filename varchar(255) not null,
primary key (id)
);
create table notebooks (
campaign_id bigint not null,
created_at timestamp(6) not null,
id bigint generated by default as identity,
updated_at timestamp(6) not null,
name varchar(255) not null,
primary key (id)
);
create table npcs (
"order" integer not null,
campaign_id bigint not null,
created_at timestamp(6) not null,
id bigint generated by default as identity,
updated_at timestamp(6) not null,
field_values TEXT,
folder varchar(255),
header_image_id varchar(255),
image_values TEXT,
key_value_values TEXT,
name varchar(255) not null,
portrait_image_id varchar(255),
related_page_ids TEXT,
primary key (id)
);
create table pages (
created_at timestamp(6) not null,
id bigint generated by default as identity,
lore_id bigint not null,
node_id bigint not null,
template_id bigint,
updated_at timestamp(6) not null,
image_values_json TEXT,
key_value_values TEXT,
notes TEXT,
related_page_ids TEXT,
table_values TEXT,
tags TEXT,
title varchar(255) not null,
values_json TEXT,
primary key (id)
);
create table playthrough_flag (
value boolean not null,
id bigint generated by default as identity,
playthrough_id bigint not null,
name varchar(128) not null,
primary key (id),
constraint uk_playthrough_flag_name unique (playthrough_id, name)
);
create table playthroughs (
campaign_id bigint not null,
created_at timestamp(6) not null,
id bigint generated by default as identity,
updated_at timestamp(6) not null,
description TEXT,
name varchar(255) not null,
primary key (id)
);
create table quest_progression (
chapter_id bigint not null,
id bigint generated by default as identity,
playthrough_id bigint not null,
status varchar(16) not null check (status in ('NOT_STARTED','IN_PROGRESS','COMPLETED')),
primary key (id),
constraint uk_quest_progression_unique unique (playthrough_id, chapter_id)
);
create table random_table_entries (
max_roll integer not null,
min_roll integer not null,
position integer not null,
id bigint generated by default as identity,
random_table_id bigint not null,
detail TEXT,
label varchar(255) not null,
primary key (id)
);
create table random_tables (
"order" integer not null,
campaign_id bigint not null,
created_at timestamp(6) not null,
id bigint generated by default as identity,
updated_at timestamp(6) not null,
dice_formula varchar(32) not null,
icon varchar(64),
description TEXT,
name varchar(255) not null,
primary key (id)
);
create table scenes (
"order" integer not null,
chapter_id bigint not null,
created_at timestamp(6) not null,
id bigint generated by default as identity,
updated_at timestamp(6) not null,
atmosphere TEXT,
branches TEXT,
choices_consequences TEXT,
combat_difficulty TEXT,
description TEXT,
enemies TEXT,
enemy_ids TEXT,
gm_secret_notes TEXT,
icon varchar(255),
illustration_image_ids TEXT,
location TEXT,
map_image_ids TEXT,
name varchar(255) not null,
player_narration TEXT,
related_page_ids TEXT,
rooms TEXT,
timing TEXT,
primary key (id)
);
create table session_entries (
created_at timestamp(6) not null,
id bigint generated by default as identity,
occurred_at timestamp(6) not null,
updated_at timestamp(6) not null,
type varchar(32) not null check (type in ('NOTE','EVENT','DICE_ROLL','PLAYER_ACTION')),
content TEXT not null,
session_id varchar(255) not null,
primary key (id)
);
create table sessions (
created_at timestamp(6) not null,
ended_at timestamp(6),
id bigint generated by default as identity,
playthrough_id bigint,
started_at timestamp(6) not null,
updated_at timestamp(6) not null,
campaign_id varchar(255),
name varchar(255) not null,
primary key (id)
);
create table templates (
created_at timestamp(6) not null,
default_node_id bigint,
id bigint generated by default as identity,
lore_id bigint not null,
updated_at timestamp(6) not null,
description TEXT,
fields TEXT,
name varchar(255) not null,
primary key (id)
);
create index idx_catalog_items_catalog_id
on catalog_items (catalog_id);
create index idx_conv_lore_entity
on conversations (lore_id, entity_type, entity_id, updated_at);
create index idx_conv_campaign_entity
on conversations (campaign_id, entity_type, entity_id, updated_at);
create index idx_enemies_campaign_id
on enemies (campaign_id);
create index idx_item_catalogs_campaign_id
on item_catalogs (campaign_id);
create index idx_notebook_messages_notebook_id
on notebook_messages (notebook_id);
create index idx_notebook_sources_notebook_id
on notebook_sources (notebook_id);
create index idx_notebooks_campaign_id
on notebooks (campaign_id);
create index ix_playthrough_flag_playthrough
on playthrough_flag (playthrough_id);
create index ix_playthrough_campaign
on playthroughs (campaign_id);
create index ix_quest_progression_playthrough
on quest_progression (playthrough_id);
create index idx_random_table_entries_table_id
on random_table_entries (random_table_id);
create index idx_session_entries_session_id
on session_entries (session_id);
alter table if exists catalog_items
add constraint FK7tuoq6mwuc00yv0hhpiw4aoni
foreign key (catalog_id)
references item_catalogs;
alter table if exists conversation_messages
add constraint FKcr8qqgnqnaqq2hw3gr4wtfe2a
foreign key (conversation_id)
references conversations;
alter table if exists random_table_entries
add constraint FKly4syvpfit2kibfjut67xxrrq
foreign key (random_table_id)
references random_tables;