Skip to content

Adjust age limit#1319

Merged
joshunrau merged 12 commits intoDouglasNeuroInformatics:mainfrom
david-roper:adjust-age-limit
Mar 25, 2026
Merged

Adjust age limit#1319
joshunrau merged 12 commits intoDouglasNeuroInformatics:mainfrom
david-roper:adjust-age-limit

Conversation

@david-roper
Copy link
Copy Markdown
Collaborator

@david-roper david-roper commented Mar 25, 2026

Allows group managers to adjust the minimum age requirement for subjects via the group management form

Removes the current default age minimum of 18

closes issue #1314

Summary by CodeRabbit

  • New Features
    • Group administrators can configure an optional minimum age requirement for sessions and enable/disable it per group.
    • Group management UI includes an Age Limit settings section to set or clear the value.
    • Session creation and validation now honor the configured minimum age and display the configured age in validation messages (EN/FR).

@david-roper david-roper requested a review from joshunrau as a code owner March 25, 2026 17:51
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 25, 2026

Warning

Rate limit exceeded

@david-roper has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 20 minutes and 22 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e4767400-152c-47bd-9ea4-79e4ef07455a

📥 Commits

Reviewing files that changed from the base of the PR and between e97e85c and a81cc90.

📒 Files selected for processing (3)
  • apps/web/src/components/StartSessionForm/StartSessionForm.tsx
  • apps/web/src/routes/_app/group/manage.tsx
  • packages/schemas/src/group/group.ts

Walkthrough

Added configurable minimum-age settings to group configuration: new minimumAge and minimumAgeApplied fields (Prisma + Zod). Group management UI exposes these settings. Start-session form validation now conditionally enforces the group's minimum-age when applied.

Changes

Cohort / File(s) Summary
Schema Updates
apps/api/prisma/schema.prisma, packages/schemas/src/group/group.ts
Added minimumAge: Int? to Prisma GroupSettings and added minimumAge?: number and minimumAgeApplied?: boolean to the Zod $GroupSettings schema.
Session Validation
apps/web/src/components/StartSessionForm/StartSessionForm.tsx
Replaced fixed 18-year DOB constraint with a conditional minimum-age-derived MIN_DATE_OF_BIRTH computed from currentGroup?.settings.minimumAge and minimumAgeApplied; updated Zod validation to conditionally enforce the date constraint and adjusted error messages.
Group Settings Management
apps/web/src/routes/_app/group/manage.tsx
Added "Age Limit Settings" UI (boolean radio minimumAgeApplied, conditional numeric minimumAge), extended form initial values and Zod schema, and included minimumAge / minimumAgeApplied in submission payload.

Sequence Diagram(s)

sequenceDiagram
    participant Admin as Group Admin (UI)
    participant Manage as Manage Group Route
    participant API as API Server
    participant DB as Database (Prisma)
    participant User as Session Starter (UI)
    participant StartForm as StartSessionForm

    Admin->>Manage: submit minimumAge + minimumAgeApplied
    Manage->>API: POST updated group settings
    API->>DB: persist Group.settings (minimumAge, minimumAgeApplied)
    DB-->>API: confirmation
    API-->>Manage: success

    User->>StartForm: open session form
    StartForm->>API: fetch group + settings
    API->>DB: read Group.settings
    DB-->>API: return settings
    API-->>StartForm: settings (minimumAge, minimumAgeApplied)
    StartForm->>StartForm: compute MIN_DATE_OF_BIRTH if applied
    User->>StartForm: submit DOB
    StartForm->>StartForm: validate DOB against MIN_DATE_OF_BIRTH (if present)
    StartForm-->>API: create session (if valid)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Adjust age limit' is concise and directly reflects the main change: adding configurable minimum age settings to group management, removing the hardcoded 18-year default.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/web/src/routes/_app/group/manage.tsx (1)

196-211: ⚠️ Potential issue | 🟠 Major

Require minimumAge when the toggle is enabled.

This schema can submit minimumAgeApplied: true with no minimumAge, and the payload forwards that state unchanged. The session form later treats that like a 0-year cutoff, so the rule silently stops enforcing anything.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/routes/_app/group/manage.tsx` around lines 196 - 211, The schema
currently allows minimumAgeApplied: true without a minimumAge; update the Zod
schema (the object that defines minimumAge and minimumAgeApplied) so that when
minimumAgeApplied is true minimumAge is required and must satisfy the positive
int constraint. Implement this by adding a conditional/refinement on the full
object (e.g. .refine(data => !data.minimumAgeApplied || data.minimumAge != null,
{ message: "minimumAge is required when minimumAgeApplied is true", path:
["minimumAge"] }) or .superRefine) to the schema that defines minimumAge and
minimumAgeApplied, and keep onSubmit (the object assembled for submission in
onSubmit) unchanged so it forwards a guaranteed valid minimumAge when
minimumAgeApplied is true.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/web/src/components/StartSessionForm/StartSessionForm.tsx`:
- Around line 181-195: subjectDateOfBirth currently remains optional so users
selecting CUSTOM_ID can skip DOB; change the validation so DOB is required
whenever the group minimum-age is active (MIN_DATE_OF_BIRTH /
currentGroup?.settings.minimumAge is set). Replace the .optional() behavior with
a refine that first enforces presence when MIN_DATE_OF_BIRTH exists (e.g.,
return false if MIN_DATE_OF_BIRTH && !date) and then checks date <=
MIN_DATE_OF_BIRTH; update the refine error message accordingly so the schema for
subjectDateOfBirth (and any logic that checks CUSTOM_ID) will fail when DOB is
missing while the age limit is enabled.
- Around line 181-195: The server is missing age validation for
subjectData.dateOfBirth when creating sessions; update sessionsService.create to
enforce group.settings.minimumAge after you load the group (or alternatively add
a context-aware refinement to $CreateSessionData if you propagate group info
into validation). Specifically, after retrieving group in
sessionsService.create, if subjectData.dateOfBirth and group.settings.minimumAge
are present compute a cutoff date = today minus group.settings.minimumAge years
and if subjectData.dateOfBirth is after that cutoff (i.e. subject is too young)
throw a clear bad-request/validation error (e.g., TRPCError with code
'BAD_REQUEST' or a ValidationError) with the same message used client-side
("Subject must be above age of ...") so server-side behavior matches the client.

In `@apps/web/src/routes/_app/group/manage.tsx`:
- Around line 35-37: The form's initialValues (constructed in the useMemo block)
doesn't copy currentGroup.settings.minimumAge or minimumAgeApplied, so existing
groups render blank; update the initialValues object inside useMemo to read from
currentGroup.settings.minimumAge and currentGroup.settings.minimumAgeApplied
(falling back to defaults as other fields do) so the form controls reflect saved
values, and apply the same change to the other initialValues construction
referenced around the other useMemo/initialization area that builds the form
state (ensure you update the same keys: minimumAge and minimumAgeApplied).

---

Outside diff comments:
In `@apps/web/src/routes/_app/group/manage.tsx`:
- Around line 196-211: The schema currently allows minimumAgeApplied: true
without a minimumAge; update the Zod schema (the object that defines minimumAge
and minimumAgeApplied) so that when minimumAgeApplied is true minimumAge is
required and must satisfy the positive int constraint. Implement this by adding
a conditional/refinement on the full object (e.g. .refine(data =>
!data.minimumAgeApplied || data.minimumAge != null, { message: "minimumAge is
required when minimumAgeApplied is true", path: ["minimumAge"] }) or
.superRefine) to the schema that defines minimumAge and minimumAgeApplied, and
keep onSubmit (the object assembled for submission in onSubmit) unchanged so it
forwards a guaranteed valid minimumAge when minimumAgeApplied is true.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a6052e26-5785-4262-8c4e-a87bc5c2f719

📥 Commits

Reviewing files that changed from the base of the PR and between a850d30 and 9119ca1.

📒 Files selected for processing (4)
  • apps/api/prisma/schema.prisma
  • apps/web/src/components/StartSessionForm/StartSessionForm.tsx
  • apps/web/src/routes/_app/group/manage.tsx
  • packages/schemas/src/group/group.ts

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/web/src/routes/_app/group/manage.tsx (1)

189-198: ⚠️ Potential issue | 🟠 Major

Align the schema with the new nullable settings.

initialValues now carries null for minimumAge, minimumAgeApplied, and subjectIdDisplayLength, but the validation schema still uses .optional(), which rejects null in Zod v3. This breaks the ability to clear these settings and prevents validation of persisted null values. Additionally, there's no constraint ensuring minimumAgeApplied: true requires minimumAge != null.

Suggested fix
-      validationSchema={z.object({
+      validationSchema={z
+        .object({
         accessibleFormInstrumentIds: z.set(z.string()),
         accessibleInteractiveInstrumentIds: z.set(z.string()),
         defaultIdentificationMethod: $SubjectIdentificationMethod.optional(),
         idValidationRegex: $RegexString.optional(),
         idValidationRegexErrorMessageEn: z.string().optional(),
         idValidationRegexErrorMessageFr: z.string().optional(),
-        minimumAge: z.number().int().positive().optional(),
-        minimumAgeApplied: z.boolean().optional(),
-        subjectIdDisplayLength: z.number().int().min(1).optional()
-      })}
+        minimumAge: z.number().int().positive().nullish(),
+        minimumAgeApplied: z.boolean().nullish(),
+        subjectIdDisplayLength: z.number().int().min(1).nullish()
+      })
+        .refine((values) => !values.minimumAgeApplied || values.minimumAge != null, {
+          message: t({
+            en: 'Minimum age is required when the setting is enabled',
+            fr: "L'âge minimum est requis lorsque le paramètre est activé"
+          }),
+          path: ['minimumAge']
+        })}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/routes/_app/group/manage.tsx` around lines 189 - 198, The Zod
schema in validationSchema must accept nulls and enforce the dependency rule:
change minimumAge, minimumAgeApplied, and subjectIdDisplayLength to accept null
by using .nullable() (e.g., minimumAge: z.number().int().positive().nullable(),
minimumAgeApplied: z.boolean().nullable(), subjectIdDisplayLength:
z.number().int().min(1).nullable()), and add a refinement (use .superRefine or
.refine) on the top-level object to ensure that when minimumAgeApplied === true
the minimumAge is not null (and is a valid number); update the validationSchema
object accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@apps/web/src/routes/_app/group/manage.tsx`:
- Around line 189-198: The Zod schema in validationSchema must accept nulls and
enforce the dependency rule: change minimumAge, minimumAgeApplied, and
subjectIdDisplayLength to accept null by using .nullable() (e.g., minimumAge:
z.number().int().positive().nullable(), minimumAgeApplied:
z.boolean().nullable(), subjectIdDisplayLength:
z.number().int().min(1).nullable()), and add a refinement (use .superRefine or
.refine) on the top-level object to ensure that when minimumAgeApplied === true
the minimumAge is not null (and is a valid number); update the validationSchema
object accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: b649ce3e-ed4e-44ed-a0dd-74bd1697499e

📥 Commits

Reviewing files that changed from the base of the PR and between 9119ca1 and 03e9b76.

📒 Files selected for processing (1)
  • apps/web/src/routes/_app/group/manage.tsx

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
apps/api/prisma/schema.prisma (1)

102-102: Optional: Add minimumAgeApplied to Prisma GroupSettings for schema consistency.

The web layer uses minimumAgeApplied as an explicit boolean flag, but Prisma only stores minimumAge. The app works correctly by deriving the flag from whether minimumAge is set (line 266 in manage.tsx), but adding minimumAgeApplied to the schema would make the design explicit rather than implicit.

Suggested addition
 type GroupSettings {
   defaultIdentificationMethod   SubjectIdentificationMethod
   idValidationRegex             String?
   idValidationRegexErrorMessage ErrorMessage?
   subjectIdDisplayLength        Int?
   minimumAge                    Int?
+  minimumAgeApplied             Boolean?
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/api/prisma/schema.prisma` at line 102, Add an explicit optional boolean
field minimumAgeApplied to the Prisma model GroupSettings to match the web
layer's flag (in addition to the existing minimumAge Int?), update any generated
Prisma types by running a migration/generate step, and adjust code that
constructs/reads GroupSettings (e.g., places that set or derive
minimumAgeApplied such as the logic referenced in manage.tsx) to read/write the
new boolean instead of inferring it solely from minimumAge where appropriate.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@apps/api/prisma/schema.prisma`:
- Line 102: Add an explicit optional boolean field minimumAgeApplied to the
Prisma model GroupSettings to match the web layer's flag (in addition to the
existing minimumAge Int?), update any generated Prisma types by running a
migration/generate step, and adjust code that constructs/reads GroupSettings
(e.g., places that set or derive minimumAgeApplied such as the logic referenced
in manage.tsx) to read/write the new boolean instead of inferring it solely from
minimumAge where appropriate.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: acd5698d-3c8f-484b-8502-390fd09f6ee3

📥 Commits

Reviewing files that changed from the base of the PR and between 03e9b76 and e97e85c.

📒 Files selected for processing (1)
  • apps/api/prisma/schema.prisma

@david-roper david-roper requested a review from joshunrau March 25, 2026 20:19
@joshunrau joshunrau merged commit b31b635 into DouglasNeuroInformatics:main Mar 25, 2026
1 check passed
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.

2 participants