Files
cesnimda ce76046a29 feat: complete release readiness work
- 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
2026-07-31 16:54:16 +02:00

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;
}