feat: sequential task IDs (HQ-1, HQ-2, etc.)

- Add serial task_number column to tasks table
- Display HQ-{number} on cards and detail panel
- API resolveTask() supports UUID, number, or HQ-N prefix
- GET /api/tasks/:id endpoint for single task lookup
- All PATCH/POST/DELETE endpoints resolve by number or UUID
This commit is contained in:
2026-01-29 00:07:04 +00:00
parent 186a565bee
commit 8131dda10d
5 changed files with 81 additions and 52 deletions

View File

@@ -66,18 +66,9 @@ export function TaskCard({
isActive,
onClick,
}: TaskCardProps) {
const [idCopied, setIdCopied] = useState(false);
const actions = statusActions[task.status] || [];
const noteCount = task.progressNotes?.length || 0;
const shortId = task.id.slice(0, 8);
const handleCopyId = (e: React.MouseEvent) => {
e.stopPropagation();
navigator.clipboard.writeText(task.id).then(() => {
setIdCopied(true);
setTimeout(() => setIdCopied(false), 1500);
});
};
const displayId = task.taskNumber ? `HQ-${task.taskNumber}` : task.id.slice(0, 8);
return (
<div
@@ -104,14 +95,14 @@ export function TaskCard({
<div className="flex items-center gap-2 mb-2 flex-wrap">
<span
className="text-xs px-1.5 py-0.5 rounded font-mono bg-gray-100 text-gray-500 cursor-pointer hover:bg-gray-200 transition"
title={`Click to copy: ${task.id}`}
className="text-xs px-1.5 py-0.5 rounded font-mono font-bold bg-amber-100 text-amber-700 cursor-pointer hover:bg-amber-200 transition"
title={`Click to copy: ${displayId}`}
onClick={(e) => {
e.stopPropagation();
navigator.clipboard.writeText(task.id);
navigator.clipboard.writeText(displayId);
}}
>
{task.id.slice(0, 8)}
{displayId}
</span>
<span className={`text-xs px-2 py-0.5 rounded-full font-medium ${priorityColors[task.priority]}`}>
{task.priority}
@@ -127,17 +118,6 @@ export function TaskCard({
💬 {noteCount}
</span>
)}
<button
onClick={handleCopyId}
className="text-xs font-mono text-gray-300 hover:text-amber-600 transition cursor-pointer ml-auto"
title={`Copy full ID: ${task.id}`}
>
{idCopied ? (
<span className="text-green-500"> copied</span>
) : (
<span>{shortId}</span>
)}
</button>
</div>
{task.description && (