Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ WebContent/*.map
WebContent/*.js
/bin/
src/main/resources/local.application.yaml
.local-postgres/
.DS_Store
10 changes: 10 additions & 0 deletions .run/Pogues local.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Pogues (local)" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot">
<module name="Pogues-BO" />
<option name="SPRING_BOOT_MAIN_CLASS" value="fr.insee.pogues.Pogues" />
<option name="ACTIVE_PROFILES" value="local" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>
41 changes: 40 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Pogues
# Pogues API

[![Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=InseeFr_Pogues-Back-Office&metric=alert_status)](https://sonarcloud.io/dashboard?id=InseeFr_Pogues-Back-Office)
[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=InseeFr_Pogues-Back-Office&metric=security_rating)](https://sonarcloud.io/dashboard?id=InseeFr_Pogues-Back-Office)
Expand All @@ -15,3 +15,42 @@ Navigation: [Client][1] | **Back-office** | [Pogues model][2]
Pogues is a tool that allow to design questionnaires with components that are structural (sequences, questions...) and dynamic (filters, controls, loops...).

This is the repository of the back-end part of Pogues.

## Local run with the Pogues front (no Keycloak)

The `local` profile uses anonymous auth (Guybrush / `FAKEPERMISSION`), mocks Magma and DDI-AS, and embeds Postgres (no Docker).

Prerequisites: Java 25, Maven. Same commands on macOS, Linux and Windows (PowerShell, Git Bash or cmd).

From IntelliJ: run the shared `Pogues (local)` configuration, or start `fr.insee.pogues.Pogues` (the `local` profile is selected on its own in a workspace classpath).

From the command line:

```bash
mvn spring-boot:run
```

That starts Postgres (port 5433, data in `.local-postgres/`) then the API on http://localhost:8081. Swagger: http://localhost:8081/

The first start can take a while: Postgres binaries are extracted once.

In the Pogues frontend repo, in parallel:

```bash
pnpm --dir next install
pnpm dev:api
```

→ http://localhost:5173

### Add a questionnaire

Drop a Pogues `.json` file in `local-questionnaires/` (this repo root). The API picks it up on its own; refresh the UI.

One questionnaire per file. The JSON `id` must be alphanumeric (`qdemo1`, no hyphen). The folder wins: on start and on drop, a file overwrites the same id in the database (logged as `Replaced questionnaire …`). UI edits on that id are lost when you restart or replace the file.

`qdemo1.json` is the sample loaded on the first start.

`.local-postgres/` is kept across restarts so Postgres binaries are not extracted every time. Delete it only if you want a full schema wipe (API stopped).

Visualization (Eno, Queen, Stromae) is not started in this mode.
7 changes: 7 additions & 0 deletions local-questionnaires/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Local questionnaires

Drop a Pogues `.json` file here (one questionnaire per file).

If the API is already running (`mvn spring-boot:run` or the IntelliJ `Pogues (local)` run config), the file is loaded or replaced immediately. Otherwise it is applied on the next start. Then refresh the UI.

The JSON `id` must be alphanumeric (`qdemo1`, not `q-demo-1`). Files overwrite the same id in the database. Check the API log for `Loaded questionnaire` or `Replaced questionnaire`.
128 changes: 128 additions & 0 deletions local-questionnaires/qdemo1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
{
"owner": "FAKEPERMISSION",
"final": false,
"id": "qdemo1",
"Label": [
"Questionnaire démo (local)"
],
"Name": "QDEMO1",
"lastUpdatedDate": "2026-09-06T08:00:00.000Z",
"DataCollection": [],
"genericName": "QUESTIONNAIRE",
"ComponentGroup": [],
"agency": "fr.insee",
"TargetMode": [
"CAPI",
"CAWI"
],
"flowLogic": "FILTER",
"formulasLanguage": "VTL",
"childQuestionnaireRef": [],
"Child": [
{
"id": "qdemo1seq1",
"depth": 1,
"Name": "SEQDEMO",
"Label": [
"Séquence démo"
],
"Declaration": [],
"Control": [],
"FlowControl": [],
"TargetMode": [
"CAPI",
"CAWI"
],
"type": "SequenceType",
"genericName": "MODULE",
"Child": [
{
"id": "qdemo1q1",
"depth": 2,
"Name": "DEMOVAR",
"Label": [
"Quelle est votre réponse démo ?"
],
"Declaration": [],
"Control": [],
"FlowControl": [],
"TargetMode": [
"CAPI",
"CAWI"
],
"type": "QuestionType",
"questionType": "SIMPLE",
"ClarificationQuestion": [],
"Response": [
{
"id": "qdemo1resp1",
"Datatype": {
"typeName": "TEXT",
"type": "TextDatatypeType",
"MaxLength": 50,
"Pattern": ""
},
"CollectedVariableReference": "qdemo1var1",
"mandatory": false
}
]
}
]
},
{
"id": "idendquest",
"depth": 1,
"Name": "QUESTIONNAIRE_END",
"Label": [
"QUESTIONNAIRE_END"
],
"Declaration": [],
"genericName": "MODULE",
"Control": [],
"FlowControl": [],
"type": "SequenceType",
"Child": [],
"TargetMode": [
"CAPI",
"CAWI"
]
}
],
"CodeLists": {
"CodeList": [
{
"id": "qdemo1cl1",
"Label": "Liste démo",
"Code": [
{
"Label": "Oui",
"Value": "1",
"Parent": ""
},
{
"Label": "Non",
"Value": "2",
"Parent": ""
}
]
}
]
},
"Variables": {
"Variable": [
{
"id": "qdemo1var1",
"Name": "DEMOVAR",
"Label": "Variable démo",
"type": "CollectedVariableType",
"Datatype": {
"typeName": "TEXT",
"type": "TextDatatypeType",
"MaxLength": 50,
"Pattern": ""
}
}
]
},
"FlowControl": []
}
63 changes: 58 additions & 5 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.1.0</version>
<version>4.1.1</version>
<relativePath/>
</parent>

Expand All @@ -22,22 +22,25 @@

<!-- Project build properties -->
<java.version>25</java.version>
<spring-boot.run.profiles>local</spring-boot.run.profiles>
<argLine>-Xms256m -Xmx512m -ea -Dfile.encoding=UTF-8</argLine>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

<!-- !!! Version properties overridden from Spring Boot !!! -->
<tomcat.version>11.0.22</tomcat.version>
<tomcat.version>11.0.25</tomcat.version>
<!-- <jackson-2-bom.version>2.21.4</jackson-2-bom.version>-->
<!-- <jackson-bom.version>3.1.4</jackson-bom.version>-->

<!-- Version properties not managed by Spring Boot -->
<pogues-model.version>2.1.0</pogues-model.version>
<fop.version>2.11</fop.version>
<springdoc-openapi-ui.version>3.0.3</springdoc-openapi-ui.version>
<springdoc-openapi-ui.version>3.1.0</springdoc-openapi-ui.version>
<jacoco.version>0.8.15</jacoco.version>
<saxon.version>12.10</saxon.version>
<netty.version>4.2.16.Final</netty.version>
<postgresql.version>42.7.12</postgresql.version>
<netty.version>4.2.17.Final</netty.version>
<postgresql.version>42.7.13</postgresql.version>
<embedded-postgres.version>2.2.2</embedded-postgres.version>
<embedded-postgres-binaries.version>16.15.0</embedded-postgres-binaries.version>

<!-- Sonar properties -->
<sonar.core.codeCoveragePlugin>jacoco</sonar.core.codeCoveragePlugin>
Expand All @@ -46,6 +49,18 @@
<sonar.language>java</sonar.language>
</properties>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.zonky.test.postgres</groupId>
<artifactId>embedded-postgres-binaries-bom</artifactId>
<version>${embedded-postgres-binaries.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<repositories>
<!-- Maven central snapshot repository -->
<repository>
Expand Down Expand Up @@ -113,6 +128,29 @@
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<dependency>
<groupId>io.zonky.test</groupId>
<artifactId>embedded-postgres</artifactId>
<version>${embedded-postgres.version}</version>
<optional>true</optional>
</dependency>
<!-- embedded-postgres already ships amd64 for Windows, macOS Intel and Linux.
These two add ARM: Apple Silicon and Linux aarch64. -->
<dependency>
<groupId>io.zonky.test.postgres</groupId>
<artifactId>embedded-postgres-binaries-darwin-arm64v8</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.zonky.test.postgres</groupId>
<artifactId>embedded-postgres-binaries-linux-arm64v8</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
Expand Down Expand Up @@ -239,6 +277,12 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>repackage</id>
<configuration>
<excludeGroupIds>io.zonky.test,io.zonky.test.postgres</excludeGroupIds>
</configuration>
</execution>
<execution>
<id>build-info</id>
<goals>
Expand Down Expand Up @@ -271,4 +315,13 @@
</plugins>
</build>

<profiles>
<profile>
<id>local</id>
<properties>
<spring-boot.run.profiles>local</spring-boot.run.profiles>
</properties>
</profile>
</profiles>

</project>
24 changes: 24 additions & 0 deletions src/main/java/fr/insee/pogues/Pogues.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,33 @@ public static SpringApplicationBuilder configureApplicationBuilder(SpringApplica
}

public static void main(String[] args) {
if (shouldDefaultToLocalProfile()) {
System.setProperty("spring.profiles.default", "local");
log.info("No Spring profile specified, using 'local'");
}
configureApplicationBuilder(new SpringApplicationBuilder()).build().run(args);
}

/**
* IDE / {@code mvn spring-boot:run} put {@code target/classes} on the classpath.
* A packaged jar does not, so production is left untouched.
*/
static boolean shouldDefaultToLocalProfile() {
if (hasText(System.getenv("SPRING_PROFILES_ACTIVE"))
|| hasText(System.getProperty("spring.profiles.active"))
|| hasText(System.getProperty("spring.profiles.default"))) {
return false;
}
String classpath = System.getProperty("java.class.path", "");
return classpath.contains("target/classes")
|| classpath.contains("out/production")
|| classpath.contains("out\\production");
}

private static boolean hasText(String value) {
return value != null && !value.isBlank();
}

@PostConstruct
public void executeAfterMain() {
log.info("Timezone is set to '{}'", applicationTimeZoneId);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package fr.insee.pogues.configuration;

import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.info.BuildProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Properties;

/**
* Maven {@code build-info} is not generated when the app is started from the IDE.
*/
@Configuration
public class BuildPropertiesFallbackConfiguration {

@Bean
@ConditionalOnMissingBean(BuildProperties.class)
public BuildProperties buildProperties() {
Properties properties = new Properties();
properties.setProperty("group", "fr.insee");
properties.setProperty("artifact", "Pogues-BO");
properties.setProperty("name", "Pogues-Back-Office");
properties.setProperty("version", "dev");
return new BuildProperties(properties);
}
}
Loading