hanoman 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build-info.json +3 -3
- package/dist/cli.js +177 -117
- package/dist/server.js +1520 -1636
- package/package.json +1 -1
- package/prisma/migrations/20260731000000_spec_created_started_at/migration.sql +43 -0
- package/prisma/migrations/20260731120000_lead_decision/migration.sql +33 -0
- package/prisma/migrations/20260731180000_drop_errors_sdk_crossaudit/migration.sql +58 -0
- package/prisma/schema.prisma +44 -87
- package/web/assets/{index-CeJYUp36.js → index-BWyQwoAk.js} +1530 -1531
- package/web/index.html +1 -1
package/package.json
CHANGED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
-- SPEC-408 · ADR-0090 · stempel waktu backlog: `Spec.createdAt` + `Spec.startedAt`.
|
|
2
|
+
--
|
|
3
|
+
-- SQLite melarang `ALTER TABLE … ADD COLUMN … DEFAULT CURRENT_TIMESTAMP` (default non-konstan),
|
|
4
|
+
-- jadi kolom ber-default waktu HARUS lewat redefinisi tabel. Redefinisi itu sekaligus tempat
|
|
5
|
+
-- backfill baris lama: `updatedAt` adalah satu-satunya jejak waktu yang pernah ada, dan `baseSha`
|
|
6
|
+
-- adalah penanda "pernah dikerjakan" yang sudah dipakai sistem (scheduler sources/backlog.ts).
|
|
7
|
+
-- Backfill ini APROKSIMASI dan dinyatakan terbuka di ADR-0090 — mengisinya dengan waktu migration
|
|
8
|
+
-- dijalankan akan membuat seluruh backlog lama tampak dibuat hari ini, yang lebih menyesatkan.
|
|
9
|
+
PRAGMA foreign_keys=OFF;
|
|
10
|
+
PRAGMA defer_foreign_keys=ON;
|
|
11
|
+
|
|
12
|
+
CREATE TABLE "new_Spec" (
|
|
13
|
+
"id" TEXT NOT NULL PRIMARY KEY,
|
|
14
|
+
"projectId" TEXT NOT NULL,
|
|
15
|
+
"title" TEXT NOT NULL,
|
|
16
|
+
"source" TEXT NOT NULL,
|
|
17
|
+
"stage" TEXT NOT NULL,
|
|
18
|
+
"priority" TEXT NOT NULL,
|
|
19
|
+
"author" TEXT NOT NULL,
|
|
20
|
+
"objective" TEXT NOT NULL,
|
|
21
|
+
"payload" JSONB,
|
|
22
|
+
"branchFrom" TEXT,
|
|
23
|
+
"baseSha" TEXT,
|
|
24
|
+
"headSha" TEXT,
|
|
25
|
+
"version" INTEGER NOT NULL DEFAULT 0,
|
|
26
|
+
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
27
|
+
"startedAt" DATETIME,
|
|
28
|
+
"updatedAt" DATETIME NOT NULL,
|
|
29
|
+
CONSTRAINT "Spec_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
INSERT INTO "new_Spec" ("id","projectId","title","source","stage","priority","author","objective","payload","branchFrom","baseSha","headSha","version","createdAt","startedAt","updatedAt")
|
|
33
|
+
SELECT "id","projectId","title","source","stage","priority","author","objective","payload","branchFrom","baseSha","headSha","version",
|
|
34
|
+
"updatedAt",
|
|
35
|
+
CASE WHEN "baseSha" IS NOT NULL THEN "updatedAt" ELSE NULL END,
|
|
36
|
+
"updatedAt"
|
|
37
|
+
FROM "Spec";
|
|
38
|
+
|
|
39
|
+
DROP TABLE "Spec";
|
|
40
|
+
ALTER TABLE "new_Spec" RENAME TO "Spec";
|
|
41
|
+
|
|
42
|
+
PRAGMA foreign_keys=ON;
|
|
43
|
+
PRAGMA defer_foreign_keys=OFF;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
-- SPEC-409 · ADR-0091 · hanoman-lead: jejak keputusan + opt-in lead per project.
|
|
2
|
+
--
|
|
3
|
+
-- Ditulis tangan (bukan `migrate dev`): worktree tetangga membuat `migrate dev` me-reset DB saat
|
|
4
|
+
-- ada drift. Keduanya ADITIF — tak ada tabel yang diredefinisi, tak ada data yang disentuh.
|
|
5
|
+
--
|
|
6
|
+
-- `Project.leadOptIn` boleh lewat ALTER TABLE karena default-nya KONSTAN (`false`); larangan SQLite
|
|
7
|
+
-- hanya berlaku untuk default non-konstan seperti CURRENT_TIMESTAMP (lihat migration SPEC-408).
|
|
8
|
+
ALTER TABLE "Project" ADD COLUMN "leadOptIn" BOOLEAN NOT NULL DEFAULT false;
|
|
9
|
+
|
|
10
|
+
CREATE TABLE "LeadDecision" (
|
|
11
|
+
"id" TEXT NOT NULL PRIMARY KEY,
|
|
12
|
+
"projectId" TEXT NOT NULL,
|
|
13
|
+
"specId" TEXT,
|
|
14
|
+
"sessionId" TEXT,
|
|
15
|
+
"gate" TEXT NOT NULL,
|
|
16
|
+
"kind" TEXT NOT NULL,
|
|
17
|
+
"question" TEXT NOT NULL,
|
|
18
|
+
"answer" TEXT NOT NULL,
|
|
19
|
+
"reason" TEXT NOT NULL,
|
|
20
|
+
"refs" JSONB NOT NULL,
|
|
21
|
+
"confidence" TEXT NOT NULL,
|
|
22
|
+
"action" TEXT NOT NULL DEFAULT 'none',
|
|
23
|
+
"status" TEXT NOT NULL DEFAULT 'berlaku',
|
|
24
|
+
"weighty" BOOLEAN NOT NULL DEFAULT false,
|
|
25
|
+
"supersededById" TEXT,
|
|
26
|
+
"actor" TEXT NOT NULL DEFAULT 'lead',
|
|
27
|
+
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
28
|
+
"updatedAt" DATETIME NOT NULL
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
CREATE INDEX "LeadDecision_projectId_createdAt_idx" ON "LeadDecision"("projectId", "createdAt");
|
|
32
|
+
CREATE INDEX "LeadDecision_specId_idx" ON "LeadDecision"("specId");
|
|
33
|
+
CREATE INDEX "LeadDecision_sessionId_idx" ON "LeadDecision"("sessionId");
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
-- SPEC-384 · ADR-0092 · cabut error monitoring (SPEC-249/254/269/271/276/296) dan cross-audit
|
|
2
|
+
-- (SPEC-337). Pemantauan error produksi pindah ke Uptrace; data di bawah ini tak punya pembaca
|
|
3
|
+
-- lagi. DESTRUKTIF & TAK BISA DIBATALKAN.
|
|
4
|
+
--
|
|
5
|
+
-- Byte source-map hidup di HANOMAN_UPLOAD_DIR dengan nama opaque `<uuid>.map` — DIREKTORI YANG
|
|
6
|
+
-- SAMA dengan lampiran tiket. Migration SQL tak bisa menyentuh filesystem, jadi pembersihannya
|
|
7
|
+
-- adalah langkah runbook manual yang dijalankan SEBELUM migration ini: baca
|
|
8
|
+
-- `SELECT storageKey FROM SourceMapArtifact` lalu hapus tepat berkas-berkas itu (JANGAN direktorinya
|
|
9
|
+
-- — lampiran tiket ikut hilang). Lihat internal/docs/operations/production.md. Melewatkannya hanya
|
|
10
|
+
-- menyisakan byte inert.
|
|
11
|
+
|
|
12
|
+
-- `defer_foreign_keys` wajib berpasangan dengan `foreign_keys=OFF` di sini: Spec & Ticket memegang
|
|
13
|
+
-- FK ke "Project", dan rebuild di bawah menjatuhkan tabel itu sebelum penggantinya bernama sama.
|
|
14
|
+
-- Idiom yang sama dipakai migration SPEC-408.
|
|
15
|
+
PRAGMA foreign_keys=OFF;
|
|
16
|
+
PRAGMA defer_foreign_keys=ON;
|
|
17
|
+
|
|
18
|
+
-- 1. Tabel. ErrorEvent dulu (FK → ErrorGroup).
|
|
19
|
+
DROP TABLE IF EXISTS "ErrorEvent";
|
|
20
|
+
DROP TABLE IF EXISTS "SourceMapArtifact";
|
|
21
|
+
DROP TABLE IF EXISTS "ErrorGroup";
|
|
22
|
+
DROP TABLE IF EXISTS "ProjectLink";
|
|
23
|
+
|
|
24
|
+
-- 2. Project kehilangan kolom DSN. Table rebuild (pola Prisma untuk SQLite), bukan DROP COLUMN:
|
|
25
|
+
-- berkas DB ini bisa dibuka SQLite versi mana pun yang dibawa instalasi npm pengguna.
|
|
26
|
+
CREATE TABLE "new_Project" (
|
|
27
|
+
"id" TEXT NOT NULL PRIMARY KEY,
|
|
28
|
+
"name" TEXT NOT NULL,
|
|
29
|
+
"desc" TEXT NOT NULL,
|
|
30
|
+
"kind" TEXT NOT NULL,
|
|
31
|
+
"repoDir" TEXT,
|
|
32
|
+
"gitRemote" TEXT,
|
|
33
|
+
"stack" TEXT NOT NULL DEFAULT '',
|
|
34
|
+
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
35
|
+
"version" INTEGER NOT NULL DEFAULT 0,
|
|
36
|
+
"updatedAt" DATETIME NOT NULL,
|
|
37
|
+
"helpEnabled" BOOLEAN NOT NULL DEFAULT false,
|
|
38
|
+
"schedulerOptIn" BOOLEAN NOT NULL DEFAULT false,
|
|
39
|
+
"leadOptIn" BOOLEAN NOT NULL DEFAULT false
|
|
40
|
+
);
|
|
41
|
+
INSERT INTO "new_Project" ("id","name","desc","kind","repoDir","gitRemote","stack","createdAt","version","updatedAt","helpEnabled","schedulerOptIn","leadOptIn")
|
|
42
|
+
SELECT "id","name","desc","kind","repoDir","gitRemote","stack","createdAt","version","updatedAt","helpEnabled","schedulerOptIn","leadOptIn" FROM "Project";
|
|
43
|
+
DROP TABLE "Project";
|
|
44
|
+
ALTER TABLE "new_Project" RENAME TO "Project";
|
|
45
|
+
|
|
46
|
+
-- 3. Baris yang nilainya tak lagi sah menurut zod. Dibiarkan hidup, ia menggagalkan pembacaan
|
|
47
|
+
-- daftar notifikasi / backlog dengan galat parse — bukan dengan pesan yang berguna.
|
|
48
|
+
DELETE FROM "Notification" WHERE "type" = 'error';
|
|
49
|
+
-- Spec bersumber cross-audit DINORMALKAN, bukan dihapus: backlog item-nya pekerjaan nyata dengan
|
|
50
|
+
-- branch & dokumen; yang hilang cuma label asalnya.
|
|
51
|
+
UPDATE "Spec" SET "source" = 'audit' WHERE "source" = 'cross-audit';
|
|
52
|
+
DELETE FROM "SyncLog" WHERE "entity" = 'errorGroup';
|
|
53
|
+
DELETE FROM "SyncOutbox" WHERE "entity" = 'errorGroup';
|
|
54
|
+
DELETE FROM "SyncConflict" WHERE "entity" = 'errorGroup';
|
|
55
|
+
DELETE FROM "SchedulerQueueItem" WHERE "source" = 'errors';
|
|
56
|
+
|
|
57
|
+
PRAGMA foreign_keys=ON;
|
|
58
|
+
PRAGMA defer_foreign_keys=OFF;
|
package/prisma/schema.prisma
CHANGED
|
@@ -18,34 +18,11 @@ model Project {
|
|
|
18
18
|
createdAt DateTime @default(now())
|
|
19
19
|
version Int @default(0) // SPEC-213 · version-stamp sync (ADR-0045)
|
|
20
20
|
updatedAt DateTime @updatedAt
|
|
21
|
-
ingestKeyHash String? // SPEC-249 · sha256(ingest key) hex; null = monitoring off. TAK PERNAH ke client.
|
|
22
|
-
ingestKeyPrefix String? // SPEC-249 · ~12-16 char awal key untuk hint UI (bukan rahasia)
|
|
23
21
|
helpEnabled Boolean @default(false) // SPEC-253 · opt-in Help Center publik
|
|
24
22
|
schedulerOptIn Boolean @default(false) // SPEC-294 · ADR-0072 · opt-in scheduler otonom (LOCAL — tak masuk FIELDS sync)
|
|
23
|
+
leadOptIn Boolean @default(false) // SPEC-409 · ADR-0091 · opt-in hanoman-lead (LOCAL — cermin schedulerOptIn)
|
|
25
24
|
specs Spec[]
|
|
26
|
-
errorGroups ErrorGroup[]
|
|
27
25
|
tickets Ticket[]
|
|
28
|
-
sourceMaps SourceMapArtifact[] // SPEC-276 · source-map ter-upload per release (symbolication)
|
|
29
|
-
linksOut ProjectLink[] @relation("ProjectLinkFrom") // SPEC-337 · project ini bergantung pada …
|
|
30
|
-
linksIn ProjectLink[] @relation("ProjectLinkTo") // SPEC-337 · … yang bergantung pada project ini
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// SPEC-337 · ADR-0075 · relasi integrasi/dependency BERARAH antar project: from BERGANTUNG PADA to.
|
|
34
|
-
// LOCAL-only (tak masuk SYNCED): id cuid + unique pasangan bertabrakan saat upsert-by-id lintas device.
|
|
35
|
-
// onUpdate: Cascade → rename project (ADR-0064) merambat gratis; tak ada ref longgar baru.
|
|
36
|
-
model ProjectLink {
|
|
37
|
-
id String @id @default(cuid())
|
|
38
|
-
fromProjectId String
|
|
39
|
-
toProjectId String
|
|
40
|
-
kind String // api | sdk | data | event | lainnya (zLinkKind)
|
|
41
|
-
note String @default("") // bentuk integrasinya — disalin apa adanya ke prompt sesi audit lintas
|
|
42
|
-
createdAt DateTime @default(now())
|
|
43
|
-
updatedAt DateTime @updatedAt
|
|
44
|
-
from Project @relation("ProjectLinkFrom", fields: [fromProjectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
45
|
-
to Project @relation("ProjectLinkTo", fields: [toProjectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
|
46
|
-
|
|
47
|
-
@@unique([fromProjectId, toProjectId])
|
|
48
|
-
@@index([toProjectId])
|
|
49
26
|
}
|
|
50
27
|
|
|
51
28
|
model Spec {
|
|
@@ -62,6 +39,13 @@ model Spec {
|
|
|
62
39
|
baseSha String? // SPEC-176 · ADR-0030 · commit detach worktree sesi (nilai balik addWorktree)
|
|
63
40
|
headSha String? // SPEC-176 · ADR-0030 · commit HEAD worktree di akhir sesi (sebelum removeWorktree)
|
|
64
41
|
version Int @default(0) // SPEC-213 · version-stamp sync (ADR-0045)
|
|
42
|
+
// SPEC-408 · ADR-0090 · kapan item difilekan. Ditulis DB (@default), tak pernah oleh route —
|
|
43
|
+
// "dibuat" harus jadi fakta yang tak bisa diedit operator.
|
|
44
|
+
createdAt DateTime @default(now())
|
|
45
|
+
// SPEC-408 · ADR-0090 · kapan sesi PERTAMA lahir untuk item ini. Ditulis di titik cekik yang
|
|
46
|
+
// sama dengan `baseSha` (services/session-launch.ts); jalur RESUME (ADR-0084) sengaja tidak
|
|
47
|
+
// menimpanya — melanjutkan sesi bukan "mulai lagi". null = belum pernah dikerjakan.
|
|
48
|
+
startedAt DateTime?
|
|
65
49
|
updatedAt DateTime @updatedAt
|
|
66
50
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
|
67
51
|
}
|
|
@@ -302,7 +286,7 @@ model SchedulerQueueItem {
|
|
|
302
286
|
id String @id @default(cuid())
|
|
303
287
|
specId String @unique
|
|
304
288
|
projectId String
|
|
305
|
-
source String // backlog |
|
|
289
|
+
source String // backlog | triase (asal checker) — SPEC-384 · `errors` dicabut (ADR-0092)
|
|
306
290
|
priority String // tinggi | sedang | rendah (urutan drain)
|
|
307
291
|
status String @default("queued") // queued | launched | done | failed
|
|
308
292
|
sessionId String?
|
|
@@ -313,6 +297,39 @@ model SchedulerQueueItem {
|
|
|
313
297
|
@@index([status])
|
|
314
298
|
}
|
|
315
299
|
|
|
300
|
+
// SPEC-409 · ADR-0091 · jejak keputusan hanoman-lead. Data BARU yang harus bertahan (bukan nilai
|
|
301
|
+
// turunan seperti coverage/PRD, ADR-0011/0018): pertanyaan yang ditanyakan sesi yang sudah mati,
|
|
302
|
+
// dan alasan yang dipakai lead, tak bisa dihitung ulang dari sumber mana pun.
|
|
303
|
+
//
|
|
304
|
+
// LOCAL-ONLY (tak disync, cermin SessionHistory/SchedulerQueueItem): barisnya menunjuk sesi tmux &
|
|
305
|
+
// worktree di MESIN INI — menyiarkannya ke hub akan mengirim rujukan yang tak ada di sana. Tanpa
|
|
306
|
+
// `version`/notifySynced. Tak ada FK ke Project: sesi VPS memakai projectId sintetis
|
|
307
|
+
// (konvensi yang sama dipakai SessionResult & SessionHistory).
|
|
308
|
+
model LeadDecision {
|
|
309
|
+
id String @id @default(cuid())
|
|
310
|
+
projectId String
|
|
311
|
+
specId String?
|
|
312
|
+
sessionId String?
|
|
313
|
+
gate String // contract | detected | pulse (pintu masuk)
|
|
314
|
+
kind String // answer | order | collision | quality | refusal
|
|
315
|
+
question String
|
|
316
|
+
answer String
|
|
317
|
+
reason String
|
|
318
|
+
refs Json // string[] — hanya rujukan yang benar-benar ada di repo (AC-6)
|
|
319
|
+
confidence String // tinggi | sedang | ragu
|
|
320
|
+
action String @default("none") // permukaan tindakan lead (allowlist, shared/src/lead.ts)
|
|
321
|
+
status String @default("berlaku") // berlaku | ditimpa | dibatalkan | gagal
|
|
322
|
+
weighty Boolean @default(false) // memicu notifikasi (AC-25)
|
|
323
|
+
supersededById String? // baris yang menimpanya (jawaban operator, AC-28)
|
|
324
|
+
actor String @default("lead") // lead | operator — siapa yang mengeluarkan baris ini
|
|
325
|
+
createdAt DateTime @default(now())
|
|
326
|
+
updatedAt DateTime @updatedAt
|
|
327
|
+
|
|
328
|
+
@@index([projectId, createdAt])
|
|
329
|
+
@@index([specId])
|
|
330
|
+
@@index([sessionId])
|
|
331
|
+
}
|
|
332
|
+
|
|
316
333
|
// SPEC-215 · ADR-0049 · LOCAL-ONLY: override config runtime (env → DB). Tak pernah disync.
|
|
317
334
|
model RuntimeConfig {
|
|
318
335
|
key String @id
|
|
@@ -320,68 +337,8 @@ model RuntimeConfig {
|
|
|
320
337
|
updatedAt DateTime @updatedAt
|
|
321
338
|
}
|
|
322
339
|
|
|
323
|
-
// SPEC-249 · ADR-0060 · grup error per project (fingerprint dedup). SPEC-268/ADR-0066: agregat
|
|
324
|
-
// grup kini tersync (version-stamp); ErrorEvent mentah tetap server-local (tak disync).
|
|
325
|
-
model ErrorGroup {
|
|
326
|
-
id String @id @default(cuid())
|
|
327
|
-
projectId String
|
|
328
|
-
fingerprint String
|
|
329
|
-
type String
|
|
330
|
-
message String
|
|
331
|
-
sampleStack String?
|
|
332
|
-
sampleFrames Json? // SPEC-276 · ADR-0070 · frame mentah sample (disymbolikasi saat display)
|
|
333
|
-
release String? // SPEC-276 · ADR-0070 · release terakhir (korelasi build + surface di UI)
|
|
334
|
-
environment String
|
|
335
|
-
status String @default("new") // new | escalated | resolved
|
|
336
|
-
count Int @default(0)
|
|
337
|
-
firstSeenAt DateTime @default(now())
|
|
338
|
-
lastSeenAt DateTime @default(now())
|
|
339
|
-
specId String?
|
|
340
|
-
createdAt DateTime @default(now())
|
|
341
|
-
updatedAt DateTime @updatedAt
|
|
342
|
-
version Int @default(0) // SPEC-268 · version-stamp sync (ADR-0066)
|
|
343
|
-
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
|
344
|
-
events ErrorEvent[]
|
|
345
|
-
|
|
346
|
-
@@unique([projectId, fingerprint])
|
|
347
|
-
@@index([projectId, lastSeenAt])
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
// SPEC-249 · ADR-0060 · kejadian error mentah, dipangkas retensi (cap per grup + umur).
|
|
351
|
-
model ErrorEvent {
|
|
352
|
-
id String @id @default(cuid())
|
|
353
|
-
groupId String
|
|
354
|
-
projectId String
|
|
355
|
-
type String
|
|
356
|
-
message String
|
|
357
|
-
stack String?
|
|
358
|
-
frames Json? // SPEC-276 · ADR-0070 · frame terstruktur mentah dari SDK
|
|
359
|
-
environment String
|
|
360
|
-
release String?
|
|
361
|
-
context Json?
|
|
362
|
-
receivedAt DateTime @default(now())
|
|
363
|
-
group ErrorGroup @relation(fields: [groupId], references: [id], onDelete: Cascade)
|
|
364
|
-
|
|
365
|
-
@@index([groupId, receivedAt])
|
|
366
|
-
@@index([projectId, receivedAt])
|
|
367
|
-
}
|
|
368
340
|
|
|
369
|
-
// SPEC-276 · ADR-0070 · source-map ter-upload per release untuk symbolication. Byte map di
|
|
370
|
-
// HANOMAN_UPLOAD_DIR (server-local, TAK disync — cermin TicketAttachment biner & ErrorEvent).
|
|
371
|
-
model SourceMapArtifact {
|
|
372
|
-
id String @id @default(cuid())
|
|
373
|
-
projectId String
|
|
374
|
-
release String
|
|
375
|
-
filename String // basename artifact hasil-build (mis. index-4f3a2b.js) yang dipetakan map ini
|
|
376
|
-
debugId String?
|
|
377
|
-
storageKey String // berkas opaque (uuid.map) di upload dir
|
|
378
|
-
size Int
|
|
379
|
-
createdAt DateTime @default(now())
|
|
380
|
-
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
|
381
341
|
|
|
382
|
-
@@unique([projectId, release, filename])
|
|
383
|
-
@@index([projectId, release])
|
|
384
|
-
}
|
|
385
342
|
|
|
386
343
|
// SPEC-253 · ADR-0062 · tiket keluhan Help Center. SPEC-268/ADR-0066: metadata tiket kini tersync
|
|
387
344
|
// (version-stamp); lampiran (TicketAttachment, file biner) tetap server-local (tak disync).
|
|
@@ -396,7 +353,7 @@ model Ticket {
|
|
|
396
353
|
status String @default("new") // new | accepted | rejected (zTicketStatus)
|
|
397
354
|
accessKeyHash String @unique // sha256(kunci opaque) — lookup cek status. Plaintext hanya sekali.
|
|
398
355
|
shareToken String? @unique // SPEC-293 · token bagikan link status publik (hnm_shr_…); operator → pelapor
|
|
399
|
-
specId String? // soft-link Spec hasil promosi
|
|
356
|
+
specId String? // soft-link Spec hasil promosi
|
|
400
357
|
createdAt DateTime @default(now())
|
|
401
358
|
updatedAt DateTime @updatedAt
|
|
402
359
|
version Int @default(0) // SPEC-268 · version-stamp sync (ADR-0066)
|
|
@@ -411,7 +368,7 @@ model Ticket {
|
|
|
411
368
|
model TicketAttachment {
|
|
412
369
|
id String @id @default(cuid())
|
|
413
370
|
ticketId String
|
|
414
|
-
projectId String // denormal — isolasi & query murah
|
|
371
|
+
projectId String // denormal — isolasi & query murah
|
|
415
372
|
filename String // nama asli tersanitasi (display saja)
|
|
416
373
|
mimeType String // image/png | image/jpeg | image/webp
|
|
417
374
|
size Int
|