feat(election): relational agenda items, email redesign, and stale-cache fix

- Add CommitteeMeetingAgenda entity + repository for relational agenda storage
- Liquibase migration 0353: create m_election_committee_meeting_agenda table,
  drop old agenda TEXT column from m_election_committee_meeting
- Update CommitteeMeeting: replace String agenda with List<CommitteeMeetingAgenda>
  (EAGER, no cascade — writes handled explicitly via repository)
- Update CommitteeMeetingRepository: explicit JPQL with SELECT DISTINCT + LEFT JOIN
  FETCH to load agendaItems and prevent NonUniqueResultException on Optional returns
- Fix email sending stale agenda: inject EntityManager, call refresh() after
  agendaRepository.flush() so EclipseLink reloads the collection from DB
- Redesign buildMeetingInviteHtml: table-based email layout, icon+label+value rows,
  amber agenda section with numbered badges, compact two-column footer

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Jaanu423
2026-07-06 16:53:32 +05:30
co-authored by Claude Sonnet 4.6
parent e72b9359c1
commit 73db4ee114
9 changed files with 404 additions and 29 deletions
@@ -380,4 +380,5 @@
<include file="parts/0350_committee_image.xml" relativeToChangelogFile="true"/>
<include file="parts/0351_committee_meeting.xml" relativeToChangelogFile="true"/>
<include file="parts/0352_committee_meeting_rename_audit_cols.xml" relativeToChangelogFile="true"/>
<include file="parts/0353_committee_meeting_agenda.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
<changeSet id="0353-committee-meeting-agenda-table" author="CBS">
<preConditions onFail="MARK_RAN">
<not><tableExists tableName="m_election_committee_meeting_agenda"/></not>
</preConditions>
<createTable tableName="m_election_committee_meeting_agenda">
<column name="id" type="BIGSERIAL">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="meeting_id" type="BIGINT">
<constraints nullable="false"/>
</column>
<column name="agenda_item" type="TEXT">
<constraints nullable="false"/>
</column>
<column name="display_order" type="INT" defaultValueNumeric="0">
<constraints nullable="false"/>
</column>
</createTable>
<addForeignKeyConstraint
baseTableName="m_election_committee_meeting_agenda"
baseColumnNames="meeting_id"
referencedTableName="m_election_committee_meeting"
referencedColumnNames="id"
constraintName="fk_meeting_agenda_meeting"
onDelete="CASCADE"/>
<createIndex tableName="m_election_committee_meeting_agenda" indexName="idx_meeting_agenda_meeting_id">
<column name="meeting_id"/>
<column name="display_order"/>
</createIndex>
</changeSet>
<changeSet id="0353-drop-meeting-agenda-column" author="CBS">
<preConditions onFail="MARK_RAN">
<columnExists tableName="m_election_committee_meeting" columnName="agenda"/>
</preConditions>
<dropColumn tableName="m_election_committee_meeting" columnName="agenda"/>
</changeSet>
</databaseChangeLog>