model.constant.ts

The constant file defines the data shape (schema) of your domain. It ensures consistency between database storage, API communication, and frontend usage by creating a single source of truth.
📐Type Safety
Schema definitions are shared across backend and frontend, ensuring type consistency throughout your application.
🔄Auto Generation
From your constant definitions, the framework auto-generates MongoDB schemas, GraphQL types, REST APIs, and client-side types.

Class Hierarchy Pattern

Akan.js uses a hierarchical class pattern to organize schema definitions. Each layer has a specific purpose and builds upon the previous one.
1
Input
Fields required to create a new document (user-provided data)
2
Object
Input + system-generated fields (status, timestamps, computed values)
3
Light
Lightweight version with selected fields for list queries (prevents overfetching)
4
Full (Model)
Complete model with all fields and static/instance utility methods
5
Insight
Statistical aggregation fields for analytics (count, sum, avg)

Defining Enums with enumOf()

Before defining your model classes, you typically need to define enums for status fields and other categorical values. The enumOf() function creates type-safe enum classes.
product.constant.ts
Key points about enumOf():
as const

Required for TypeScript to infer literal types instead of string[]

First argument

The enum name used in dictionary translations

Generated type

Access values via ProductStatus["value"] type (e.g., "active" | "soldOut" | ...)

Input Class - Creation Fields

The Input class defines fields required when creating a new document. These are the values a user or system must provide.
product.constant.ts
Understanding the via() pattern:
via((field) => ({...}))

Creates a new class with the specified fields. The field() function takes a type and optional options.

field(Type, options?)

Type can be: String, Int, Float, Boolean, Date, JSON, ID, [Array], custom classes, or enums.

.optional()

Chain .optional() to make a field nullable. The field can then be omitted or set to null.

💡Usage in Code
Input fields are used in: fetch.createProduct(input), st.do.setNameOnProduct(value), productForm state

Object Class

The Object class extends Input and adds fields that are automatically set by the system. These fields are typically modified through service methods, not through direct user input.
product.constant.ts
Common Object fields:
status

Document lifecycle state, controlled by service methods

stock

Inventory count, default to 0, modified by sell operations

soldCount

Accumulated sales count for analytics

Light Class - Optimized for Lists

The Light class picks only necessary fields from Object for list views. This prevents overfetching when displaying multiple items in tables or cards.
product.constant.ts
Performance Benefits

When fetching 100 products for a list, Light ensures only essential fields are transferred, reducing payload size and database load.

Field Selection

Choose fields that appear in list UIs: identifiers, status, key metadata. Exclude: content, files, detailed nested objects.

Resolve Function

The (resolve) => ({}) function can add computed/virtual fields that are calculated server-side but not stored in DB.

Full Model - Complete with Methods

The Full model (often named after the domain like 'Product') combines Object and Light, and adds static utility methods for data manipulation.
product.constant.ts
Static Methods

Static methods operate on arrays of items. Use for filtering, grouping, or computing derived data from lists.

Usage Example

const activeProducts = cnst.Product.getActiveList(productList);

Insight Class

The Insight class defines aggregation fields for analytics. When querying, the framework calculates these statistics using MongoDB aggregation pipeline.
product.constant.ts
Understanding the accumulate option:
{ $sum: 1 }

Simple count - adds 1 for each matching document

{ $sum: "$fieldName" }

Sum of field values across all matching documents

{ $cond: [...] }

Conditional aggregation - count only documents matching a condition

Usage in code:
Using Insight

Scalar - Embedded Objects

Scalars are embedded objects that don't have their own collection. They're stored within the parent document and defined using via() without the full class hierarchy.
milestone.constant.ts
Using scalars in parent models:
bizContract.constant.ts
When to use Scalars

Data that belongs to a single parent (1:N embedded). No need for separate queries or references. Data always accessed with parent document.

Scalar Location

Scalars are typically placed in __scalar/ directory to indicate they're embedded types, not standalone collections.

Relation Patterns

There are three main ways to establish relationships between models in Akan.js, following MongoDB schema design principles.
Scalar Embedding

Embed scalar objects directly in the document. Best for 1:N relationships where child data is always accessed with parent.

Reference by ID

Store only the ObjectID of related document. Best when you need to query the referenced collection separately.

Light Model Reference

Embed a Light version of another model. Best when you need key fields without full population.

Field Options Reference

The field() function accepts various options to configure validation, defaults, database behavior, and more. Here's the complete reference:
default:any | (() => any):-

Default value when no value is provided. Can be a static value or a function for dynamic defaults.

nullable:boolean:false

If true, the field can be null or omitted. Equivalent to using .optional() chain method.

ref:string:-

Reference collection name for ID fields. Used for MongoDB population.

refPath:string:-

Dynamic reference path - uses another field's value to determine the referenced collection.

refType:"child" | "parent" | "relation":-

Type of reference relationship. Affects how population and cascading operations work.

type:"email" | "password" | "url":-

Preset type that applies default validation and example values for common patterns.

fieldType:"property" | "hidden" | "resolve":"property"

property: normal field, hidden: backend-only (not sent to frontend), resolve: computed field (not stored in DB).

immutable:boolean:false

If true, field cannot be modified after document creation. Only set during create.

min:number:-

Minimum value constraint for Int or Float fields. Validation runs on save.

max:number:-

Maximum value constraint for Int or Float fields. Validation runs on save.

minlength:number:-

Minimum string length constraint for String fields.

maxlength:number:-

Maximum string length constraint for String fields.

enum:EnumClass:-

Restrict field values to enum values. Typically used with enumOf() defined classes.

select:boolean:true

If false, field is excluded from default queries. Use for sensitive or large fields.

accumulate:object:-

MongoDB aggregation expression for Insight fields. Calculates statistics across matched documents.

example:any:-

Example value for API documentation generation (Swagger/OpenAPI).

of:Type:-

Value type for Map fields. The key is always string, value type is specified by 'of'.

validate:(value, model) => boolean:-

Custom validation function. Receives the field value and full model, returns boolean.

text:"search" | "filter":-

Enable text indexing for full-text search (search) or filtering (filter) capabilities.

meta:object:-

Custom metadata object for additional field information used by UI components or plugins.

fieldType Options
property

Normal field - stored in DB, sent to frontend

hidden

Backend only - stored in DB but never sent to frontend (e.g., OTP codes)

resolve

Virtual field - computed on query, not stored in DB (e.g., view count from other collection)

refType Options
parent

This document belongs to the referenced document

child

Referenced document belongs to this document

relation

Many-to-many relationship without ownership

Common field patterns:
Common Field Patterns

Constant Best Practices

Class Ordering

Define in order: Enums → Input → Object → Light → Full → Insight. This prevents forward reference issues.

Light Field Selection

Include: id, status, key identifiers, timestamps. Exclude: large content fields, files, detailed nested objects.

Default Values

Always provide defaults for Object fields. Use functions for dynamic values like dates: () => dayjs()

Static Methods

Add static utility methods to Full class for filtering/grouping logic. Keep them pure (no side effects).

Import Paths

Always use direct file imports for other constants to avoid circular references. Never import from barrel files.

Released under the MIT License
Official Akan.js Consulting onAkansoft
Copyright © 2025 Akan.js. All rights reserved.
System managed bybassman