Skip to content

feat: automated seminar invitations#4968

Open
CLC0609 wants to merge 6 commits into
VATSIM-UK:mainfrom
CLC0609:tech-329-automate-obs-s1-seminar-arrangement
Open

feat: automated seminar invitations#4968
CLC0609 wants to merge 6 commits into
VATSIM-UK:mainfrom
CLC0609:tech-329-automate-obs-s1-seminar-arrangement

Conversation

@CLC0609

@CLC0609 CLC0609 commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Parts of TECH-329

Summary of changes

A fairly simple version of what was requested in TECH-329. Currently the implemented workflow looks like:

  • TGI creates a seminar, links a waiting list, and sets a maximum capacity
  • TGI specifies an expiry time for the invitations to last
  • TGI can see the waiting list they have linked, manually invite members from the list, or, invite members who are not on the list via a modal. TGIs can invite anyone irrelevant of their theory exam status
  • Once the TGI has done the manual invites, they can start automatic invites, which works as follows:
    • Invites members who have completed the theory exam, from the top of the waiting list, until capacity - (number of pending invites + number of confirmed attendees) = 0. This means there will only ever be capacity number of potential people invited at any time
    • If someone declines
      • for "Not Interested" - they are removed from the waiting list
      • for "Cannot Attend" - if it's their first Cannot Attend its logged and they remain, if its their 2nd they are removed
    • Either way, the automatic invite system will then fire another invitation to the next person who has completed the theory exam
    • Invitations stop sending when one of two things happen
      • The seminar is closed manually by an Admin
      • When the expiry time would take the invite past the seminar start date and time. e.g. if the expiry is 7 days, invites will stop sending 7 days prior to the event, meaning everyone gets equal time to accept invitations
    • Invitations that expire get cleaned up by a job that runs at 11:30 each day, member is removed from waiting list, if automatic invites enabled, another one is sent
  • TGI can see the status of all invitations and all confirmed attendees
  • TGI can create Training Place from the Attendees list

What it doesn't do:
The spec requested was fairly large, and with this PR already 3000+ lines, I think it's best to leave these for another one, but most of the groundwork is here to make those fairly simple.

  • No email is sent to students who have failed to complete the CTS theory exam, or follow up emails
  • No workflow after the invitation process
  • No moodle integration

Syncs with CTS group_session_* tables to allow the later part of the workflow to be done on the CTS for now.

Screenshots (if necessary)

image image

Awaiting copy text

@CLC0609 CLC0609 added the on-hold label Jul 3, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements the initial “automated seminar invitations” workflow (TECH-329 groundwork) by introducing training seminars, invitations, attendee tracking, CTS group session syncing, and a scheduled expiry process, surfaced through a new Filament Training “Seminars” resource and member-facing invitation response pages.

Changes:

  • Added Seminar/Invitation/Attendee domain models, migrations, factories, and services to send/track invitations and create attendees.
  • Added member routes + controller + Blade views for accepting/declining seminar invitations, plus an expiry command scheduled daily.
  • Added CTS sync support (group session + students) via a service and observers, with corresponding tests and CTS test DB schema additions.

Reviewed changes

Copilot reviewed 43 out of 43 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/Unit/Training/Seminar/SeminarInvitationServiceTest.php Unit coverage for invitation sending/accept/decline/expiry behaviors.
tests/Unit/Training/Seminar/SeminarCtsSyncServiceTest.php Unit coverage for syncing seminars/attendees into CTS tables.
tests/Feature/Training/Seminar/SeminarInvitationControllerTest.php Feature coverage for member invitation response endpoints and authorization.
tests/Feature/Training/Seminar/CheckForExpiredSeminarInvitationsCommandTest.php Feature coverage for the scheduled expiry command behavior.
tests/Database/MockCtsDatabase.php Extends mocked CTS schema to include group session tables used by the sync service.
routes/web-main.php Adds member routes for seminar invitation accept/decline actions by token.
resources/views/training/seminar-invitation/result.blade.php Member-facing result page for accept/decline flows.
resources/views/training/seminar-invitation/expired.blade.php Member-facing page for expired/invalid/non-respondable invitations.
resources/views/emails/training/seminar_invitation.blade.php Email template for seminar invitations with response links.
database/seeders/RolesAndPermissionsSeeder.php Adds permissions for viewing/managing seminars in Filament.
database/migrations/2026_07_02_100020_create_training_seminar_attendees_table.php Creates attendee table (incl. CTS student ID back-reference).
database/migrations/2026_07_02_100010_create_training_seminar_invitations_table.php Creates invitations table with token + status + expiry fields.
database/migrations/2026_07_02_100000_create_training_seminars_table.php Creates seminars table with capacity, expiry window, and CTS session ID.
database/factories/Training/Seminar/SeminarInvitationFactory.php Factory + states for invitations used in tests.
database/factories/Training/Seminar/SeminarFactory.php Factory + states for seminars (closed/automatic/past/CTS session).
database/factories/Training/Seminar/SeminarAttendeeFactory.php Factory for seminar attendees used in tests.
app/Services/Training/SeminarInvitationService.php Core invitation logic (top-up, create, accept/decline, expiry cleanup).
app/Services/Training/SeminarCtsSyncService.php Syncs core seminars/attendees into legacy CTS group session tables.
app/Observers/Training/SeminarObserver.php Triggers CTS sync when seminars are created/updated.
app/Observers/Training/SeminarAttendeeObserver.php Triggers CTS sync when attendees are created.
app/Notifications/Training/SeminarInvitationNotification.php Notification that renders the seminar invitation email.
app/Models/Training/WaitingList/RemovalReason.php Adds waiting list removal reasons for seminar invitation outcomes.
app/Models/Training/Seminar/SeminarInvitation.php Invitation model with enum cast and response eligibility logic.
app/Models/Training/Seminar/SeminarAttendee.php Attendee model + observer binding.
app/Models/Training/Seminar/Seminar.php Seminar model with capacity/cutoff calculations and relations.
app/Models/Mship/Concerns/HasSeminarInvitations.php Adds invitation relationship + cannot-attend counting on Account.
app/Models/Mship/Account.php Wires in the seminar invitations trait.
app/Models/Cts/GroupSessionStudent.php CTS model for group session student join table.
app/Models/Cts/GroupSession.php CTS model for group sessions.
app/Http/Controllers/Mship/Training/SeminarInvitationController.php Member controller for responding to invitations by token.
app/Filament/Training/Resources/TrainingPlaces/TrainingPlaceResource.php Adjusts navigation sort to accommodate new Seminars navigation ordering.
app/Filament/Training/Resources/Seminars/Widgets/SeminarStatsOverview.php Adds per-seminar stats widget (sent/pending/declined/attendees).
app/Filament/Training/Resources/Seminars/SeminarResource.php New Filament resource for creating/viewing seminars and managing relations.
app/Filament/Training/Resources/Seminars/RelationManagers/WaitingListRelationManager.php Shows waiting list accounts + supports manual invitations.
app/Filament/Training/Resources/Seminars/RelationManagers/InvitationsRelationManager.php Lists invitations and their statuses in Filament.
app/Filament/Training/Resources/Seminars/RelationManagers/AttendeesRelationManager.php Lists attendees and supports creating Training Places from attendees.
app/Filament/Training/Resources/Seminars/Pages/ViewSeminar.php Seminar view page actions (enable/disable auto invites, close seminar).
app/Filament/Training/Resources/Seminars/Pages/ListSeminars.php List page for seminars.
app/Filament/Training/Resources/Seminars/Pages/EditSeminar.php Edit page for seminars.
app/Filament/Training/Resources/Seminars/Pages/CreateSeminar.php Create page for seminars (sets created_by to current user).
app/Enums/SeminarInvitationStatus.php Enum for invitation statuses incl. label/color/responded helpers.
app/Console/Kernel.php Schedules the daily seminar invitation expiry check at 11:30.
app/Console/Commands/Training/CheckForExpiredSeminarInvitations.php Command wrapper to run the expiry cleanup service method.

Comment thread app/Services/Training/SeminarInvitationService.php
Comment thread app/Filament/Training/Resources/Seminars/SeminarResource.php
Comment thread resources/views/training/seminar-invitation/expired.blade.php Outdated
CLC0609 and others added 3 commits July 3, 2026 10:45
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@CLC0609

CLC0609 commented Jul 3, 2026

Copy link
Copy Markdown
Contributor Author

Fixes TECH-681

@kristiankunc kristiankunc self-requested a review July 3, 2026 13:20
Comment thread app/Services/Training/SeminarInvitationService.php
Comment thread app/Enums/SeminarInvitationStatus.php
@CLC0609 CLC0609 marked this pull request as ready for review July 4, 2026 17:05
@CLC0609 CLC0609 requested a review from AxonC July 4, 2026 17:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants