Files
nick-doc/02 - Data Models/Category.md
2026-06-01 17:22:53 +04:00

3.2 KiB

title, tags, aliases
title tags aliases
Category
data-model
mongoose
postgres
Category Model
Taxonomy
ICategory

Category

Hierarchical taxonomy node used by PurchaseRequest and RequestTemplate. Each row is bilingual (name in the local language, nameEn in English), supports parent/child via parentId, has an icon and a display order, and an isActive toggle for soft-removal.

[!note] Source backend/src/models/Category.ts:15 — schema definition backend/src/models/Category.ts:64 — model export backend/src/services/marketplace/categoryStore.ts:89 — Postgres runtime bootstrap and duplicate cleanup backend/src/db/schema/category.ts:88 — Drizzle active normalized-name unique index

Schema

Field Type Required Default Validation Index Description
name String yes trim yes Local language name.
nameEn String yes trim unique English name.
description String no trim Description.
icon String no trim Icon identifier / URL.
isActive Boolean no true yes Active flag.
parentId ObjectId → Category no null yes Parent category (null for top level).
order Number no 0 Display order.
createdAt Date auto Mongoose timestamp.
updatedAt Date auto Mongoose timestamp.

Virtuals

None defined.

Indexes

Defined at backend/src/models/Category.ts:55-62:

  • { name: 1 }
  • { nameEn: 1 }, unique
  • { isActive: 1 }
  • { parentId: 1 }

Postgres runtime and Drizzle additionally enforce:

  • categories_legacy_object_id_uq: unique Mongo bridge id for idempotent backfill/upsert.
  • categories_active_name_norm_uq: unique active category display label using lower(btrim(name)) WHERE is_active = true.
  • Existing duplicate active PG rows are deactivated before the unique index is created; purchase-request category references and child category parents are repointed to the kept row.

Pre/Post Hooks

None declared.

Instance Methods

None defined.

Static Methods

None defined.

Relationships

State Transitions

No status field — only the isActive boolean for soft-disable.

stateDiagram-v2
    [*] --> active
    active --> inactive : admin disables
    inactive --> active : admin re-enables

Common Queries

// Top-level categories; runtime store dedupes active rows by normalized display name.
Category.find({ parentId: null, isActive: true }).sort({ order: 1 });

// Children of a category
Category.find({ parentId, isActive: true }).sort({ order: 1 });

// Bilingual search
Category.find({ $or: [{ name: regex }, { nameEn: regex }], isActive: true });

// Full tree (basic, two-level)
const roots = await Category.find({ parentId: null }).sort({ order: 1 });
const children = await Category.find({ parentId: { $in: roots.map(r => r._id) } });

Related: PurchaseRequest, RequestTemplate.