설문 조사 및 설문지: 집단 결정을 위한 두 가지 보완 시스템
이벤트를 조직한다는 것은 수십 가지의 공동 결정을 내리는 것을 의미합니다. "어디로 가나요? 무엇을 먹나요? 어느 날짜를 선호하나요?". ~ 안에 이벤트를 플레이하세요 이러한 질문은 서로 다르지만 상호보완적인 두 가지 시스템을 통해 답변됩니다. 나 설문조사 미리 정의된 옵션에 대한 빠른 투표를 위해 설문지 질문을 통해 구조화된 피드백을 수집합니다. 다양한 유형의. 그들은 함께 의견 수집에 필요한 모든 요구 사항을 다룹니다. 행사를 계획하고 있습니다.
이 기사에서 찾을 수 있는 내용
- 설문조사 상태 머신(DRAFT, ACTIVE, CLOSED, CANCELLED)
- 최대 구성 가능 선택 옵션을 갖춘 SINGLE 및 MULTIPLE 응답
- UUID 공유 코드를 사용한 익명 투표 및 공개 여론 조사
- 전체 복사 옵션이 포함된 재사용 가능한 템플릿
- 각 변경사항에 대한 필수 동기 부여가 포함된 승자 기록
- 엔터티별 설문조사(위치, 날짜, 메뉴, 활동, 맞춤)
- 입력된 질문과 추적된 편집본이 포함된 설문지 시스템
- 실시간으로 결과 보기
집계 루트로서의 설문 조사
도메인 모델에서는 이벤트를 플레이하세요, 는 조사 행동이 풍부한 Aggregate Root입니다. 이는 단순한 옵션 컨테이너가 아닙니다. 자체 수명 주기를 관리하고, 상태 전환을 검증하고, 투표를 확인하고, 기록을 유지합니다. 결정이 완료되었습니다.
@Entity
@Table(name = "sondaggi")
public class Sondaggio {
private Long id;
private Evento evento;
private TipoEntitaSondaggio tipoEntita; // LUOGO, DATA, MENU...
private Long entitaId;
private String titolo;
private String descrizione;
private TipoRispostaSondaggio tipoRisposta; // SINGOLA o MULTIPLA
private StatoSondaggio stato; // BOZZA, ATTIVO, CHIUSO, ANNULLATO
private TipoSondaggio tipo; // EVENTO o TEMPLATE
private Long templateOrigineId;
private LocalDateTime dataScadenza;
private Boolean anonimo;
private Boolean permettiModificaVoto;
private Boolean mostraRisultatiPrimaVoto;
private Integer maxOpzioniSelezionabili;
private Boolean pubblico;
private String codiceCondivisione; // UUID per sharing
private Set<OpzioneSondaggio> opzioni;
private OpzioneSondaggio opzioneVincitrice;
private Set<StoricoVincitoreSondaggio> storicoVincitori;
}
각 설문조사는 이벤트에 연결되어 있으며 다음을 나타내는 엔터티 유형이 있습니다. 무엇을 참조하는지(장소, 날짜, 메뉴, 활동)를 내부적으로 관리합니다. 귀하의 옵션, 답변 및 우승자 기록. 집계 루트 패턴 모든 비즈니스 불변성이 항상 존중되도록 보장합니다.
주 조사 기계
설문조사의 라이프사이클은 잘 정의된 상태 머신을 따릅니다. 네 가지 가능한 상태와 제어된 전환. 모든 전환은 도메인 모델 자체에 의해 검증되므로 유효하지 않은 상태에 도달하는 것이 불가능합니다.
public enum StatoSondaggio {
BOZZA("Bozza"), // Creazione e configurazione
ATTIVO("Attivo"), // Aperto alle votazioni
CHIUSO("Chiuso"), // Votazioni terminate
ANNULLATO("Annullato"); // Sondaggio invalidato
}
허용되는 전환은 다음과 같습니다.
- 초안 → 활성 (
pubblica()): 최소 2개의 옵션이 필요합니다. - 활성 → 폐쇄 (
chiudi()): 투표 종료 - 활성 → 취소됨 (
annulla()): 설문조사를 무효화합니다. - 폐쇄 → 활성 (
riapri()): 투표 재개
public void pubblica() {
if (this.stato != StatoSondaggio.BOZZA) {
throw new IllegalStateException(
"Solo sondaggi in bozza possono essere pubblicati");
}
if (this.opzioni.size() < 2) {
throw new IllegalStateException(
"Il sondaggio deve avere almeno 2 opzioni");
}
this.stato = StatoSondaggio.ATTIVO;
}
public void riapri() {
if (this.stato != StatoSondaggio.CHIUSO) {
throw new IllegalStateException(
"Solo sondaggi chiusi possono essere riaperti");
}
this.stato = StatoSondaggio.ATTIVO;
}
재개하는 이유는 무엇입니까?
CLOSED → ACTIVE 전환은 중요한 설계 선택입니다. 실제 생활에서는 결정이 변경됩니다. 위치를 사용할 수 없게 되거나, 투표를 원하는 새로운 참가자가 도착하거나 단순히 봉사하기를 원합니다. 결정을 내리려면 더 많은 표를 얻어야 합니다. 새 설문조사를 만드는 대신 기존 투표를 잃더라도 다시 열면 수집을 계속할 수 있습니다. 투명한 방법으로.
응답 유형: SINGLE 및 MULTIPLE
시스템은 시나리오를 포괄하는 두 가지 투표 모드를 지원합니다. 이벤트 기획에서 가장 일반적입니다.
public enum TipoRispostaSondaggio {
SINGOLA("Singola"), // Radio button - una sola scelta
MULTIPLA("Multipla"); // Checkbox - più' opzioni selezionabili
}
응답의 경우 하나의, 필드 maxOpzioniSelezionabili
자동으로 1로 설정됩니다. 응답의 경우 다수의,
기본값은 3이지만 주최자가 구성할 수 있습니다.
이를 통해 "10개의 제안 중에서 가장 좋아하는 활동 3개를 선택하세요"와 같은 시나리오가 가능합니다.
public static Sondaggio crea(Evento evento, User creatoDa,
TipoEntitaSondaggio tipoEntita, String titolo,
TipoRispostaSondaggio tipoRisposta) {
Sondaggio s = new Sondaggio();
// ... inizializzazione campi ...
s.maxOpzioniSelezionabili =
tipoRisposta == TipoRispostaSondaggio.SINGOLA ? 1 : 3;
s.permettiModificaVoto = true;
s.mostraRisultatiPrimaVoto = false;
return s;
}
익명 투표
각 설문조사는 다음과 같이 구성될 수 있습니다. 익명의.
익명성이 활성화되면 응답은 익명성 없이 기록됩니다.
이를 투표 사용자와 연결하여 민감한 결정에 있어 개인정보 보호를 보장합니다.
분야 anonimo 로 설정되었습니다 false 기본적으로:
주최자는 이를 명시적으로 활성화해야 합니다.
익명 응답은 팩토리 메소드를 사용합니다. creaAnonima()
사용자나 이메일이 필요하지 않습니다. 추적 대상
이중 투표 방지는 다음을 통해 별도로 처리됩니다. 브라우저 지문.
// Voto di un utente registrato
RispostaSondaggio.creaPerUtente(sondaggio, opzione, utente);
// Voto di un esterno via email (con token di modifica)
RispostaSondaggio.creaPerEmail(sondaggio, opzione, email);
// Voto anonimo su sondaggio pubblico
RispostaSondaggio.creaAnonima(sondaggio, opzione);
공유 코드를 사용한 공개 설문조사
설문조사가 가능합니다 공공의 수집하다 플랫폼에 등록되지 않은 사람들의 투표도 가능합니다. 시스템은 UUID 공유 코드 가능한 한 독특하다 링크로 배포됩니다.
public String rendiPubblico() {
if (this.stato == StatoSondaggio.BOZZA) {
throw new IllegalStateException(
"Pubblica il sondaggio prima di renderlo pubblico");
}
if (this.pubblico && this.codiceCondivisione != null) {
return this.codiceCondivisione; // Gia' pubblico
}
this.pubblico = true;
this.codiceCondivisione = UUID.randomUUID().toString();
return this.codiceCondivisione;
}
public String rigeneraCodiceCondivisione() {
// Invalida i link precedenti
this.codiceCondivisione = UUID.randomUUID().toString();
return this.codiceCondivisione;
}
엔터티 공개투표 여론조사에서 익명의 투표를 추적합니다.
공개. 사용 브라우저 지문 방지하기 위해
중복 투표: 고유성 제약 조건 (sondaggio_id, fingerprint)
각 장치가 한 번만 투표할 수 있도록 보장합니다.
@Entity
@Table(name = "voti_pubblici",
uniqueConstraints = @UniqueConstraint(
columnNames = {"sondaggio_id", "fingerprint"}))
public class VotoPubblico {
private Long id;
private Sondaggio sondaggio;
private String fingerprint; // Hash del browser
private Instant votatoIl;
}
공개 설문조사 흐름
- 주최자가 설문조사를 생성하고 게시합니다(활성 상태).
- 부르다
rendiPubblico()UUID 코드를 생성하려면 - 링크는 메시지, 이메일 또는 소셜 미디어를 통해 공유됩니다.
- 외부인은 등록 없이 투표하며 지문으로 추적됩니다.
- 주최자는 코드를 다시 생성하여 이전 링크를 무효화할 수 있습니다.
- 설문조사를 비공개로 설정한 다음 코드를 유지하면서 다시 활성화할 수 있습니다.
재사용 가능한 템플릿
시스템은 유형 조사를 구별합니다. 이벤트 (에 연결 특정 이벤트) 및 유형 조사 주형 (재사용 가능). 템플릿은 역할을 하는 이벤트와 연결되지 않은 설문조사입니다. 서로 다른 컨텍스트에서 동일한 인스턴스를 생성하기 위한 템플릿입니다.
// Crea un template riutilizzabile
Sondaggio template = Sondaggio.creaTemplate(
utente, "Preferenza Location",
TipoEntitaSondaggio.LUOGO, "Dove facciamo la festa?",
TipoRispostaSondaggio.SINGOLA);
// Istanzia il template per un evento specifico
Sondaggio istanza = Sondaggio.creaDaTemplate(
template, evento, organizzatore);
istanza.copiaOpzioniDa(template);
// L'istanza eredita: titolo, descrizione, tipoRisposta,
// configurazione (anonimo, maxSelezionabili, ecc.)
// ma parte sempre in stato BOZZA
복사 옵션은 인스턴스화 유지 관리와 별개입니다.
올바른 JPA 관계. 각 옵션은 다음을 통해 복제됩니다.
OpzioneSondaggio.copiaDa() 새로운 엔터티를 생성하는
동일한 데이터를 사용하지만 ID가 없고 응답이 없어 인스턴스를 보장합니다.
템플릿과 완전히 독립적입니다.
감사 추적을 통한 우승자의 역사
유형 조사의 경우 장소, 시스템은 선택을 지원합니다 투표가 종료된 후 승리 옵션. 각 선택 또는 승자 변경은 엔터티에서 추적됩니다. 연혁수상자설문조사, 완전한 감사 추적을 생성합니다.
@Entity
@Table(name = "storico_vincitori_sondaggio")
public class StoricoVincitoreSondaggio {
private Long id;
private Sondaggio sondaggio;
private OpzioneSondaggio opzionePrecedente; // null se prima selezione
private OpzioneSondaggio opzioneNuova;
private String motivazione; // obbligatoria per cambi
private User modificatoDa;
private Instant modificatoIl;
}
핵심 규칙은 다음과 같습니다. 동기부여는 필수 이미 선택된 우승자를 변경할 때. 첫 번째 선택이 아닌 필요합니다. 이는 그룹 결정의 투명성을 보장합니다.
public StoricoVincitoreSondaggio selezionaVincitore(
Long opzioneId, User selezionatoDa, String motivazione) {
verificaChiuso(); // Deve essere CHIUSO
verificaTipoLuogo(); // Solo per sondaggi LUOGO
OpzioneSondaggio opzione = trovaNelleOpzioni(opzioneId);
StoricoVincitoreSondaggio storico;
if (this.opzioneVincitrice != null) {
// Cambio vincitore: motivazione OBBLIGATORIA
if (motivazione == null || motivazione.isBlank()) {
throw new IllegalArgumentException(
"La motivazione e' obbligatoria per cambiare il vincitore");
}
storico = StoricoVincitoreSondaggio.creaCambio(
this, this.opzioneVincitrice, opzione,
motivazione, selezionatoDa);
} else {
// Prima selezione
storico = StoricoVincitoreSondaggio.creaPrimaSelezione(
this, opzione, selezionatoDa);
}
this.opzioneVincitrice = opzione;
this.storicoVincitori.add(storico);
return storico;
}
엔터티 설문조사: 단순한 질문 그 이상
설문조사는 일반적이지 않습니다. 각 설문조사는 엔터티 유형 이는 컨텍스트를 정의하고 기능을 사용할 수 있습니다.
public enum TipoEntitaSondaggio {
LUOGO("Luogo"), // Votare la venue dell'evento
DATA("Data"), // Scegliere la data
MENU("Menu"), // Preferenze catering
ATTIVITA("Attività"), // Attività da organizzare
CUSTOM("Personalizzato"); // Sondaggio generico
}
그 남자 장소 특히 풍부합니다. 옵션은
다음을 통해 시스템의 장소 엔터티에 직접 연결됩니다.
entitaRiferimentoId, 설명 및 전용 이미지 포함.
또한 LUOGO 여론조사만 승자 선택을 지원합니다.
@Entity
public class OpzioneSondaggio {
private Long id;
private Sondaggio sondaggio;
private String testo;
private Long entitaRiferimentoId; // ID del luogo collegato
private String descrizione; // Info aggiuntive
private String immagineUrl; // Foto della venue
private Integer ordine;
private Set<RispostaSondaggio> risposte;
}
전용 팩토리 메소드 creaPerLuoghi() 생성을 단순화합니다
위치 선택을 위한 설문 조사, 엔터티 유형 사전 설정
PLACE로, SINGLE로 응답합니다.
구성 가능한 옵션
각 설문조사는 투표 경험을 제어하는 세 가지 부울 플래그를 제공합니다. 이러한 구성은 설문조사가 진행되는 동안에만 편집 가능합니다. 초안 상태입니다.
- maxSelectable옵션: 선택 항목 수를 제한합니다. 여러 답변. 1 이상인 것으로 검증되었습니다.
-
showResultsFirstVote: 만약에
true, 참가자 투표하기 전에 부분적인 결과를 확인하세요. 기본값:false에 대한 밴드웨건 효과를 피하세요. -
허용편집등급: 만약에
true, 유권자는 다음을 수행할 수 있습니다. 선택을 바꾸세요. 기본값:true.
public void configura(Boolean anonimo, Boolean permettiModificaVoto,
Boolean mostraRisultatiPrimaVoto,
Integer maxOpzioniSelezionabili,
LocalDateTime dataScadenza) {
verificaModificabile(); // Solo in stato BOZZA
if (maxOpzioniSelezionabili != null) {
if (maxOpzioniSelezionabili < 1) {
throw new IllegalArgumentException(
"Deve essere selezionabile almeno un'opzione");
}
this.maxOpzioniSelezionabili = maxOpzioniSelezionabili;
}
this.dataScadenza = dataScadenza;
// ... altri campi ...
}
La 만료 날짜 선택사항입니다. 설정된 경우 설문조사는
마감일 이후에는 투표 접수가 자동으로 중단됩니다.
활성 상태. 방법 isVotabile() 두 가지 조건을 모두 확인하세요.
설문지 시스템
여론조사와 함께, 이벤트를 플레이하세요 시스템을 제공합니다 설문지 정보를 수집하기 위해 더 구조화되었습니다. 여론 조사는 옵션에 대한 투표이지만 사전 정의된 설문지는 다양한 유형의 질문이 포함된 형식입니다.
@Entity
@Table(name = "questionari")
public class Questionario {
private Long id;
private Evento evento;
private TipoQuestionario tipo; // TEMPLATE o EVENTO
private Long templateOrigineId;
private String titolo;
private String descrizione;
private String etichetta;
private String coloreEtichetta;
private StatoQuestionario stato; // BOZZA, PUBBLICATO, CHIUSO, ARCHIVIATO
private LocalDateTime dataScadenza;
private Boolean anonimo;
private Boolean richiediEmail;
private Boolean richiediNome;
private Boolean pubblico;
private String codiceCondivisione;
private List<DomandaQuestionario> domande;
}
설문지의 수명주기는 설문조사의 수명주기와 유사하지만 상태가 하나 더 있습니다: 초안 → 게시됨 → 종료됨 → 보관됨. ARCHIVED 상태에서는 설문지를 보관할 수 있습니다. 활성 뷰를 어수선하게 하지 않고 완료되었습니다.
public enum StatoQuestionario {
BOZZA("Bozza"), // In fase di creazione
PUBBLICATO("Pubblicato"), // Aperto alle compilazioni
CHIUSO("Chiuso"), // Compilazioni terminate
ARCHIVIATO("Archiviato"); // Conservato in archivio
}
설문지의 질문 유형
설문조사의 각 질문에는 표시 방법을 결정하는 유형이 있습니다. 그리고 응답이 수집되는 방법.
public enum TipoDomanda {
APERTA("Risposta aperta"), // Testo libero
SCELTA_SINGOLA("Scelta singola"), // Radio button
SCELTA_MULTIPLA("Scelta multipla"); // Checkbox
}
유형 질문 열려 있는 자유 텍스트 수집: 댓글,
제안, 특별 메모. 질문은 SINGLE_CHOICE e
MULTIPLE_CHOICE 다음을 통해 기본 옵션이 필요합니다.
실체 OpzioneDomanda. 시스템이 자동으로 유효성을 검사합니다.
옵션이 필요한 유형만 가질 수 있다는 것입니다.
@Entity
public class DomandaQuestionario {
private Long id;
private Questionario questionario;
private String testo;
private TipoDomanda tipoDomanda;
private Boolean obbligatoria; // Default: true
private Integer ordine;
private String descrizioneAiuto; // Testo di aiuto opzionale
private List<OpzioneDomanda> opzioni;
}
// Validazione nel metodo aggiungiOpzione
public OpzioneDomanda aggiungiOpzione(String testo) {
if (!this.tipoDomanda.richiedeOpzioni()) {
throw new IllegalStateException(
"Le domande di tipo " + this.tipoDomanda
+ " non supportano opzioni");
}
// ...
}
편집 및 응답
사용자가 설문지를 작성하면 시스템에서 설문지를 생성합니다. 설문지 편집 모든 답변을 하나로 묶습니다. 설문지는 등록된 사용자의 편집과 편집을 모두 지원합니다. 공개(익명 또는 자발적으로 제공되는 데이터).
@Entity
public class CompilazioneQuestionario {
private Long id;
private Questionario questionario;
private User utente; // null se compilazione pubblica
private String nomeCompilatore;
private String emailCompilatore;
private String fingerprint; // Per tracciamento anonimo
private List<RispostaQuestionario> risposte;
private Instant compilatoIl;
}
// Due modalità' di compilazione
CompilazioneQuestionario.creaPerUtente(questionario, utente);
CompilazioneQuestionario.creaPubblica(
questionario, nome, email, fingerprint);
각 반응은 다음에 의해 형성됩니다. 답변설문지, 그 자유 텍스트(미결 질문의 경우)와 선택한 옵션을 모두 관리합니다. (선택 질문에 대해 JSON 배열로 직렬화됨)
라벨 및 조직
설문지는 다음과 같이 분류될 수 있습니다. 라벨 이름과 색상을 사용자 정의할 수 있습니다. 시스템은 사전 정의된 라벨을 제공합니다. (시스템) 및 각 사용자가 개인화된 시스템을 만들 수 있는 가능성.
@Entity
public class EtichettaQuestionario {
private Long id;
private String nome; // Max 50 caratteri
private String colore; // Codice esadecimale (#3B82F6)
private Long userId; // null per etichette di sistema
private boolean predefinita; // true = di sistema
}
// Creazione etichetta personalizzata
EtichettaQuestionario.creaPersonalizzata(
userId, "Feedback Post-Evento", "#10B981");
실시간 결과
결과의 가시성은 두 가지 모두에 대한 정확한 규칙에 의해 제어됩니다.
설문 조사 및 설문지. 설문 조사의 경우 방법은
sonoRisultatiVisibili() 논리를 구현하십시오.
- 설문조사인 경우 닫은: 결과는 항상 모든 사람에게 표시됩니다.
- Se showResultsFirstVote 활성화됨: 투표하지 않아도 결과가 표시됩니다.
- 그렇지 않은 경우: 투표 후에만 결과가 표시됩니다.
public boolean sonoRisultatiVisibili(boolean haVotato) {
if (this.stato == StatoSondaggio.CHIUSO) return true;
if (Boolean.TRUE.equals(this.mostraRisultatiPrimaVoto)) return true;
return haVotato;
}
public boolean isVotabile() {
return this.stato == StatoSondaggio.ATTIVO &&
(this.dataScadenza == null ||
LocalDateTime.now().isBefore(this.dataScadenza));
}
결과는 각 옵션에 대한 응답을 집계하여 계산됩니다.
모든 것이 괜찮습니다 OpzioneSondaggio 개수를 노출합니다.
getNumeroVoti() 컬렉션의 응답을 계산합니다.
프런트엔드에서 이 데이터는 업데이트된 막대 및 백분율 차트를 제공합니다.
실시간으로.
핵심 사항
- 4개의 제어된 전환과 재개 가능성이 있는 상태 머신
- 선택 가능한 옵션의 제한을 구성할 수 있는 SINGLE 및 MULTIPLE 응답
- 중복 방지를 위한 지문 추적을 통한 익명 투표
- 외부 유권자를 위한 UUID 공유 코드를 사용한 공개 여론 조사
- 옵션이 포함된 깊은 복사 기능을 갖춘 재사용 가능한 템플릿
- 각 우승자 변경에 대한 정당성이 포함된 필수 감사 추적
- 5가지 유형의 설문조사 엔터티(위치, 날짜, 메뉴, 활동, 사용자 정의)
- 질문을 입력한 설문지(OPEN, SINGLE_CHOICE, MULTIPLE_CHOICE)
- 설문지를 정리하기 위한 맞춤형 색상 라벨
- 3가지 액세스 수준으로 결과 가시성 제어
프로젝트의 소스 코드는 다음에서 확인할 수 있습니다. GitHub. 전체 설문조사 및 설문지 시스템을 사용해 보려면 다음 사이트를 방문하세요. www.playtheevent.com.







