Skip to content

feat(Coordly): Add member management and invitation workflows - #185

Merged
OmarZaatari merged 6 commits into
coordly-chadi-omarfrom
coordly/member-management-crud
Jul 22, 2026
Merged

feat(Coordly): Add member management and invitation workflows#185
OmarZaatari merged 6 commits into
coordly-chadi-omarfrom
coordly/member-management-crud

Conversation

@chko0

@chko0 chko0 commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

Description

  • Adds member management CRUD support for organization administrators and super admins.
  • Adds member invitation workflows, including invite, resend, revoke, and public invitation acceptance.
  • Adds shared contract schemas and response types for member create/update actions and member invitations.
  • Adds a MemberInvitation Prisma model and migration for storing invitation metadata, token hashes, expiration, and acceptance state.
  • Updates the members page to support managing members and pending invitations from the web app.
  • Updates web hooks to support member mutations, invitation mutations, and cache invalidation.
  • Allows /invite/accept to be accessed without an authenticated session so invited users can accept invitations.

Link to issue or ticket

N/A

Steps to QA

  • Run npx turbo run db:generate.
  • Run npx turbo run db:deploy.
  • Run npx turbo run check-types.
  • Sign in as an org admin and open /members.
  • Create a member and verify the new member appears in the members list.
  • Edit a member and verify the updated values persist after refresh.
  • Delete a member and verify the member is removed from the members list.
  • Invite a member by email and verify the pending invitation appears in the invitations list.
  • Resend and revoke an invitation and verify the invitation list updates correctly.
  • Open /invite/accept?token=<valid-token> while signed out and verify the invitation is accepted, a session is created, and the user is redirected to /dashboard.

Screenshots

image image image image

Summary by CodeRabbit

  • New Features
    • Expanded organization-scoped member management (create, view, edit, delete) with updated listing behavior.
    • Added member invitation lifecycle: list pending, send, resend, revoke, and accept via token.
    • Invitation acceptance now automatically signs the user in and redirects to the dashboard (with a dedicated invite-accept page).
    • Refreshed the Members page with typed dialogs/forms, role badges, expiration display, email/login column, row actions, and confirmation flows.

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds member CRUD and invitation lifecycle support across Prisma, API contracts, backend services, web hooks, authenticated management UI, and a public invitation-acceptance page.

Changes

Member invitations and management

Layer / File(s) Summary
Invitation contracts and persistence
packages/contracts/src/members/*, packages/database/prisma/...
Adds typed Zod contracts and persists invitations through Prisma models, relations, indexes, and migrations.
Member and invitation service workflows
apps/api/src/members/members.service.ts, apps/api/src/auth/session.service.ts
Implements scoped member CRUD, invitation lifecycle operations, token hashing, email queueing, transactional acceptance, and session creation.
Members API endpoints and module wiring
apps/api/src/members/members.controller.ts, apps/api/src/members/members.module.ts
Exposes validated member and invitation endpoints, sets the acceptance session cookie, and wires authentication and mail modules.
Typed web actions and route access
apps/web/hooks/use-auth.ts, apps/web/hooks/use-members.ts, apps/web/proxy.ts
Adds typed mutation hooks, SWR invalidation, invitation acceptance, and public access for /invite/accept.
Member management and invitation acceptance UI
apps/web/app/(authenticated)/members/page.tsx, apps/web/app/invite/accept/page.tsx
Adds member and invitation dialogs, tables, lifecycle controls, and token acceptance states.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant InvitePage
  participant useAuth
  participant MembersController
  participant MembersService
  participant SessionService
  InvitePage->>useAuth: acceptMemberInvitation({ token })
  useAuth->>MembersController: POST /members/invitations/accept
  MembersController->>MembersService: acceptInvitation(token)
  MembersService->>SessionService: createSession(userId, transaction)
  SessionService-->>MembersService: sessionId
  MembersService-->>MembersController: accepted user
  MembersController-->>useAuth: user response and session cookie
  useAuth-->>InvitePage: success response
  InvitePage->>InvitePage: redirect to /dashboard
Loading

Possibly related PRs

Suggested labels: enhancement

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: member management plus invitation workflows.
Description check ✅ Passed The description matches the template with Description, ticket, QA steps, and screenshots sections filled out.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch coordly/member-management-crud

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (3)
apps/web/hooks/use-members.ts (1)

55-62: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Same invalidation anti-pattern in both hooks: undefined data arg wipes the cache and swrMutate() double-fetches. Both invalidation helpers reset matched /members* cache entries to undefined (causing an empty-state flash during revalidation) and redundantly call swrMutate() on a key already covered by the matcher. Revalidate without clearing.

  • apps/web/hooks/use-members.ts#L55-L62: replace swrMutate() + mutate(matcher, undefined, { revalidate: true }) with mutate(matcher) in invalidateMembers.
  • apps/web/hooks/use-members.ts#L132-L139: apply the identical change in invalidateInvitations.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/hooks/use-members.ts` around lines 55 - 62, The invalidation helpers
clear cached data and redundantly fetch the same key. In
apps/web/hooks/use-members.ts lines 55-62, update invalidateMembers to replace
swrMutate() and the matcher call with mutate(matcher); apply the identical
change to invalidateInvitations at lines 132-139, preserving cached data while
triggering revalidation.
apps/web/app/invite/accept/page.tsx (1)

19-49: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Guard the acceptance call against double invocation.

Invitation acceptance is a non-idempotent, single-use-token operation (it marks the invitation accepted and creates a session). Under React 19 Strict Mode this effect mounts twice in development, firing accept() twice; the second call runs against an already-consumed token and can flip a successful acceptance into the error state. A useRef one-shot guard keeps the mutation firing exactly once.

🛡️ Suggested guard
+  const hasAccepted = useRef(false);
+
   useEffect(() => {
     const token = searchParams.get('token');

     if (!token) {
       setStatus('error');
       setErrorMessage('Invalid or missing invitation token');
       return;
     }

+    if (hasAccepted.current) return;
+    hasAccepted.current = true;
+
     const accept = async () => {

Remember to import useRef.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/app/invite/accept/page.tsx` around lines 19 - 49, Guard the
invitation acceptance effect with a useRef one-shot flag so
acceptMemberInvitation is invoked only once, including under React Strict Mode’s
duplicate effect execution. Import useRef, check the guard before starting
accept(), and mark it before the mutation; preserve the existing success,
redirect, and error handling.
apps/api/src/members/members.service.ts (1)

387-414: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate token-generation/mail-enqueue logic between invite() and resendInvitation().

Both methods independently generate a token, hash it, compute expiresAt, build invitationLink from process.env.APP_URL, and enqueue MAIL_JOBS.SEND_INVITATION with the same payload shape. Extracting a private helper (e.g. issueInvitationToken(invitation)) would remove this duplication and keep the mail-job payload in one place going forward.

Also applies to: 439-461

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/members/members.service.ts` around lines 387 - 414, The
invitation token and email queuing logic is duplicated between invite() and
resendInvitation(). Extract the shared token generation, hashing, expiry,
invitation-link construction, and MAIL_JOBS.SEND_INVITATION enqueue payload into
a private helper such as issueInvitationToken, then have both methods call it
while preserving their existing invitation data and response behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/api/src/members/members.controller.ts`:
- Around line 91-107: Apply Nest’s ParseUUIDPipe to every `@Param`('id') in the
members controller, including findOne, update, remove, resendInvitation, and
revokeInvitation. Keep the existing service calls and response behavior
unchanged so malformed IDs are rejected as 400 responses before reaching Prisma.

In `@apps/api/src/members/members.service.ts`:
- Around line 491-604: The acceptInvitation flow consumes the invitation before
session creation can succeed, risking a committed user/member with no retryable
invitation when createSession fails. Adjust acceptInvitation and its transaction
so session creation is included in the same atomic unit when supported, or move
the acceptedAt update until after sessionService.createSession succeeds while
preserving rollback/retry behavior on session-store failure.
- Around line 205-233: Update create() to validate that the resolved
organizationId references an existing Organization before calling
prisma.member.create, reusing the same lookup and NotFoundException behavior as
invite(). Keep the existing username validation and member creation flow
unchanged when the organization exists.

In `@apps/web/app/`(authenticated)/members/page.tsx:
- Around line 63-66: Update the ROLE_COLORS mapping to use the design-token
classes defined in globals.css instead of the arbitrary blue and purple Tailwind
palette classes, while preserving distinct styling for ADMIN and PRESENTER
badges.

In `@packages/database/prisma/schema.prisma`:
- Around line 207-210: Add a Prisma index for the invitedById foreign key in the
affected model, alongside the existing organizationId, email, and expiresAt
indexes, while preserving the private schema declaration.

---

Nitpick comments:
In `@apps/api/src/members/members.service.ts`:
- Around line 387-414: The invitation token and email queuing logic is
duplicated between invite() and resendInvitation(). Extract the shared token
generation, hashing, expiry, invitation-link construction, and
MAIL_JOBS.SEND_INVITATION enqueue payload into a private helper such as
issueInvitationToken, then have both methods call it while preserving their
existing invitation data and response behavior.

In `@apps/web/app/invite/accept/page.tsx`:
- Around line 19-49: Guard the invitation acceptance effect with a useRef
one-shot flag so acceptMemberInvitation is invoked only once, including under
React Strict Mode’s duplicate effect execution. Import useRef, check the guard
before starting accept(), and mark it before the mutation; preserve the existing
success, redirect, and error handling.

In `@apps/web/hooks/use-members.ts`:
- Around line 55-62: The invalidation helpers clear cached data and redundantly
fetch the same key. In apps/web/hooks/use-members.ts lines 55-62, update
invalidateMembers to replace swrMutate() and the matcher call with
mutate(matcher); apply the identical change to invalidateInvitations at lines
132-139, preserving cached data while triggering revalidation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: c547eeaf-c16b-4294-9d25-d53d8f8100d9

📥 Commits

Reviewing files that changed from the base of the PR and between 6d52850 and 1a6d86e.

📒 Files selected for processing (21)
  • apps/api/src/members/members.controller.ts
  • apps/api/src/members/members.module.ts
  • apps/api/src/members/members.service.ts
  • apps/web/app/(authenticated)/members/page.tsx
  • apps/web/app/invite/accept/page.tsx
  • apps/web/hooks/use-auth.ts
  • apps/web/hooks/use-members.ts
  • apps/web/proxy.ts
  • packages/contracts/src/members/index.ts
  • packages/contracts/src/members/member-action.response.ts
  • packages/contracts/src/members/member-create.request.ts
  • packages/contracts/src/members/member-invitation-accept.request.ts
  • packages/contracts/src/members/member-invitation-accept.response.ts
  • packages/contracts/src/members/member-invitation-action.response.ts
  • packages/contracts/src/members/member-invitation-list.response.ts
  • packages/contracts/src/members/member-invitation.response.ts
  • packages/contracts/src/members/member-invite.request.ts
  • packages/contracts/src/members/member-update.request.ts
  • packages/contracts/src/members/member.response.ts
  • packages/database/prisma/migrations/20260717183454_add_member_invitations/migration.sql
  • packages/database/prisma/schema.prisma

Comment thread apps/api/src/members/members.controller.ts
Comment thread apps/api/src/members/members.service.ts
Comment thread apps/api/src/members/members.service.ts
Comment thread apps/web/app/(authenticated)/members/page.tsx
Comment thread packages/database/prisma/schema.prisma
@chko0

chko0 commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/database/prisma/migrations/20260721183637_add_member_invitation_invited_by_index/migration.sql (1)

2-2: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Avoid blocking writes during production index creation.

Use CREATE INDEX CONCURRENTLY for this live-table index, and verify that the migration runner does not wrap it in a transaction because PostgreSQL disallows concurrent index creation inside one.

Proposed change
-CREATE INDEX "MemberInvitation_invitedById_idx" ON "private"."MemberInvitation"("invitedById");
+CREATE INDEX CONCURRENTLY "MemberInvitation_invitedById_idx" ON "private"."MemberInvitation"("invitedById");
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/database/prisma/migrations/20260721183637_add_member_invitation_invited_by_index/migration.sql`
at line 2, Update the MemberInvitation_invitedById_idx migration to use
concurrent index creation, and configure this migration so the runner executes
it outside a transaction, preserving PostgreSQL’s requirement for concurrent
indexes.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/api/src/auth/session.service.ts`:
- Around line 27-36: Update createSession so the Redis setex write occurs only
after the database transaction has successfully resolved, ensuring rollback
leaves no Redis-only session and Redis failures do not affect the transaction.
Keep the existing prisma.session.create persistence and return behavior intact,
and use the post-transaction path or established outbox/retry mechanism for the
Redis write.

---

Nitpick comments:
In
`@packages/database/prisma/migrations/20260721183637_add_member_invitation_invited_by_index/migration.sql`:
- Line 2: Update the MemberInvitation_invitedById_idx migration to use
concurrent index creation, and configure this migration so the runner executes
it outside a transaction, preserving PostgreSQL’s requirement for concurrent
indexes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 2f1f0a3c-788b-41c8-b8c8-a9a7190afbf0

📥 Commits

Reviewing files that changed from the base of the PR and between 1a6d86e and c4d81dc.

📒 Files selected for processing (9)
  • apps/api/src/auth/session.service.ts
  • apps/api/src/members/members.controller.ts
  • apps/api/src/members/members.service.ts
  • apps/web/app/(authenticated)/members/page.tsx
  • apps/web/app/invite/accept/page.tsx
  • apps/web/hooks/use-auth.ts
  • apps/web/hooks/use-members.ts
  • packages/database/prisma/migrations/20260721183637_add_member_invitation_invited_by_index/migration.sql
  • packages/database/prisma/schema.prisma
🚧 Files skipped from review as they are similar to previous changes (7)
  • apps/web/hooks/use-auth.ts
  • packages/database/prisma/schema.prisma
  • apps/web/app/invite/accept/page.tsx
  • apps/api/src/members/members.controller.ts
  • apps/web/hooks/use-members.ts
  • apps/web/app/(authenticated)/members/page.tsx
  • apps/api/src/members/members.service.ts

Comment thread apps/api/src/auth/session.service.ts
@chko0

chko0 commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (3)
apps/api/src/members/members.service.ts (3)

221-237: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Make token rotation and email enqueue retry-safe.

The database token update completes before mailQueue.add(). If queueing fails, invite() or resendInvitation() can leave a valid but unsent token, while resend also invalidates the previous working link. Use a transactional outbox/job record or a retry-safe compensating transition.

Also applies to: 473-493, 525-528

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/members/members.service.ts` around lines 221 - 237, Make token
rotation and invitation email enqueue atomic or retry-safe across the invitation
flows around the Prisma member update, invite(), and resendInvitation(). Persist
an outbox/job record transactionally with the token change, or add a
compensating transition that restores the prior token state when mailQueue.add()
fails, ensuring retries do not leave a valid unsent token or invalidate a
previously working link.

221-227: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Make invitation state transitions conditional.

Accept, revoke, and resend first check pending state, then update only by id. Concurrent operations can therefore set both acceptedAt and revokedAt, or rotate a token after acceptance. Include organizationId, acceptedAt: null, and revokedAt: null in the write predicate and verify the affected-row count; acceptance should re-read or lock the invitation inside the transaction.

Also applies to: 507-513, 539-555, 659-662

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/members/members.service.ts` around lines 221 - 227, Make the
invitation writes in the accept, revoke, and resend flows conditional on the
invitation remaining pending: include organizationId, acceptedAt: null, and
revokedAt: null alongside id in each Prisma update/updateMany predicate. Check
the affected-row count and reject or stop when no pending row was updated; for
acceptance, re-read or lock the invitation within the transaction before
applying the transition.

456-488: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Make active-invitation deduplication atomic. The schema only enforces tokenHash uniqueness, so the findFirst + create path can still race and produce duplicate active invitations for the same organization/email or username. Add a database-level uniqueness or locking guard and map conflicts to ConflictException.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/members/members.service.ts` around lines 456 - 488, The
findFirst/create flow in the member invitation creation method is race-prone and
must enforce active-invitation deduplication atomically. Add an appropriate
database-level unique constraint or locking mechanism for organization plus
active email/username invitations, then update the create path to catch and map
resulting uniqueness conflicts to ConflictException while preserving the
existing duplicate-invitation message.
🧹 Nitpick comments (1)
apps/api/src/auth/session.service.ts (1)

58-68: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use the mandated DatabaseService for the new session lookup.

cacheSession introduces database access through PrismaService; inject and use DatabaseService instead so this service follows the repository’s database boundary.

As per coding guidelines, “Access the database only through DatabaseService (extends PrismaClient).”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/auth/session.service.ts` around lines 58 - 68, Update
cacheSession to perform the session lookup through the mandated DatabaseService
instead of PrismaService. Inject DatabaseService into the containing service and
use it for the findUnique query, preserving the existing expiration check and
cacheSessionData behavior.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/api/src/members/members.service.ts`:
- Around line 672-678: Update the session caching warning in the
accepted-invitation flow around cacheSession to remove result.sessionId from the
log, since it is a bearer credential. Log only the invitation ID and a sanitized
error class or code, avoiding raw error messages and backend details.

---

Outside diff comments:
In `@apps/api/src/members/members.service.ts`:
- Around line 221-237: Make token rotation and invitation email enqueue atomic
or retry-safe across the invitation flows around the Prisma member update,
invite(), and resendInvitation(). Persist an outbox/job record transactionally
with the token change, or add a compensating transition that restores the prior
token state when mailQueue.add() fails, ensuring retries do not leave a valid
unsent token or invalidate a previously working link.
- Around line 221-227: Make the invitation writes in the accept, revoke, and
resend flows conditional on the invitation remaining pending: include
organizationId, acceptedAt: null, and revokedAt: null alongside id in each
Prisma update/updateMany predicate. Check the affected-row count and reject or
stop when no pending row was updated; for acceptance, re-read or lock the
invitation within the transaction before applying the transition.
- Around line 456-488: The findFirst/create flow in the member invitation
creation method is race-prone and must enforce active-invitation deduplication
atomically. Add an appropriate database-level unique constraint or locking
mechanism for organization plus active email/username invitations, then update
the create path to catch and map resulting uniqueness conflicts to
ConflictException while preserving the existing duplicate-invitation message.

---

Nitpick comments:
In `@apps/api/src/auth/session.service.ts`:
- Around line 58-68: Update cacheSession to perform the session lookup through
the mandated DatabaseService instead of PrismaService. Inject DatabaseService
into the containing service and use it for the findUnique query, preserving the
existing expiration check and cacheSessionData behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 77f81757-a6bc-44b5-a045-e4de6def2dbc

📥 Commits

Reviewing files that changed from the base of the PR and between c4d81dc and 916eeeb.

📒 Files selected for processing (3)
  • apps/api/src/auth/session.service.ts
  • apps/api/src/members/members.service.ts
  • packages/database/prisma/migrations/20260721183637_add_member_invitation_invited_by_index/migration.sql
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/database/prisma/migrations/20260721183637_add_member_invitation_invited_by_index/migration.sql

Comment on lines +672 to +678
await this.sessionService.cacheSession(result.sessionId).catch((error) => {
this.logger.warn(
`Failed to cache accepted invitation session ${result.sessionId}: ${
error instanceof Error ? error.message : String(error)
}`,
);
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Do not log the full session identifier.

result.sessionId is returned for cookie creation, so logging it can expose a bearer credential. The raw error message may also contain sensitive backend details; log only the invitation ID and a sanitized error class/code.

Proposed fix
-        `Failed to cache accepted invitation session ${result.sessionId}: ${
-          error instanceof Error ? error.message : String(error)
-        }`,
+        `Failed to cache accepted invitation session for invitation ${invitation.id}`,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
await this.sessionService.cacheSession(result.sessionId).catch((error) => {
this.logger.warn(
`Failed to cache accepted invitation session ${result.sessionId}: ${
error instanceof Error ? error.message : String(error)
}`,
);
});
await this.sessionService.cacheSession(result.sessionId).catch((error) => {
this.logger.warn(
`Failed to cache accepted invitation session for invitation ${invitation.id}`,
);
});
🧰 Tools
🪛 ast-grep (0.44.1)

[warning] 672-676: Avoid logging sensitive data
Context: this.logger.warn(
Failed to cache accepted invitation session ${result.sessionId}: ${ error instanceof Error ? error.message : String(error) },
)
Note: [CWE-532] Insertion of Sensitive Information into Log File.

(log-sensitive-data-typescript)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/members/members.service.ts` around lines 672 - 678, Update the
session caching warning in the accepted-invitation flow around cacheSession to
remove result.sessionId from the log, since it is a bearer credential. Log only
the invitation ID and a sanitized error class or code, avoiding raw error
messages and backend details.

Source: Linters/SAST tools

@chko0
chko0 requested a review from OmarZaatari July 22, 2026 07:30

@OmarZaatari OmarZaatari left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Awesome!

@OmarZaatari
OmarZaatari merged commit 481e886 into coordly-chadi-omar Jul 22, 2026
2 checks passed
@OmarZaatari
OmarZaatari deleted the coordly/member-management-crud branch July 22, 2026 07:33
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