-
Notifications
You must be signed in to change notification settings - Fork 113
feat: public opportunity apply #3489
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
@claude review |
|
Claude finished @capJavert's task in 1m 28s —— View job Code Review
SummaryThis PR adds a public opportunity apply feature that allows authenticated users to apply to LIVE opportunities. The implementation includes:
✅ What's Good
🔍 Issues & Recommendations1. Potential N+1 Query Issue (Minor)Location: The final GraphORM query uses Current pattern: await ctx.con.getRepository(OpportunityMatch).save({
opportunityId,
userId: ctx.userId,
status: OpportunityMatchStatus.CandidateApplied,
// ...
});
return await graphorm.queryOneOrFail<GQLOpportunityMatch>(
ctx,
info,
(builder) => {
builder.queryBuilder
.where({ opportunityId })
.andWhere({ userId: ctx.userId });
return builder;
},
);Suggestion: Capture the saved entity and use it: const savedMatch = await ctx.con.getRepository(OpportunityMatch).save({
opportunityId,
userId: ctx.userId,
status: OpportunityMatchStatus.CandidateApplied,
description: {},
screening: [],
feedback: [],
applicationRank: {},
});
return await graphorm.queryOneOrFail<GQLOpportunityMatch>(
ctx,
info,
(builder) => {
builder.queryBuilder
.where({ opportunityId: savedMatch.opportunityId })
.andWhere({ userId: savedMatch.userId });
return builder;
},
);However, this is a minor optimization and the current pattern is acceptable. 2. Inconsistent Query Pattern (Medium)Location: You're using Current: const opportunity = await ctx.con.getRepository(OpportunityJob).findOne({
where: { id: opportunityId },
select: ['id', 'state'],
});However, in this case you actually SHOULD use the primary connection (not read replica) because:
So the current implementation is actually correct! But it's worth adding a brief comment to clarify why we're not using the read replica here: // Use primary connection for immediate consistency before write operation
const opportunity = await ctx.con.getRepository(OpportunityJob).findOne({
where: { id: opportunityId },
select: ['id', 'state'],
});3. Missing Transaction (Medium Priority)Location: The mutation performs multiple database operations sequentially:
According to CLAUDE.md best practices:
While the read operations don't need a transaction, having them outside provides better separation. However, if there were multiple writes, they should be wrapped. In this specific case, there's only one write operation (the save), so a transaction is not strictly necessary. But if you were to add more writes (e.g., updating user stats, sending notifications synchronously), you'd want to wrap them. Current implementation is acceptable for a single write, but worth keeping in mind for future changes. 4. Function Style Preference (Style)Location: According to CLAUDE.md:
The mutation uses a traditional async function declaration, but given the context (it's within the resolvers object), this is the standard GraphQL pattern and is fine. 5. Test Assertion Style (Minor)Location: The test uses separate assertions for each field: expect(res.data.opportunityApply).toEqual({
opportunityId: '550e8400-e29b-41d4-a716-446655440002',
userId: '3',
status: OpportunityMatchStatus.CandidateApplied,
});Then separately verifies the database: expect(match).toMatchObject({
status: OpportunityMatchStatus.CandidateApplied,
description: {},
screening: [],
feedback: [],
applicationRank: {},
});According to CLAUDE.md:
This is already following best practices! ✅ 6. Opportunity State Constants (Suggestion)When checking for LIVE state, consider if there will be other valid states in the future. The current check
In this case, you're doing the opposite (checking for a specific state), which is correct for this business logic. The opportunity must be LIVE to apply. 🎯 Action Items
📊 Test Coverage AnalysisThe test suite covers:
Excellent coverage! No gaps identified. 🔒 Security Assessment
📝 Overall AssessmentStatus: ✅ Approved with minor suggestions This is a solid implementation that follows most best practices. The code is well-tested, properly structured, and secure. The suggestions above are minor optimizations and documentation improvements that would make the code even better, but they're not blockers for merging. The most important suggestion is adding the clarifying comment about using the primary connection (see #2), but even that is optional since the implementation is correct. |
|
🍹 The Update (preview) for dailydotdev/api/prod (at 833c715) was successful. Resource Changes Name Type Operation
~ vpc-native-clean-zombie-user-companies-cron kubernetes:batch/v1:CronJob update
~ vpc-native-update-current-streak-cron kubernetes:batch/v1:CronJob update
~ vpc-native-ws-deployment kubernetes:apps/v1:Deployment update
~ vpc-native-validate-active-users-cron kubernetes:batch/v1:CronJob update
- vpc-native-api-clickhouse-migration-cdea2a18 kubernetes:batch/v1:Job delete
- vpc-native-api-db-migration-cdea2a18 kubernetes:batch/v1:Job delete
~ vpc-native-clean-gifted-plus-cron kubernetes:batch/v1:CronJob update
+ vpc-native-api-clickhouse-migration-63df05c9 kubernetes:batch/v1:Job create
~ vpc-native-personalized-digest-cron kubernetes:batch/v1:CronJob update
~ vpc-native-generate-search-invites-cron kubernetes:batch/v1:CronJob update
~ vpc-native-update-highlighted-views-cron kubernetes:batch/v1:CronJob update
~ vpc-native-update-source-tag-view-cron kubernetes:batch/v1:CronJob update
~ vpc-native-clean-zombie-users-cron kubernetes:batch/v1:CronJob update
~ vpc-native-hourly-notification-cron kubernetes:batch/v1:CronJob update
~ vpc-native-expire-super-agent-trial-cron kubernetes:batch/v1:CronJob update
~ vpc-native-generic-referral-reminder-cron kubernetes:batch/v1:CronJob update
~ vpc-native-deployment kubernetes:apps/v1:Deployment update
+ vpc-native-api-db-migration-63df05c9 kubernetes:batch/v1:Job create
~ vpc-native-update-tags-str-cron kubernetes:batch/v1:CronJob update
~ vpc-native-update-views-cron kubernetes:batch/v1:CronJob update
~ vpc-native-update-trending-cron kubernetes:batch/v1:CronJob update
~ vpc-native-clean-zombie-images-cron kubernetes:batch/v1:CronJob update
~ vpc-native-update-source-public-threshold-cron kubernetes:batch/v1:CronJob update
~ vpc-native-private-deployment kubernetes:apps/v1:Deployment update
~ vpc-native-update-tag-recommendations-cron kubernetes:batch/v1:CronJob update
~ vpc-native-check-analytics-report-cron kubernetes:batch/v1:CronJob update
~ vpc-native-personalized-digest-deployment kubernetes:apps/v1:Deployment update
~ vpc-native-post-analytics-history-day-clickhouse-cron kubernetes:batch/v1:CronJob update
~ vpc-native-clean-stale-user-transactions-cron kubernetes:batch/v1:CronJob update
~ vpc-native-clean-zombie-opportunities-cron kubernetes:batch/v1:CronJob update
~ vpc-native-post-analytics-clickhouse-cron kubernetes:batch/v1:CronJob update
~ vpc-native-temporal-deployment kubernetes:apps/v1:Deployment update
~ vpc-native-calculate-top-readers-cron kubernetes:batch/v1:CronJob update
~ vpc-native-daily-digest-cron kubernetes:batch/v1:CronJob update
~ vpc-native-bg-deployment kubernetes:apps/v1:Deployment update
~ vpc-native-sync-subscription-with-cio-cron kubernetes:batch/v1:CronJob update
~ vpc-native-user-profile-updated-sync-cron kubernetes:batch/v1:CronJob update
|
rebelchris
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good?
No description provided.