feat: add AssetModel Prisma model + migration
This commit is contained in:
@@ -0,0 +1,14 @@
|
|||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "asset_models" (
|
||||||
|
"id" UUID NOT NULL,
|
||||||
|
"category_id" UUID NOT NULL,
|
||||||
|
"manufacturer" TEXT NOT NULL,
|
||||||
|
"name" TEXT NOT NULL,
|
||||||
|
"specs" JSONB NOT NULL DEFAULT '{}',
|
||||||
|
"created_at" TIMESTAMPTZ(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
|
CONSTRAINT "asset_models_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "asset_models" ADD CONSTRAINT "asset_models_category_id_fkey" FOREIGN KEY ("category_id") REFERENCES "asset_categories"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
@@ -242,6 +242,13 @@ model AssetCategory {
|
|||||||
valueGroup AssetCategoryValueGroup @map("value_group")
|
valueGroup AssetCategoryValueGroup @map("value_group")
|
||||||
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
|
||||||
attributeDefs AssetCategoryAttributeDef[]
|
attributeDefs AssetCategoryAttributeDef[]
|
||||||
|
// Back-relation for AssetModel.categoryId — see "Cập nhật 2026-08-02 (2)"
|
||||||
|
// in docs/asset-license-management.md. Only categories with
|
||||||
|
// valueGroup=high_value are ever actually referenced by an AssetModel (a
|
||||||
|
// business rule enforced in src/lib/asset-models.ts's createAssetModel(),
|
||||||
|
// not expressible as a Prisma-level constraint), but the relation itself
|
||||||
|
// is not restricted to high_value categories at the schema level.
|
||||||
|
assetModels AssetModel[]
|
||||||
|
|
||||||
@@map("asset_categories")
|
@@map("asset_categories")
|
||||||
}
|
}
|
||||||
@@ -293,6 +300,37 @@ model AssetCategoryAttributeDef {
|
|||||||
@@map("asset_category_attribute_defs")
|
@@map("asset_category_attribute_defs")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sits between AssetCategory and AssetItem — see docs/
|
||||||
|
// asset-license-management.md's "Cập nhật 2026-08-02 (2)" section and the
|
||||||
|
// `AssetModel` row in the "Data model (sơ bộ)" table. 1 AssetModel has many
|
||||||
|
// AssetItem serials (AssetItem.modelId FK, not built in this task).
|
||||||
|
// `manufacturer`/`name` are deliberately two separate String fields (not
|
||||||
|
// merged into one), per the doc, to allow filtering/reporting by
|
||||||
|
// manufacturer alone (e.g. "Dell") without string-parsing a combined field.
|
||||||
|
// `categoryId` is a required FK to AssetCategory — the DB layer doesn't
|
||||||
|
// enforce that the referenced category is `high_value` (Prisma/Postgres FK
|
||||||
|
// constraints can't express that), that business rule is checked in
|
||||||
|
// src/lib/asset-models.ts's createAssetModel() via an explicit lookup
|
||||||
|
// before the create, per the doc's "Ràng buộc dữ liệu" section. `specs` is
|
||||||
|
// JSONB, defaulting to an empty object — the real per-category dynamic
|
||||||
|
// attribute *values* (whose *shape* is defined by
|
||||||
|
// AssetCategoryAttributeDef rows for this model's category). This task
|
||||||
|
// deliberately does NOT validate specs against the category's attribute
|
||||||
|
// defs (loose z.record(z.unknown()) validation only, see
|
||||||
|
// src/lib/asset-models.ts) — that dynamic cross-validation is a separate
|
||||||
|
// follow-up task per the doc's "Cập nhật 2026-08-02 (3)" section.
|
||||||
|
model AssetModel {
|
||||||
|
id String @id @default(uuid()) @db.Uuid
|
||||||
|
categoryId String @map("category_id") @db.Uuid
|
||||||
|
category AssetCategory @relation(fields: [categoryId], references: [id])
|
||||||
|
manufacturer String
|
||||||
|
name String
|
||||||
|
specs Json @default("{}")
|
||||||
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
|
||||||
|
|
||||||
|
@@map("asset_models")
|
||||||
|
}
|
||||||
|
|
||||||
// Minimal internal auth accounts — NOT company SSO (deliberately ruled out,
|
// Minimal internal auth accounts — NOT company SSO (deliberately ruled out,
|
||||||
// see CLAUDE.md / auth decision notes). A handful of trusted IT staff
|
// see CLAUDE.md / auth decision notes). A handful of trusted IT staff
|
||||||
// accounts, created by hand via scripts/create-user.ts, no self-registration.
|
// accounts, created by hand via scripts/create-user.ts, no self-registration.
|
||||||
|
|||||||
Reference in New Issue
Block a user