조직과 축제: 복잡한 행사를 위한 복잡한 구조
단일 사용자로는 더 이상 충분하지 않을 때, 조직. ~ 안에 이벤트를 플레이하세요 조직이 될 수 있다대행사 또는협회, 각각은 고유한 프로필, 구성원 및 역할을 가지고 있습니다. 그리고 언제 조직에서는 회의실, 스탠드, 일정을 포함하여 며칠에 걸쳐 이벤트를 관리하려고 합니다. 연결되면 모듈이 작동하게 됩니다. 제전.
이 문서에서는 다음을 허용하는 두 가지 하위 도메인을 살펴봅니다. 이벤트를 플레이하세요 단일 이벤트 관리에서 이벤트 관리까지 확장 가능 수십 명의 배우가 참여하는 며칠간의 이벤트입니다.
이 기사에서 찾을 수 있는 내용
- 두 가지 유형의 조직: 회사와 협회
- 양방향 워크플로우를 통한 멤버십 및 계층적 역할
- 아직 등록되지 않은 사용자에 대한 이메일 초대장
- 여러 날에 걸쳐 진행되는 행사를 위한 종합 루트로서의 축제
- 요일, 방, 스탠드 및 오케스트레이션
- 라이프사이클을 갖춘 스탠드 예약 시스템
- 예산 관리를 위한 Money Value 객체
두 가지 유형의 조직
플랫폼은 열거형을 통해 네 가지 계정 유형을 지원합니다. 계정 유형: 개인, 회사, 협회 e SUPER_ADMINISTRATOR. 처음 3개는 등록 중에 선택할 수 있습니다. 사용자가 COMPANY 또는 ASSOCIATION을 선택하면 시스템은 다음을 요청합니다. 특정 추가 프로필을 편집합니다.
TipoAccount
├── INDIVIDUO → Nessun profilo aggiuntivo
├── AZIENDA → Richiede ProfiloAzienda
├── ASSOCIAZIONE → Richiede ProfiloAssociazione
└── SUPER_AMMINISTRATORE → Non selezionabile in registrazione
회사 프로필
회사에는 국제 세금 데이터로 가득 찬 프로필이 있습니다: 회사 이름, 국가(ISO 3166-1 alpha-2 코드), VAT 번호, 세금 ID 및 등록 번호 기업. 또한 연락처 세부 정보(회사 이메일, PEC), 등록된 사무실도 포함됩니다. 값 객체를 통해 주소, 회사 연락처 및 속하는 업종입니다.
@Entity
public class ProfiloAzienda {
private Long id;
private User user; // Relazione 1:1
// Identificazione
private String ragioneSociale; // "TechCorp S.r.l."
private String paese; // "IT" (ISO 3166-1 alpha-2)
private String vatNumber; // "IT12345678901"
private String taxId; // Codice Fiscale
private String companyRegistrationNumber;
// Contatti
private String emailAziendale;
private String pec; // Per aziende italiane
// Sede e referente
private Indirizzo sedeLegale; // Value Object embedded
private String referenteNome;
private String referenteCognome;
private String referenteRuolo;
private SettoreAzienda settore; // Classificazione
}
협회 프로필
협회는 비영리 세계를 지향하는 다른 프로필을 가지고 있습니다. 키 필드와 유형협회, 이는 다음에 따라 달라집니다. 국가: 이탈리아의 경우 APS, ASD, ODV, ETS, ONLUS를 지원합니다. 미국을 위해 501(c)(3); 영국 자선 단체를 위해. 각 유형은 다음을 기준으로 검증됩니다. 선택한 국가.
@Entity
public class ProfiloAssociazione {
private Long id;
private User user; // Relazione 1:1
private String nomeAssociazione; // "ASD Runners Bari"
private String paese; // "IT"
private TipoAssociazione tipoAssociazione; // APS, ASD, ODV, 501C3...
private String registrationNumber; // RUNTS, EIN, etc.
private String taxId;
private Indirizzo sede;
private String rappresentanteLegaleNome;
private String rappresentanteLegaleCognome;
}
// Validazione tipo-paese:
// TipoAssociazione.ASD.isValidoPerPaese("IT") → true
// TipoAssociazione.ASD.isValidoPerPaese("US") → false
// TipoAssociazione._501C3.isValidoPerPaese("US") → true
두 프로필의 차이점
- 회사 프로필: 완전한 세금 데이터(VAT, PEC, 회사 등록부), 회사 연락처, 소속 부문, 사업 계획
- 협회 프로필: 국가별로 인증된 협회 유형, 법적 대리인, 등록 번호(RUNTS/EIN), 협회 플랜 35~38% 할인
회원 및 역할: 회원 조직
COMPANY 또는 ASSOCIATION 계정을 가진 사용자는조직 다른 사용자가 속할 수 있습니다. 조직과 회원의 관계 그리고 엔터티에 의해 형성됩니다. 회원조직, 작동 멤버십 하위 도메인에 대한 Aggregate Root에서.
계층적 역할
역할은 열거형으로 정의됩니다. 역할조직 4개로 승인 수준이 높아집니다.
public enum RuoloOrganizzazione {
MEMBRO(10), // Partecipa e riceve benefici piano
RESPONSABILE(50), // Crea eventi/viaggi per l'organizzazione
ADMIN(80), // Gestisce membri e ruoli
OWNER(100); // Controllo completo (uno solo per org)
}
PERMESSI:
MEMBRO RESPONSABILE ADMIN OWNER
Ricevere benefici ✓ ✓ ✓ ✓
Creare eventi ✗ ✓ ✓ ✓
Gestire membri ✗ ✗ ✓ ✓
Cambiare ruoli ✗ ✗ ✓ ✓
Invitare membri ✗ ✗ ✓ ✓
Rimuovere membri ✗ ✗ ✓ ✓
역할 소유자 특별: 자동으로 할당됩니다.
조직의 창설자에게 초대를 통해 할당할 수 없으며
정지할 수 없습니다. 소유권을 이전하려면 전용 방법이 있습니다
trasferisciOwnership().
양방향 작업 흐름
멤버십은 두 가지 스트림을 지원합니다. 조직 초대하다 회원(초기 상태 PENDING_INVITO) 또는 회원 필요하다 가입합니다(초기 상태 PENDING_REQUEST). 두 경우 모두 수신자는 수락하거나 거부할 수 있습니다.
public enum StatoAppartenenza {
PENDING_INVITO, // L'org ha invitato, in attesa del membro
PENDING_RICHIESTA, // Il membro ha richiesto, in attesa dell'org
ATTIVO, // Membro attivo nell'organizzazione
SOSPESO, // Temporaneamente sospeso
RIFIUTATO // Invito/richiesta rifiutata
}
FLUSSO INVITO (dall'organizzazione):
PENDING_INVITO ──accetta──► ATTIVO ──sospendi──► SOSPESO
│ │
└──rifiuta──► RIFIUTATO riattiva ◄───┘
FLUSSO RICHIESTA (dal membro):
PENDING_RICHIESTA ──approva──► ATTIVO
│
└──rifiuta──► RIFIUTATO
시스템은 또한 다중 회원: 사용자 서로 다른 역할로 동시에 여러 조직에 속할 수 있음 각각. 테이블에는 쌍에 대한 고유성 제약 조건이 있습니다. (organization_id, member_id) 중복을 방지합니다.
이메일을 통한 초대: OrganizationInvitationEmail
아직 플랫폼에 등록되지 않은 사람을 초대하는 방법은 무엇입니까? 을 통해 초대조직이메일. 이 개체는 전체를 관리합니다. 흐름: 고유한 토큰이 포함된 이메일을 보내는 것부터 변환까지 사용자가 수락할 때 MembershipOrganization.
1. Admin/Owner crea invito con email destinatario
2. Sistema genera token SecureRandom (48 bytes, Base64 URL-safe)
3. Email inviata con link contenente il token
4. Destinatario clicca il link
├── Se registrato → Accetta direttamente
└── Se non registrato → Si registra, poi accetta
5. Invito convertito in AppartenenzaOrganizzazione ATTIVA
STATI INVITO:
PENDING ──accetta──► ACCETTATO
│
├──annulla──► ANNULLATO (dall'org)
├──scade────► SCADUTO (dopo N giorni, default 7)
└──rinnova──► PENDING (nuovo token, nuova scadenza)
초대 보안
각 초대는 다음을 통해 암호화된 보안 48바이트 토큰을 생성합니다. 시큐어랜덤. 토큰에는 구성 가능한 만료일이 있습니다(기본값 7일) 초대가 갱신되면 다시 생성됩니다. 이메일이 온다 보내기 전에 정규화(소문자, 트림) 및 유효성 검사를 거쳤습니다.
페스티벌: 여러 날에 걸쳐 진행되는 이벤트의 총체적 루트
이제 기사의 두 번째 주요 주제로 넘어가겠습니다. 에이 제전 in 이벤트를 플레이하세요 여러 날의 이벤트를 날짜별로 모델링하는 복잡한 집계 프로그래밍되고 장비가 갖춰진 공간, 전시 스탠드 및 구조화된 프로그램이 있습니다. DDD 원칙에 따라 페스티벌과 Aggregate Root를 경계로 합니다. 강력한 일관성: 모든 변경 사항이 이를 통과합니다.
Festival (Aggregate Root)
├── id, titolo, descrizione
├── organizzatoreId // Chi organizza
├── luogoId // Location principale
├── dataInizio / dataFine
├── stato: StatoFestival
├── budget: Money // Value Object embedded
├── maxPartecipantiTotali
├── tokenCondivisione // QR / link sharing
│
├── giornate: Set<GiornataFestival>
│ └── ogni giornata ha i suoi EventoFestival
│
├── sale: Set<SalaFestival>
│ └── ogni sala ha le sue ConfigurazioneSala
│
└── stand: Set<StandFestival>
└── ogni stand ha le sue PrenotazioneStand
축제 라이프사이클
축제는 통제된 전환과 함께 잘 정의된 5개의 상태를 거칩니다. 그리고 각 단계에서 검증을 수행합니다.
public enum StatoFestival {
DRAFT, // Bozza: in preparazione, non visibile
PUBLISHED, // Pubblicato: visibile, in attesa dell'inizio
IN_CORSO, // In svolgimento
COMPLETATO, // Concluso con successo
ANNULLATO // Annullato
}
TRANSIZIONI:
DRAFT ──pubblica──► PUBLISHED ──avvia──► IN_CORSO ──completa──► COMPLETATO
│ │
└──annulla──► ANNULLATO ◄──annulla───┘
▲
DRAFT ────────────────annulla────────────┘
PERMESSI PER STATO:
DRAFT PUBLISHED IN_CORSO COMPLETATO ANNULLATO
Modificabile ✓ ✓ ✗ ✗ ✗
Accetta eventi ✓ ✓ ✓ ✗ ✗
Accetta prenotaz. ✓ ✓ ✗ ✗ ✗
Annullabile ✓ ✓ ✓ ✗ ✗
축제를 게시하려면 최소한 하루가 있어야 합니다.
구성되었습니다. 시스템은 메소드에서 이 요구사항을 확인합니다.
pubblica() 만족하지 않으면 예외가 발생합니다.
축제일
모든 것이 괜찮습니다 축제의 날 하루를 나타냅니다. 축제. 날짜, 선택적 제목, 시작 및 종료 시간이 있습니다. (기본값 09:00 - 23:00) 및 점진적인 순서입니다.
@Entity
public class GiornataFestival {
private Long id;
private Long festivalId;
private LocalDate data;
private String titolo; // "Giorno 1 - Apertura"
private String descrizione;
private LocalTime oraInizio; // Default: 09:00
private LocalTime oraFine; // Default: 23:00
private Integer ordine; // Posizione nel calendario
private Set<EventoFestival> eventi; // Eventi programmati
}
VALIDAZIONI:
- La data deve essere compresa tra dataInizio e dataFine del festival
- Non possono esistere due giornate con la stessa data
- Gli orari degli eventi devono rientrare negli orari della giornata
- Non si può rimuovere una giornata con eventi programmati
축제는 또한 방법을 제공합니다 generaGiornate() 그것은 창조한다
해당 기간의 각 날짜에 대해 자동으로 축제의 날을 피하고
이미 존재하는 날짜와 중복됩니다.
홀: 살라페스티벌 및 구성
Le 살라축제 그들은 축제의 물리적 공간을 나타냅니다. 각 방에는 그 기능과 용도를 결정하는 유형이 있습니다.
public enum TipoSala {
SALA_CONFERENZE // Conferenze e presentazioni (seduti, eventi)
AUDITORIUM // Grande sala per molti partecipanti (seduti)
PALCO // Spettacoli e performance (eventi)
AREA_ESTERNA // Spazio all'aperto (eventi)
STAND_AREA // Area dedicata agli stand espositivi
SALA_WORKSHOP // Workshop pratici (seduti, eventi)
FOYER // Area accoglienza e networking
SALA_STAMPA // Per giornalisti e media (seduti, eventi)
}
capacità:
Posti Seduti Ospita Eventi
SALA_CONFERENZE ✓ ✓
AUDITORIUM ✓ ✗
PALCO ✗ ✓
AREA_ESTERNA ✗ ✓
STAND_AREA ✗ ✗
SALA_WORKSHOP ✓ ✓
FOYER ✗ ✗
SALA_STAMPA ✓ ✓
룸 구성
방은 가질 수 있습니다 여러 구성 용량이 있는 다르다. 예를 들어 회의실을 모드로 설정할 수 있습니다. "극장"(좌석 200석), "플라테아"(좌석 150석 + 입석 50석) 또는 "스탠딩"(300 스탠딩). 구성을 활성화하거나 비활성화되었습니다.
SalaFestival: "Sala Magna" (SALA_CONFERENZE)
├── Configurazione "Teatro"
│ ├── Posti seduti: 200
│ ├── Posti in piedi: 0
│ └── Attiva: true
├── Configurazione "Platea"
│ ├── Posti seduti: 150
│ ├── Posti in piedi: 50
│ └── Attiva: true
└── Configurazione "Standing"
├── Posti seduti: 0
├── Posti in piedi: 300
└── Attiva: false
Capienza massima: max(200, 200, 300) = 300 (tra configurazioni attive: 200)
스탠드: 스탠드페스티벌 및 예약
그만큼 스탠드페스티벌 전시공간을 표현합니다. 는 근본적인 구별과 스탠드 사이 소유하다 (관리 조직에서) e 임대 가능 (제3자에게 임대 가능) 일일 가격 포함).
StandFestival
├── codice: "A01" // Identificativo univoco
├── nome: "Stand Principale"
├── tipo: PROPRIO | AFFITTABILE
├── dimensioniMq: 25.50
├── prezzoGiornaliero: Money // Solo per AFFITTABILE
├── dotazioni: "Tavolo, sedie, corrente elettrica"
├── posizioneMappa: "Padiglione A, Fila 1"
│
└── prenotazioni: Set<PrenotazioneStand>
└── PrenotazioneStand
├── giornataId // Per quale giorno
├── affittuarioNome // Chi affitta
├── affittuarioEmail
├── attivitaNome // Cosa esporra
├── stato: StatoPrenotazione
└── importoPagato: Money // Tracking pagamenti
예약 수명주기
모든 예약은 간단하지만 효과적인 주기를 거칩니다. 스탠드 캔 고유성 제약 조건을 적용하여 특정 날짜에 예약해야 합니다. 같은 스탠드에 대해 두 개의 활성 예약이 있을 수 있습니다. 일.
public enum StatoPrenotazione {
PRENOTATO, // Prenotazione effettuata, in attesa di conferma
CONFERMATO, // Prenotazione confermata e attiva
ANNULLATO // Prenotazione annullata
}
TRANSIZIONI:
PRENOTATO ──conferma──► CONFERMATO
│ │
└──annulla──► ANNULLATO ◄┘
VINCOLI:
- Solo stand AFFITTABILE possono essere prenotati
- Un solo affittuario per stand per giornata
- La prenotazione include tracking dei pagamenti via Money
EventoFestival: 이벤트-당일-홀 연결
엔터티 이벤트축제 이벤트와 이벤트 사이의 다리 축제의 맥락. 특정 날짜에 이벤트를 연결합니다. 정확한 시간과 방에 대한 선택적 할당. 시스템이 확인합니다. 자동으로 같은 방에 겹치는 부분이 없도록 합니다.
public enum TipoEventoFestival {
// Eventi principali (main stage)
MAIN_EVENT, KEYNOTE, CERIMONIA, CONCERTO, SPETTACOLO
// Eventi formativi
TALK, WORKSHOP, PANEL
// Networking e servizi
NETWORKING, REGISTRAZIONE, BREAK, ALTRO
}
ESEMPIO PALINSESTO - Giorno 1:
09:00-09:30 REGISTRAZIONE (Foyer)
09:30-10:30 CERIMONIA apertura (Auditorium)
10:30-11:00 BREAK (Foyer)
11:00-12:00 KEYNOTE speaker (Auditorium)
11:00-12:30 WORKSHOP Angular (Sala Workshop A)
11:00-12:30 WORKSHOP Spring Boot (Sala Workshop B)
12:30-14:00 BREAK pranzo
14:00-14:45 TALK microservizi (Sala Conferenze 1)
14:00-14:45 TALK frontend (Sala Conferenze 2)
15:00-16:30 PANEL "Il futuro del web" (Auditorium)
17:00-18:00 NETWORKING (Area Esterna)
21:00-23:00 CONCERTO (Palco)
오버랩 제어
이벤트가 룸에 할당되면 시스템은 해당 이벤트가 룸에 할당되지 않았는지 확인합니다.
같은 방의 다른 이벤트와 시간적으로 겹칩니다.
두 이벤트가 겹치는 경우 A.oraInizio < B.oraFine AND
A.oraFine > B.oraInizio. 배정된 방이 없는 행사는 진행되지 않습니다.
확인됩니다.
돈이라는 가치를 지닌 예산
페스티벌과 스탠드 모두 Value Object를 사용합니다. Money
금전적인 금액을 관리합니다. 돈은 캡슐화된 불변의 객체이다.
금액 (BigDecimal 규모 2) 및 통화 포함
(String ISO 4217).
@Embeddable
public class Money implements Comparable<Money> {
private BigDecimal amount; // Scala 2, HALF_UP
private String currency; // ISO 4217 (EUR, USD, GBP...)
// Factory methods
Money.of(100.00, "EUR")
Money.euro(50.00)
Money.zero("EUR")
// Operazioni aritmetiche (stessa valuta obbligatoria)
money1.add(money2) // Somma
money1.subtract(money2) // Sottrazione
money1.multiply(1.22) // Moltiplicazione (es: IVA)
money1.divide(3) // Divisione
// Query
money.isPositive()
money.isZero()
money.isGreaterThan(other)
}
USO NEL FESTIVAL:
Festival.budget = Money.euro(50000.00) // Budget totale
StandFestival.prezzoGiornaliero = Money.euro(150.00) // Prezzo affitto/giorno
PrenotazioneStand.importoPagato = Money.euro(450.00) // 3 giorni x 150
돈을 값 개체로 사용하면 돈을 추가할 수 없습니다. 금액이 서로 다른 통화로 표시되고(시스템에서 예외가 발생함) 반올림은 일관됩니다.
축제 나눔
각 축제는 공유 토큰 (8 영숫자)를 통해 페스티벌을 빠르게 공유할 수 있습니다. 링크나 QR코드를 통해 공유를 켜고 끌 수 있습니다 언제든지 주최측에 의해.
핵심 사항
- 국가별로 검증된 두 개의 조직 프로필(회사 및 협회)
- 4가지 계층적 역할과 양방향 초대/요청 워크플로를 갖춘 MembershipOrganization
- 보안 토큰 및 만료를 통해 등록되지 않은 사용자를 초대하는 OrganizationInvitationEmail
- 라이프사이클에 5개 상태가 있는 Aggregate Root DDD와 같은 페스티벌
- 구성 가능한 시간과 자동 생성 기능을 갖춘 DayFestival
- 다양한 구성과 수용 인원 조절이 가능한 8개 객실 유형
- 일일 예약 시스템을 갖춘 OWN 및 RENTABLE 스탠드
- 룸별 오버레이 제어를 통한 12가지 유형의 페스티벌 이벤트
- 예산 관리 및 유형 안전 결제를 위한 화폐 가치 개체
소스 코드는 다음에서 확인할 수 있습니다. GitHub. 실제 조직 및 축제 관리를 살펴보려면 다음을 방문하세요. www.playtheevent.com.







