Skip to content

Conversation

@yuanchen233
Copy link
Collaborator

@yuanchen233 yuanchen233 commented Oct 22, 2025

… to RecruitmentService

Also marks InviteNewParticipantGroup Endpoint and related method as deprecated, and replace their usage with new create and invite method respectively.


  • I did not include connectedDevicePreregistration here, as I think it should be a separate issue/commit.
  • I did not include 'add UpdateParticipantGroup endpoint' in this PR, to keep thing clean here.

Qs:

  • Should test cases related to inviteNewParticipant be removed? as its functionalities are now in create and invite, respectively and we have coverage for them. So some suppress can be removed. ( Kotlin compiler fails it even the deprecation level is warning )

TODO(not for this PR):

  1. Update 'stopParticipantGroup' parameter in the order from the most relevant one to secondary ones.
  2. Create an issue to keep all creation endpoint consistent: let user pass IDs.
  3. Create new endpoint UpdateParticipantGroup

@yuanchen233 yuanchen233 marked this pull request as ready for review October 23, 2025 07:05
Copy link
Member

@Whathecode Whathecode left a comment

Choose a reason for hiding this comment

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

Only reviewed the interface for now.

Copy link
Member

@Whathecode Whathecode left a comment

Choose a reason for hiding this comment

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

Reviewed RecruitmentServiceHost. Primarily, we should try to come to a decision on whether or not we want idempotency and then pursue something consistent.

@yuanchen233 yuanchen233 force-pushed the separate-crate-and-invite-participant-group branch 2 times, most recently from 2ddb36c to f7d527e Compare November 2, 2025 14:09
Copy link
Member

@Whathecode Whathecode left a comment

Choose a reason for hiding this comment

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

Still reviewing, but here are some further comments. :)

@yuanchen233 yuanchen233 force-pushed the separate-crate-and-invite-participant-group branch 3 times, most recently from 3226b5c to 37280cd Compare November 8, 2025 09:32
@yuanchen233 yuanchen233 force-pushed the separate-crate-and-invite-participant-group branch from 37280cd to 0b74cb5 Compare November 10, 2025 11:26
… to RecruitmentService

Also marks `InviteNewParticipantGroup` Endpoint and related method as deprecated, and replace their usage with new create and invite method respectively.
@yuanchen233 yuanchen233 force-pushed the separate-crate-and-invite-participant-group branch from 0b74cb5 to 8924bff Compare November 10, 2025 11:47
Copy link
Member

@Whathecode Whathecode left a comment

Choose a reason for hiding this comment

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

Some minor comments, but then I ran into the getRecruitments() method on the repository, which is a bigger problem and I'll already post now so you can fix it while I continue reviewing later on. :)

* - a study with [studyId] does not exist
* - an existing participant group with [groupId] already exists
* - any of the participant roles specified in [group] does not exist
* @throws IllegalStateException when the study is not yet ready for deployment.
Copy link
Member

Choose a reason for hiding this comment

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

Re-reading this again, I think this exception warrants a bit more explanation. I would add:

As long as no final study protocol is locked in for the study, a participant group can't be created since participant roles to which participants need to be assigned are unknown.

Don't forget to also update RecruitmentServiceHost. :)

That's at least where the current limitation comes from. But, that does seem limiting and perhaps a useful area to improve functionality for later on.

In the main use case there is only a single participant and participant roles are irrelevant. That's why AssignTo.All exists. If group only contains AssignTo.All, that should be a valid configuration for any study protocol, even if it changes after.

And/or, maybe it is fine to only validate the assignments in context of the current protocol, make the assignments nullable, and simply invalidate existing role assignments when a new protocol is set.

Does this make sense? If so, we should likely spin off a new feature/discussion issue for this.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, this feature would decouple study setup from inviting participants. So as a researcher, I can recruit participant before finalize technical details "protocol".

In the main use case there is only a single participant and participant roles are irrelevant. That's why AssignTo.All exists. If group only contains AssignTo.All, that should be a valid configuration for any study protocol, even if it changes after.

Since protocol also defines the number of participant, AssignTo.All could be misused here. But yep, the discussion should be hold in a separate issue.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Re-reading this again, I think this exception warrants a bit more explanation. I would add:
As long as no final study protocol is locked in for the study, a participant group can't be created since participant roles to which participants need to be assigned are unknown.

Should this also be added to Recruitment.addParticipantGroup's documentation, or the error message?

* Invite the participant group with the specified [groupId] to start participating in its study.
*
* @throws IllegalArgumentException when:
* - the participant group with [groupId] does not exist.
Copy link
Member

Choose a reason for hiding this comment

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

Minor: drop punctuation at the end. Seemingly it's not used in any of the other bullet lists.

participantRepository.getRecruitment( studyId )
?: throw IllegalArgumentException( "Study with ID \"$studyId\" not found." )

private suspend fun getRecruitmentAndGroupByGroupIdOrThrow(
Copy link
Member

Choose a reason for hiding this comment

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

I think you can safely drop "ByGroupId" as that is already documented by the parameter name.

/**
* Returns all stored [Recruitment]s.
*/
suspend fun getRecruitments(): List<Recruitment>
Copy link
Member

@Whathecode Whathecode Nov 12, 2025

Choose a reason for hiding this comment

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

This is a very bad idea. It's a full table dump and will inevitably get slower and slower.

I guess you added this to be able to drop the studyId parameter. But, the way the repository pattern in DDD works is that you are supposed to expose the queries you need from the domain layer in the interface (the use cases), instead of the very typical simplistic CRUD operations and end up writing query code in the layer above.

So, instead what we likely need is a getRecruitmentWithParticipantGroup( groupId ). This can be optimized by whatever underlying DB technology and doesn't pull in unnecessary data.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants