ce76046a29
- consolidate API ownership and remove dead vendor code - add Stripe billing, learning paths, and public CV hardening - add migration, recovery, security, audit, and browser gates
81 lines
3.4 KiB
C#
81 lines
3.4 KiB
C#
namespace JobTrackerApi.Models;
|
|
|
|
// Phase 5 Milestone 2 — the application checklist.
|
|
//
|
|
// A workflow GUIDANCE layer, not a new store of truth. It duplicates nothing: the CV lives in
|
|
// CvVariant, documents in Attachment, history in JobEvent, follow-up in JobApplication.FollowUpAt.
|
|
// A checklist item only records "is this step done, and does the user still want it".
|
|
//
|
|
// System items carry a stable SystemKey and (usually) an AutoSignal: the same readiness signal the
|
|
// /readiness endpoint already computes. When the signal is satisfied the item auto-completes, so the
|
|
// checklist and readiness can never disagree — readiness became the calculation, this is the surface.
|
|
// docs/architecture/application-workspace.md.
|
|
public sealed class ApplicationChecklistItem
|
|
{
|
|
public int Id { get; set; }
|
|
public string OwnerUserId { get; set; } = string.Empty;
|
|
public int JobApplicationId { get; set; }
|
|
public JobApplication? JobApplication { get; set; }
|
|
|
|
// Stable identifier for system items ("prepare-cv", ...). Null for user-created items, so re-seeding
|
|
// is idempotent and a system item can be recognised across renames.
|
|
public string? SystemKey { get; set; }
|
|
|
|
// Which readiness signal completes this item automatically. Null = manual only.
|
|
public string? AutoSignal { get; set; }
|
|
|
|
public string Title { get; set; } = string.Empty;
|
|
public string? Description { get; set; }
|
|
|
|
// preparation | submission | follow-up | interview | custom. Drives grouping and next-action priority.
|
|
public string Category { get; set; } = ChecklistCategories.Custom;
|
|
|
|
// pending | done | dismissed. "dismissed" is the user opting out — not every item fits every role.
|
|
public string Status { get; set; } = ChecklistStatuses.Pending;
|
|
|
|
// Workspace section this step is done in, so the checklist can link straight to the work.
|
|
public string? Section { get; set; }
|
|
|
|
public int SortOrder { get; set; }
|
|
public bool IsSystemGenerated { get; set; }
|
|
|
|
// Set when the auto-signal completed the item, so the sync may reopen it if the signal reverts.
|
|
// A manual tick clears this and therefore sticks.
|
|
public bool IsAutoCompleted { get; set; }
|
|
|
|
public DateTimeOffset? CompletedAt { get; set; }
|
|
public DateTimeOffset CreatedAtUtc { get; set; } = DateTimeOffset.UtcNow;
|
|
public DateTimeOffset UpdatedAtUtc { get; set; } = DateTimeOffset.UtcNow;
|
|
}
|
|
|
|
public static class ChecklistStatuses
|
|
{
|
|
public const string Pending = "pending";
|
|
public const string Done = "done";
|
|
public const string Dismissed = "dismissed";
|
|
|
|
public static bool IsValid(string? value) =>
|
|
value is Pending or Done or Dismissed;
|
|
}
|
|
|
|
public static class ChecklistCategories
|
|
{
|
|
public const string Preparation = "preparation";
|
|
public const string Submission = "submission";
|
|
public const string FollowUp = "follow-up";
|
|
public const string Interview = "interview";
|
|
public const string Custom = "custom";
|
|
|
|
// Next-action priority: critical preparation, then submission, then chasing, then interview prep,
|
|
// then whatever the user added themselves.
|
|
public static readonly string[] Order = { Preparation, Submission, FollowUp, Interview, Custom };
|
|
|
|
public static int Rank(string? category)
|
|
{
|
|
var index = Array.IndexOf(Order, category ?? Custom);
|
|
return index < 0 ? Order.Length : index;
|
|
}
|
|
|
|
public static bool IsValid(string? value) => Array.IndexOf(Order, value ?? string.Empty) >= 0;
|
|
}
|