533 lines
13 KiB
TypeScript
533 lines
13 KiB
TypeScript
export interface Company {
|
|
id: number;
|
|
name: string;
|
|
location?: string;
|
|
source?: string;
|
|
recruiterName?: string;
|
|
recruiterEmail?: string;
|
|
recruiterLinkedIn?: string;
|
|
lastContactedAt?: string;
|
|
nextContactAt?: string;
|
|
pipelineStage?: string;
|
|
}
|
|
|
|
export type WorkflowActionKey = "package-work" | "follow-up" | "interview-prep" | "review-readiness";
|
|
export type WorkflowWorkspaceTab = "tailored-cv" | "follow-up" | "interview-prep" | "readiness";
|
|
|
|
export interface WorkflowSignal {
|
|
actionKey: WorkflowActionKey;
|
|
reason: string;
|
|
workspaceTab: WorkflowWorkspaceTab;
|
|
followMode?: string | null;
|
|
needsAttention: boolean;
|
|
hasPackageGap: boolean;
|
|
needsInterviewPrep: boolean;
|
|
needsFollowUpAction: boolean;
|
|
hasTailoredCv: boolean;
|
|
hasSavedApplicationAnswerDraft: boolean;
|
|
hasInterviewPrepNotes: boolean;
|
|
}
|
|
|
|
export interface TailoredCvExperienceItem {
|
|
title?: string | null;
|
|
company?: string | null;
|
|
location?: string | null;
|
|
start?: string | null;
|
|
end?: string | null;
|
|
isCurrent?: boolean;
|
|
bullets: string[];
|
|
}
|
|
|
|
export interface TailoredCvEducationItem {
|
|
qualification?: string | null;
|
|
qualificationLevel?: string | null;
|
|
institution?: string | null;
|
|
location?: string | null;
|
|
start?: string | null;
|
|
end?: string | null;
|
|
details: string[];
|
|
}
|
|
|
|
export interface TailoredCvCustomSection {
|
|
title?: string | null;
|
|
items: string[];
|
|
}
|
|
|
|
export interface TailoredCvRenderOptions {
|
|
showPhoto: boolean;
|
|
pageMode: string;
|
|
accentColor: string;
|
|
sectionOrder: string[];
|
|
bulletDensity: string;
|
|
}
|
|
|
|
export interface TailoredCvDraft {
|
|
id?: number | null;
|
|
canonicalProfileVersion?: number | null;
|
|
templateId: string;
|
|
headline?: string | null;
|
|
summary: string[];
|
|
selectedSkills: string[];
|
|
experience: TailoredCvExperienceItem[];
|
|
education: TailoredCvEducationItem[];
|
|
customSections: TailoredCvCustomSection[];
|
|
renderOptions: TailoredCvRenderOptions;
|
|
generationContextHash?: string | null;
|
|
lastGeneratedAtUtc?: string | null;
|
|
lastEditedAtUtc?: string | null;
|
|
status: string;
|
|
renderedText: string;
|
|
isLegacyFallback: boolean;
|
|
}
|
|
|
|
export interface JobApplication {
|
|
id: number;
|
|
jobTitle: string;
|
|
company: Company;
|
|
companyId?: number;
|
|
status: string;
|
|
// Null while the job sits in a pre-application stage (Saved/Interested/Preparing): nothing has
|
|
// been submitted, so there is no applied date. Render "—", never a fabricated date.
|
|
dateApplied: string | null;
|
|
// When the user captured the job. Always set — use it wherever a job needs a date to sort or
|
|
// show regardless of whether it has been applied to.
|
|
savedAt: string;
|
|
location?: string;
|
|
salary?: string;
|
|
salaryMin?: number | null;
|
|
salaryMax?: number | null;
|
|
salaryCurrency?: string | null;
|
|
salaryPeriod?: string | null;
|
|
nextAction?: string;
|
|
followUpAt?: string;
|
|
feedbackRequestedAt?: string;
|
|
responseReceived: boolean;
|
|
responseDate?: string;
|
|
description?: string;
|
|
translatedDescription?: string;
|
|
descriptionLanguage?: string;
|
|
tags?: string; // JSON array string
|
|
deadline?: string;
|
|
notes?: string;
|
|
coverLetterText?: string;
|
|
recruiterMessageDraft?: string | null;
|
|
jobUrl?: string;
|
|
shortSummary?: string;
|
|
fullSummary?: string | null;
|
|
tailoredCvText?: string | null;
|
|
tailoredCvUpdatedAt?: string | null;
|
|
workflowSignal?: WorkflowSignal | null;
|
|
|
|
hasResume?: boolean;
|
|
hasCoverLetter?: boolean;
|
|
hasPortfolio?: boolean;
|
|
hasOtherAttachment?: boolean;
|
|
|
|
// Null when dateApplied is null — there is no elapsed time to report before applying.
|
|
daysSince: number | null;
|
|
isDeleted?: boolean;
|
|
deletedAt?: string;
|
|
needsFollowUp?: boolean;
|
|
followUpReason?: string | null;
|
|
}
|
|
|
|
export interface CandidateFitChannelGuidance {
|
|
cv: string[];
|
|
coverLetter: string[];
|
|
interview: string[];
|
|
recruiterMessage: string[];
|
|
}
|
|
|
|
export interface MatchScoreSectionCoverage {
|
|
section: string;
|
|
matched: number;
|
|
total: number;
|
|
}
|
|
|
|
export interface LearningRecommendation {
|
|
id: number;
|
|
keyword: string;
|
|
status: "pending" | "done" | "dismissed";
|
|
}
|
|
|
|
export interface StatusSuggestion {
|
|
hasSuggestion: boolean;
|
|
suggestedStatus?: string | null;
|
|
currentStatus?: string | null;
|
|
signal?: string | null;
|
|
confidence?: string | null;
|
|
messageDate?: string | null;
|
|
messageSubject?: string | null;
|
|
}
|
|
|
|
export interface MatchScore {
|
|
score: number;
|
|
band: string;
|
|
matchedCount: number;
|
|
totalKeywords: number;
|
|
matchedKeywords: string[];
|
|
missingKeywords: string[];
|
|
sectionCoverage: MatchScoreSectionCoverage[];
|
|
hasEnoughSignal: boolean;
|
|
learningRecommendations: LearningRecommendation[];
|
|
}
|
|
|
|
export interface CandidateFit {
|
|
matchSummary: string;
|
|
fitLevel: string;
|
|
matchScore: number;
|
|
strengths: string[];
|
|
gaps: string[];
|
|
mention: string[];
|
|
avoid: string[];
|
|
cvImprovements: string[];
|
|
missingKeywords: string[];
|
|
interviewPrep: string[];
|
|
tailoredPitch: string;
|
|
guidance: CandidateFitChannelGuidance;
|
|
coverLetterDraft?: string | null;
|
|
recruiterMessageDraft?: string | null;
|
|
}
|
|
|
|
export interface FocusPlanResponse {
|
|
immediatePriorities: string[];
|
|
cvBulletIdeas: string[];
|
|
proofPointsToLeadWith: string[];
|
|
coverLetterAngles: string[];
|
|
followUpApproach: string[];
|
|
strategicSummary: string;
|
|
}
|
|
|
|
export interface UserOperation {
|
|
id: string;
|
|
taskType: string;
|
|
status: "queued" | "running" | "waiting_for_retry" | "waiting_for_external_fallback" | "succeeded" | "failed" | "cancelled";
|
|
subjectType?: string | null;
|
|
createdAtUtc: string;
|
|
startedAtUtc?: string | null;
|
|
completedAtUtc?: string | null;
|
|
deadlineAtUtc?: string | null;
|
|
cancellationRequestedAtUtc?: string | null;
|
|
progressStage?: string | null;
|
|
progressPercent?: number | null;
|
|
failureCategory?: string | null;
|
|
canCancel: boolean;
|
|
canRetry: boolean;
|
|
}
|
|
|
|
export interface StrategySnapshotOperationResponse {
|
|
operation: UserOperation;
|
|
statusUrl: string;
|
|
created: boolean;
|
|
}
|
|
|
|
export interface InterviewPrepResponse {
|
|
summary: string;
|
|
talkingPoints: string[];
|
|
likelyQuestions: string[];
|
|
weakSpots: string[];
|
|
}
|
|
|
|
export interface ReadinessResponse {
|
|
score: number;
|
|
level: string;
|
|
completed: string[];
|
|
missing: string[];
|
|
reminders: string[];
|
|
workflowSignal: WorkflowSignal;
|
|
}
|
|
|
|
export interface FollowUpDraft {
|
|
subject: string;
|
|
body: string;
|
|
reason: string;
|
|
suggestedSendOn: string;
|
|
contextSummary: string;
|
|
contextSignals: string[];
|
|
threadSubject?: string | null;
|
|
lastCorrespondenceFrom?: string | null;
|
|
lastCorrespondenceAt?: string | null;
|
|
}
|
|
|
|
export interface ApplicationPackageResponse {
|
|
tailoredCvText: string;
|
|
coverLetterDraft?: string | null;
|
|
applicationAnswerDraft?: string | null;
|
|
recruiterMessageDraft?: string | null;
|
|
keyPoints: string[];
|
|
attachmentSignals: string[];
|
|
attachmentFilesUsed: string[];
|
|
coverLetterVariants: string[];
|
|
recruiterMessageVariants: string[];
|
|
}
|
|
|
|
export interface SaveApplicationDraftsRequest {
|
|
coverLetterText?: string | null;
|
|
notes?: string | null;
|
|
recruiterMessageDraft?: string | null;
|
|
}
|
|
|
|
export interface CorrespondenceAttachmentMetadata {
|
|
fileName?: string | null;
|
|
mimeType?: string | null;
|
|
sizeBytes?: number | null;
|
|
gmailAttachmentId?: string | null;
|
|
inline?: boolean;
|
|
}
|
|
|
|
export interface CorrespondenceMessage {
|
|
id: number;
|
|
jobApplicationId: number;
|
|
from: string;
|
|
direction?: string | null;
|
|
content: string;
|
|
subject?: string;
|
|
channel?: string;
|
|
date: string;
|
|
externalMessageId?: string | null;
|
|
externalThreadId?: string | null;
|
|
externalFrom?: string | null;
|
|
externalTo?: string | null;
|
|
externalLabelsJson?: string | null;
|
|
attachmentMetadataJson?: string | null;
|
|
}
|
|
|
|
export interface AttachmentItem {
|
|
id: number;
|
|
fileName: string;
|
|
uploadDate: string;
|
|
fileType: string;
|
|
fileSize: number;
|
|
purpose?: string | null;
|
|
useForAi: boolean;
|
|
}
|
|
|
|
export interface GmailJobMatchReason {
|
|
label: string;
|
|
value: string;
|
|
}
|
|
|
|
export interface GmailJobMatchedMessage {
|
|
id: string;
|
|
threadId: string;
|
|
subject: string;
|
|
from: string;
|
|
to: string;
|
|
date?: string;
|
|
snippet: string;
|
|
score: number;
|
|
confidence: string;
|
|
alreadyImported: boolean;
|
|
matchReasons: GmailJobMatchReason[];
|
|
}
|
|
|
|
export interface GmailJobMatchedThread {
|
|
threadId: string;
|
|
subject: string;
|
|
score: number;
|
|
confidence: string;
|
|
hasImportedMessages: boolean;
|
|
messageCount: number;
|
|
latestDate?: string;
|
|
matchReasons: GmailJobMatchReason[];
|
|
messages: GmailJobMatchedMessage[];
|
|
}
|
|
|
|
export interface GmailJobMatchesResponse {
|
|
jobApplicationId: number;
|
|
jobTitle: string;
|
|
companyName: string;
|
|
recruiterName?: string | null;
|
|
recruiterEmail?: string | null;
|
|
queries: string[];
|
|
threads: GmailJobMatchedThread[];
|
|
}
|
|
|
|
export interface GmailImportMessageResult {
|
|
imported: number;
|
|
skipped: number;
|
|
messageId: string;
|
|
threadId?: string | null;
|
|
message?: CorrespondenceMessage | null;
|
|
}
|
|
|
|
export interface GmailImportThreadResult {
|
|
imported: number;
|
|
skipped: number;
|
|
threadId?: string | null;
|
|
}
|
|
|
|
export interface GmailThreadRefreshThreadResult {
|
|
threadId: string;
|
|
imported: number;
|
|
skipped: number;
|
|
totalMessages: number;
|
|
status: string;
|
|
latestMessageDate?: string;
|
|
}
|
|
|
|
export interface GmailThreadRefreshResult {
|
|
jobApplicationId: number;
|
|
threadsChecked: number;
|
|
imported: number;
|
|
skipped: number;
|
|
hasLinkedThreads: boolean;
|
|
refreshedAt: string;
|
|
threads: GmailThreadRefreshThreadResult[];
|
|
}
|
|
|
|
export interface GmailReviewJobCandidate {
|
|
jobApplicationId: number;
|
|
jobTitle: string;
|
|
companyName: string;
|
|
score: number;
|
|
confidence: string;
|
|
reasons: GmailJobMatchReason[];
|
|
}
|
|
|
|
export interface GmailReviewThread {
|
|
threadId: string;
|
|
subject: string;
|
|
latestDate?: string;
|
|
messageCount: number;
|
|
routing: string;
|
|
hasImportedMessages: boolean;
|
|
decisionNote?: string | null;
|
|
matchedQueries: string[];
|
|
jobCandidates: GmailReviewJobCandidate[];
|
|
messages: GmailJobMatchedMessage[];
|
|
}
|
|
|
|
export interface GmailReviewQueueResponse {
|
|
queries: string[];
|
|
candidateThreadCount: number;
|
|
autoLinkThreadCount: number;
|
|
reviewThreadCount: number;
|
|
unmatchedThreadCount: number;
|
|
threads: GmailReviewThread[];
|
|
}
|
|
|
|
export interface GmailStatus {
|
|
connected: boolean;
|
|
gmailAddress?: string;
|
|
connectedAt?: string;
|
|
lastSyncedAt?: string;
|
|
lastSyncAttemptedAt?: string;
|
|
lastSyncSucceededAt?: string;
|
|
lastSyncMode?: string | null;
|
|
lastSyncSource?: string | null;
|
|
lastSyncStatus?: string | null;
|
|
lastSyncError?: string | null;
|
|
}
|
|
|
|
export interface MicrosoftGraphStatus {
|
|
connected: boolean;
|
|
mailAddress?: string | null;
|
|
connectedAt?: string;
|
|
lastSyncedAt?: string;
|
|
lastSyncAttemptedAt?: string;
|
|
lastSyncSucceededAt?: string;
|
|
lastSyncMode?: string | null;
|
|
lastSyncSource?: string | null;
|
|
lastSyncStatus?: string | null;
|
|
lastSyncError?: string | null;
|
|
}
|
|
|
|
export interface ImapStatus {
|
|
connected: boolean;
|
|
host?: string | null;
|
|
port?: number | null;
|
|
useSsl?: boolean | null;
|
|
username?: string | null;
|
|
connectedAt?: string;
|
|
lastSyncedAt?: string;
|
|
lastSyncAttemptedAt?: string;
|
|
lastSyncSucceededAt?: string;
|
|
lastSyncMode?: string | null;
|
|
lastSyncSource?: string | null;
|
|
lastSyncStatus?: string | null;
|
|
lastSyncError?: string | null;
|
|
}
|
|
|
|
export interface GmailManualSyncResult {
|
|
queriesRun: number;
|
|
candidateThreadCount: number;
|
|
autoLinkedThreadCount: number;
|
|
reviewThreadCount: number;
|
|
unmatchedThreadCount: number;
|
|
importedMessages: number;
|
|
importedThreads: number;
|
|
skippedMessages: number;
|
|
lookbackDays: number;
|
|
includeSpamTrash: boolean;
|
|
syncedAt: string;
|
|
}
|
|
|
|
export interface GmailSuggestedJobCandidate {
|
|
threadId: string;
|
|
subject: string;
|
|
latestDate?: string | null;
|
|
companyName?: string | null;
|
|
recruiterName?: string | null;
|
|
recruiterEmail?: string | null;
|
|
suggestedJobTitle?: string | null;
|
|
routing: string;
|
|
matchedQueries: string[];
|
|
preview: string;
|
|
}
|
|
|
|
export interface GmailSuggestedJobsResponse {
|
|
count: number;
|
|
items: GmailSuggestedJobCandidate[];
|
|
}
|
|
|
|
export interface CreatedSuggestedGmailJobResult {
|
|
jobApplicationId: number;
|
|
companyId: number;
|
|
threadId: string;
|
|
imported: number;
|
|
skipped: number;
|
|
}
|
|
|
|
export interface GmailRelinkResult {
|
|
threadId: string;
|
|
jobApplicationId: number;
|
|
imported: number;
|
|
skipped: number;
|
|
unlinkedMessages: number;
|
|
}
|
|
|
|
export interface GmailUnlinkResult {
|
|
threadId: string;
|
|
jobApplicationId: number;
|
|
removedMessages: number;
|
|
decision: string;
|
|
}
|
|
|
|
export interface GmailMessageSummary {
|
|
id: string;
|
|
threadId: string;
|
|
subject: string;
|
|
from: string;
|
|
to: string;
|
|
date?: string;
|
|
snippet: string;
|
|
}
|
|
|
|
export interface JobImportResult {
|
|
title?: string;
|
|
company?: string;
|
|
location?: string;
|
|
description?: string;
|
|
translatedDescription?: string;
|
|
language?: string;
|
|
tags: string[];
|
|
sourceUrl: string;
|
|
source?: string;
|
|
countryCode?: string;
|
|
deadline?: string;
|
|
success: boolean;
|
|
parser?: string;
|
|
error?: string;
|
|
}
|