Skip to content

feat: complete offline interview review workflow - #137

Merged
zzemy merged 8 commits into
v3.1from
codex/offline-interview-workflow
Aug 6, 2026
Merged

feat: complete offline interview review workflow#137
zzemy merged 8 commits into
v3.1from
codex/offline-interview-workflow

Conversation

@zzemy

@zzemy zzemy commented Aug 6, 2026

Copy link
Copy Markdown
Member

Scope

  • add a Docker-backed local development workflow and remove unused AI drafting features
  • complete Feishu offline interview scheduling, meeting-event state, and Minutes archival integration
  • require lecturer evaluation content and recommendation before administrator approval
  • make archived evaluation decisions immutable; non-interview flows cannot bypass review approval
  • let lecturers view QQ while keeping phone visibility restricted to administrators
  • streamline dashboard surfaces and standardize email-record filters on shadcn Select

Database migrations

Apply migrations 0027_interview_schedule_event_state.sql, 0028_offline_interview_email_copy.sql, and 0029_interview_evaluation_recommendation.sql before deploying the application.

Validation

  • pnpm lint
  • pnpm exec tsc --noEmit
  • pnpm test (61 suites, 149 tests)
  • browser checks for evaluation validation, immutable archives, and email filter selection

Copilot AI lite review requested due to automatic review settings August 6, 2026 08:39

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

This PR completes the offline interview review workflow end-to-end: it removes the unused AI drafting features, expands Feishu interview scheduling to track meeting end/minutes events for archival, and updates evaluation + approval rules/UI to require lecturer evaluation content + recommendation and keep archived decisions immutable. It also introduces a Docker-backed local dev workflow and standardizes several dashboard surfaces (including email record filters) with shadcn/ui styling.

Changes:

  • Add local dev workflow (dev:local) and enable inngest-cli builds; remove server-side OpenAI/AI draft features across UI/actions/docs/env.
  • Complete Feishu offline interview scheduling lifecycle: store meeting unique ID, handle meeting-ended + minutes-generated events, and propagate “ended” state into the workflow/UI.
  • Tighten evaluation/approval flow: require lecturer content + recommendation, prevent archived decision mutation, restrict phone visibility to admins while allowing lecturers to view QQ; refresh related UI/tests.

Reviewed changes

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

Show a summary per file
File Description
scripts/dev-local.sh New local dev script orchestrating DB + Inngest + Next dev with cleanup.
README.md Remove AI draft feature references and OpenAI env docs.
queue/interviewScheduleReminder.ts Reminder cards now use QQ and offline interview wording.
pnpm-workspace.yaml Allow inngest-cli to build/install.
package.json Add dev:local; ensure INNGEST_DEV=1 for dev:full Next process.
migrations/meta/_journal.json Register new migrations 0027–0029.
migrations/0027_interview_schedule_event_state.sql Add meeting state fields + active-schedule uniqueness index.
migrations/0028_offline_interview_email_copy.sql Update interview schedule email copy to offline wording.
migrations/0029_interview_evaluation_recommendation.sql Add lecturer recommendation enum + column.
lib/feishu/interview-schedule.ts Surface Feishu meeting unique ID from calendar events.
lib/feishu/interview-message.ts Schedule cards updated for offline “recording/minutes” semantics and QQ display.
lib/feishu/interview-event.ts New utilities to normalize Feishu meeting/minutes event payloads.
lib/feishu/interview-event.test.ts Unit tests for Feishu event payload normalization.
lib/evaluation-state.ts Remove obsolete state helpers; simplify action→step mapping.
lib/evaluation-state.test.ts Update tests to reflect removed helpers/actions.
lib/email/interview-template-settings.ts Update defaults and remove meeting/schedule link variables for candidate emails.
lib/email/interview-schedule.tsx Stop providing meeting/schedule link variables; keep offline email rendering.
lib/email-center/render.test.ts Update render test inputs to match new interview template variables.
lib/email-center/registry.ts Update template descriptions/variables for offline schedule emails.
lib/ai/openai.ts Remove OpenAI client helper (AI drafts removed).
hooks/useUserList.ts Split visibility flags to expose QQ to lecturers while keeping phone admin-only.
hooks/useUserInfoById.ts Same visibility split for user detail; QQ for lecturers, phone for admins only.
emails/interview-schedule.tsx Candidate email updated for offline interview (no meeting/schedule links).
docs/FEISHU_INTERVIEW_SCHEDULING_PLAN.md Update plan/spec for offline-only emails and meeting/minutes archival workflow.
docker-compose.dev.yml Use fully-qualified postgres image reference.
db/schema.ts Add recommendation enum/column; add schedule meeting state fields + partial unique index.
components/userInfo/basic.tsx Simplify college field UI; remove unused college list Select.
components/userInfo/basic.test.tsx Update tests for disabled college input (no combobox).
components/ui/card.tsx Adjust Card radius/shadow styling.
components/review/selectProblem.tsx Review UI surface styling adjustments.
components/review/selectedRangeDisplay.tsx Factor storage reader into lib helper; add “missing range” notice component.
components/review/selectedRangeDisplay.test.tsx Add coverage for new notice behavior.
components/review/qrcodeScanner.tsx Review scanner styling adjustments.
components/review/probCheckBox.tsx Review selection styling adjustments.
components/review/markProblemTable.tsx Restructure markup from Card to semantic sections; styling tweaks.
components/review/mannualInput.tsx Remove inline “missing range” warning (handled elsewhere).
components/recruitment/table.tsx Recruitment table surface styling tweaks.
components/recruitment/recruitmentContent.tsx Recruitment header section styling tweaks.
components/recruitment/evaluationTable.tsx Offline interview workflow UI: QQ display, schedule-ended confirmation, required content + recommendation, remove AI drafting/reopen/reject paths.
components/recruitment/evaluationTable.test.tsx Add test for required evaluation content; update candidate fields for QQ/recommendation/schedule state.
components/manage/viewUserInfoSheet.tsx Remove AI summary; show QQ to lecturers; keep phone admin-only.
components/manage/manageTable.tsx Show QQ column/details to lecturers; keep phone gated to admins.
components/manage/manageTable.test.tsx Add test to ensure lecturers see QQ but not phone.
components/manage/interviewEvaluation.tsx Require content; add lecturer recommendation selection; update copy for “不通过”.
components/manage/approvalsContent.tsx Make archives immutable; add archive filters/search/pagination and show lecturer recommendation badge; remove reopen/unapprove actions.
components/manage/approvalsContent.test.tsx Add coverage for archive search + recommendation labels.
components/flow/table.tsx Flow table styling tweaks.
components/email/EmailTemplateManagementSection.tsx Update interview template help text; styling tweaks.
components/email/EmailSendingTasksSection.tsx Remove shadow styling.
components/email/EmailRecordsSection.tsx Replace native selects with shadcn Select + hidden inputs for filter submission.
components/email/EmailOverviewSection.tsx Remove extra borders/shadows in overview surfaces.
components/email/EmailBatchTasksSection.tsx Remove shadow styling.
CLAUDE.md Remove optional AI draft mention from stack summary.
app/dashboard/review/page.tsx Update layout; integrate ReviewRangeNotice.
app/api/feishu/events/route.ts Expand Feishu event handling for meeting-ended + minutes-generated; update schedule/evaluation linkage; require verification token config.
app/api/auth/feishu/route.ts Harden OAuth state validation and restrict binding to lecturer+ roles.
action/user-flow/interviewSchedule.ts Offline schedule creation/reschedule/cancel rules; store meeting unique ID; add manual meeting-ended confirmation action; update card/email copy.
action/user-flow/evaluation.ts Add lecturer recommendation; prevent archived rewrites; link evaluations to schedules; improve admin listings with minutes fallback.
action/user-flow/edit.ts Prevent non-written flows from bypassing approval via direct outcome edits.
action/email/test-send.ts Update test-send payload for interview schedule email variables.
action/ai/candidate.ts Remove AI server actions (candidate summary + evaluation draft).
.env.example Remove OpenAI envs; add local INNGEST_DEV=1 note.
Suppressed comments (1)

action/user-flow/interviewSchedule.ts:494

  • The initial idempotencyKey only includes startsAt. If a first attempt partially succeeds and a retry changes endsAt while keeping the same start time, Feishu may return the original event due to idempotency, producing inconsistent meeting metadata.

Include endsAt in the key so retries with a different end time won’t reuse the earlier event.

        timezone: DEFAULT_TIMEZONE,
        idempotencyKey: `people-interview-${input.userFlowId}-${startsAt.getTime()}`,
      });

Comment on lines 479 to 481
timezone: DEFAULT_TIMEZONE,
idempotencyKey: `people-interview-${input.userFlowId}-${startsAt.getTime()}-recreate-${Date.now()}`,
idempotencyKey: `people-interview-${input.userFlowId}-${startsAt.getTime()}-recreate`,
});
Comment on lines 52 to +55
const filters = deliveryPage.filters;
const [status, setStatus] = useState(filters.status || "all");
const [category, setCategory] = useState(filters.category || "all");
const [flowId, setFlowId] = useState(filters.flowId || "all");
Comment on lines 180 to 210
const result = await db.transaction(async (tx) => {
const [currentFlow] = await tx
.select({ progressStatus: userFlow.progressStatus })
.from(userFlow)
.where(eq(userFlow.id, userFlowId))
.limit(1);

if (!currentFlow) {
return {
success: false as const,
error: { message: "报名流程不存在" },
};
}
if (currentFlow.progressStatus === "passed") {
return {
success: false as const,
error: {
message: "该候选人流程已结束;如需调整成员权限,请在成员管理中操作",
},
};
}
if (currentFlow.progressStatus === "failed") {
return {
success: false as const,
error: {
message: "该候选人流程已结束;如需重新评估,请重新报名并完整走流程",
},
};
}

const active = await findActiveEvaluationInTx(tx, userFlowId);
Co-authored-by: zzemy <86453687+zzemy@users.noreply.github.com>
@zzemy
zzemy merged commit 8c4b737 into v3.1 Aug 6, 2026
8 checks passed
@zzemy
zzemy deleted the codex/offline-interview-workflow branch August 6, 2026 09:13
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