feat(workspace): interview and follow-up workflow
Phase 5.5. Completes the lifecycle after submission: prepare, communicate, chase. Interview preparation gets a durable, user-owned store. There were already two per-application AI stores, InterviewPrepNote and AiWorkspaceNote, but both are caches that regenerate when their context signature changes — anything a user typed into them would eventually be overwritten. InterviewPrepItem is the side nothing regenerates, covering company research, technical notes, behavioural answers, STAR examples and the user's own questions in one table, because those categories differ only by label and adding one must not need a migration. Each item records whether the user wrote it or accepted a suggestion, and an IsPrepared flag makes the section double as the preparation checklist. Generation stays in the existing AiWorkspaceService "interview" module, appended to AiInteraction as before. A suggestion is history until the user adds it as a prep item; opening the section generates nothing. Follow-up reuses what exists rather than adding a tracker. The date is JobApplication.FollowUpAt, the same field RulesEngine and the reminder hosted service already act on, so reminders keep working with no new wiring. The task stays an ApplicationChecklistItem in the follow-up category — the section counts open tasks without owning them. The record is a FollowUpSet JobEvent, the same type the rest of the app emits. Communication is untouched: Correspondence already owns recruiter contacts, history and notes, and the workspace already mounted it. The timeline interpreter learned five more types — InterviewScheduled, InterviewCompleted and OfferReceived as milestones, FollowUpCreated and FollowUpCompleted as routine, deliberately outside the milestone spine so it stays a summary of what actually happened. JobEvent remains the history source. InterviewPrepItems is reconciler-owned with a no-op migration, guarded on JobApplications, and verified on a fresh MariaDB 11: int AUTO_INCREMENT primary key, varchar owner and title, tinyint flag, datetime(6), composite index inside the key limit. 371 backend tests, 128 frontend tests, Release build and the production build all pass locally. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -297,6 +297,66 @@ storage, no duplicate upload path. Files stay private to the owning user.
|
||||
- **Multiple attached variants**: relax the one-per-application rule in `AttachVariantAsync`; the DTO
|
||||
already carries the full variant list.
|
||||
|
||||
## Interview and follow-up (Phase 5.5)
|
||||
|
||||
Completes the lifecycle after submission: prepare, communicate, chase.
|
||||
|
||||
### Interview preparation
|
||||
|
||||
There were already two per-application AI stores — `InterviewPrepNote` and `AiWorkspaceNote` — and
|
||||
**both are caches**: each regenerates when its context signature changes, so anything a user typed
|
||||
into them would eventually be overwritten. `InterviewPrepItem` is the durable, user-owned side.
|
||||
Nothing regenerates it.
|
||||
|
||||
One table covers every category (`company-research`, `technical`, `behavioural`, `star`, `question`,
|
||||
`note`) — they differ only by label, and adding a category must not need a migration. Each item
|
||||
carries the user's own `Content`, a `Source` (`user | ai`) recording whether they wrote it or accepted
|
||||
a suggestion, and `IsPrepared`, which makes the section double as the preparation checklist.
|
||||
|
||||
An accepted AI suggestion is marked `ai` for honesty, not to restrict editing — it is fully the
|
||||
user's afterwards.
|
||||
|
||||
### The AI boundary, restated
|
||||
|
||||
Generation stays in `AiWorkspaceService`'s existing `interview` module, reached from
|
||||
`AiWorkspacePanel`, authenticated and ownership-scoped like every other module, with each run appended
|
||||
to `AiInteraction`. **A suggestion is history until the user adds it as a prep item.** Opening the
|
||||
section generates nothing; `Generating_ai_history_does_not_create_prep_items` pins that.
|
||||
|
||||
### Communication
|
||||
|
||||
Unchanged. `Correspondence` already owns recruiter contacts, message history and notes, and the
|
||||
workspace already mounts that component. No second messaging or history system was added.
|
||||
|
||||
### Follow-up
|
||||
|
||||
Reuses what exists rather than adding a tracker:
|
||||
|
||||
- **The date** is `JobApplication.FollowUpAt` — the same field `RulesEngine` and
|
||||
`FollowUpReminderHostedService` already act on. Writing it here means reminders keep working with no
|
||||
new wiring.
|
||||
- **The task** is an `ApplicationChecklistItem` in the `follow-up` category. The follow-up section
|
||||
*counts* open tasks; it does not own them.
|
||||
- **The record** is a `FollowUpSet` `JobEvent` — the same type the rest of the app emits, so the
|
||||
timeline reads it unchanged.
|
||||
|
||||
### Timeline integration
|
||||
|
||||
`JobEvent` remains the source of history. The interpreter learned five more types:
|
||||
`InterviewScheduled`, `InterviewCompleted`, `OfferReceived` (milestones) and `FollowUpCreated`,
|
||||
`FollowUpCompleted` (routine, deliberately kept out of the milestone spine so it stays the "what
|
||||
actually happened" summary).
|
||||
|
||||
### Ownership
|
||||
|
||||
`InterviewPrepItems` is reconciler-owned with a no-op migration, guarded on `JobApplications`
|
||||
(`docs/infrastructure/database-ownership.md`). Verified on a fresh MariaDB 11: `int AUTO_INCREMENT`
|
||||
PK, `varchar(255)` owner, `varchar(500)` title, `tinyint(1)` flag, `datetime(6)`, composite index
|
||||
inside the key limit.
|
||||
|
||||
`InterviewPrepBoardDto` is named to avoid colliding with the pre-existing `InterviewPrepDto`, which
|
||||
belongs to the AI cache — a reminder that the two systems are genuinely different.
|
||||
|
||||
## Extension points
|
||||
|
||||
- **New section**: add to `WORKSPACE_SECTIONS` and render it; nav is data-driven.
|
||||
@@ -313,4 +373,6 @@ storage, no duplicate upload path. Files stay private to the owning user.
|
||||
(Phase 5.3, all three deterministic and read-only).
|
||||
4. ✅ Application assets — CV variant association, tailoring suggestions, cover letter workflow with
|
||||
version history, documents (Phase 5.4).
|
||||
5. ✅ Interview and follow-up — user-owned interview preparation, follow-up over the existing
|
||||
FollowUpAt and checklist, five more timeline event types (Phase 5.5).
|
||||
7. Cover letter workflow. 8. Documents. 9. Interview preparation. 10. Dashboard improvements.
|
||||
|
||||
@@ -75,8 +75,8 @@ Created by `StartupInitializationExtensions`, with a **no-op migration** holding
|
||||
`CareerProfiles`, `CareerProfileVersions`, the six CareerProfile children (`CareerExperiences`,
|
||||
`CareerEducations`, `CareerSkills`, `CareerProjects`, `CareerCertifications`, `CareerLanguages`),
|
||||
`InterviewPrepNotes`, `AiWorkspaceNotes`, `CvVariants`, `CvVariantVersions`, `AiInteractions`,
|
||||
`ApplicationChecklistItems`, `CoverLetterVersions`, `TwoFactorRecoveryCodes`, `TrustedDevices`,
|
||||
`UserSessions`.
|
||||
`ApplicationChecklistItems`, `CoverLetterVersions`, `InterviewPrepItems`, `TwoFactorRecoveryCodes`,
|
||||
`TrustedDevices`, `UserSessions`.
|
||||
|
||||
No-op migrations, each with a comment explaining why:
|
||||
|
||||
@@ -88,6 +88,7 @@ No-op migrations, each with a comment explaining why:
|
||||
| `20260719085904_AddApplicationChecklistItems` | `ApplicationChecklistItems` |
|
||||
| `20260719094728_SyncCareerChildKeyLengths` | snapshot sync only |
|
||||
| `20260719120954_AddCoverLetterVersions` | `CoverLetterVersions` |
|
||||
| `20260719145044_AddInterviewPrepItems` | `InterviewPrepItems` |
|
||||
|
||||
### Dependency guards
|
||||
|
||||
@@ -96,7 +97,7 @@ skips it on a fresh database and pass 2 creates it:
|
||||
|
||||
| Table | Waits for |
|
||||
|---|---|
|
||||
| `TailoredCvDrafts`, `InterviewPrepNotes`, `AiWorkspaceNotes`, `CvVariants`, `AiInteractions`, `ApplicationChecklistItems`, `CoverLetterVersions` | `JobApplications` (migration-owned) |
|
||||
| `TailoredCvDrafts`, `InterviewPrepNotes`, `AiWorkspaceNotes`, `CvVariants`, `AiInteractions`, `ApplicationChecklistItems`, `CoverLetterVersions`, `InterviewPrepItems` | `JobApplications` (migration-owned) |
|
||||
| `CvVariantVersions` | `CvVariants` |
|
||||
| `CareerProfileVersions`, the six CareerProfile children | `CareerProfiles` |
|
||||
| `CvExtractionRuns` | `CvUploadArtifacts` |
|
||||
|
||||
Reference in New Issue
Block a user