Skip to main content

Naming Conventions

This document outlines the standard naming conventions and coding patterns for the backend hooks codebase. Follow these guidelines to ensure consistency and maintainability.

Directory Structure​

Hooks are organized under apps/api/src/app/hooks in a collection → hook hierarchy. Each hook has its own directory containing 3 files:

apps/api/src/app/hooks/
├── finance-general-ledger/ ← hook collection (kebab-case)
│ ├── collection.json ← collection metadata
│ ├── create-general-ledger-account/ ← individual hook (kebab-case)
│ │ ├── hook.json ← hook metadata (name, slug, path, version, etc.)
│ │ ├── context.md ← hook description
│ │ └── create-general-ledger-account.finance-general-ledger.hook.ts
│ └── delete-general-ledger-account/
│ ├── hook.json
│ ├── context.md
│ └── delete-general-ledger-account.finance-general-ledger.hook.ts

File Naming​

Hook files follow a strict kebab-case pattern: hook-name.collection-name.hook.ts

  • Format: hook-slug.collection-slug.hook.ts
  • Extension: .hook.ts

Examples​

StatusFilenameReason
✅ DOcalculate-new-transaction.finance-general-ledger.hook.tsCorrect kebab-case + collection + extension
✅ DOcomplete-manufacturing-order.manufacturing-ai.hook.tsCorrect kebab-case + collection + extension
❌ DON'TFinanceGeneralLedger.tsWrong case, missing .hook, missing collection
❌ DON'TcalculateNewTransaction.hooks.tscamelCase, old .hooks extension, missing collection

Class Naming​

Class names combine the collection name and hook name in PascalCase, without underscores or unique IDs.

  • Format: PascalCaseCollectionPascalCaseHookName

Examples​

StatusClass NameReason
✅ DOFinanceGeneralLedgerCreateGeneralLedgerAccountCollection + hook name in PascalCase
✅ DOManufacturingAiGenerateManufacturingSummaryCollection + hook name in PascalCase
❌ DON'TFinanceGeneralLedger_iqbvltadOld format with underscore + unique ID
❌ DON'TcreateGeneralLedgerAccountcamelCase, missing collection prefix

Method Naming​

The entry-point method for every hook is always execute(). This is the method that the event engine calls.

  • Entry point: Always public static execute()
  • Internal helpers: Use descriptive camelCase names (e.g., calculateTotal, validateUser)

Examples​

StatusMethod NameContext
✅ DOexecute()Entry-point method — always this name
✅ DOcalculateSubtotal()Internal helper method
❌ DON'TcalculateBillOfMaterials()As an entry point — use execute()
❌ DON'TRun()PascalCase, too generic

Code Structure & Patterns​

We follow a strict "Bob Request" pattern for all hook methods, wrapped with the @LogicHook decorator.

The @LogicHook Decorator​

Every hook class must be decorated with @LogicHook which provides metadata to the event engine:

import { BobRequest, returnEventResult } from '@logic-bee/event-engine'
import { NaoQueryOptions } from '@logic-bee/flow-query'
import { naoFormatErrorById, SuperJoi } from '@logic-bee/utils'
import { LogicHook } from '@logic-bee/logic-hooks'

@LogicHook({
name: 'Create general ledger account',
slug: 'create-general-ledger-account',
path: 'finance-general-ledger/create-general-ledger-account',
legacy: 'FinanceGeneralLedger_iqbvltad.createGeneralLedgerAccount',
hookCollection: 'finance-general-ledger',
version: 1,
concurrency: 'parallel',
timeout: 30000,
idempotent: false,
pattern: 'hook',
patternScore: 0
})
export class FinanceGeneralLedgerCreateGeneralLedgerAccount {

/**
* Describe what this method does clearly.
*/
public static execute() {
return async (
bob: BobRequest<{
data: {
data: any
naoQueryOptions: NaoQueryOptions
}
}>
) => {
let ok = true,
error: any = null,
data

try {
/**START_CODE_LOGIC*/

// Your business logic goes here
ok = true
data = { result: "success" }

/**END_CODE_LOGIC*/
} catch (err) {
error = err
ok = false
}
// -->Return: result
return returnEventResult(bob, { ok, error, data })
}
}
}

@LogicHook Properties​

PropertyDescription
nameHuman-readable hook name
slugKebab-case identifier
pathcollection-slug/hook-slug
legacyOld format reference (for migration)
hookCollectionCollection slug this hook belongs to
versionHook version number
concurrency'parallel' or 'sequential'
timeoutExecution timeout in milliseconds
idempotentWhether the hook is safe to retry
patternHook pattern type (e.g., 'hook')
patternScorePriority/ordering score

Comments & Annotations​

Use specific comment styles to denote actions and logic blocks.

  • Logic Blocks: Always wrap your core logic with /**START_CODE_LOGIC*/ and /**END_CODE_LOGIC*/.
  • Action Steps: Use // -->Action: description to describe significant steps in the process.
// -->Update: manufacturing order with finalize reason and user

// -->Verb: {subject} {qualifier} │ │ │ │ │ └── condition, source, or constraint │ └──────────── the exact entity being acted on └──────────────────── what operation

Examples​

// ✅ DO: Use directional comments for steps
// -->Get: inventory settings
const inventorySettings = await ...

// -->Check: if the item exists
if (!item) { ... }

// -->Calculate: total cost
const total = ...

// ❌ DON'T: Use random comment styles
// getting the settings now
// checking item

Common Pitfalls​

  • DON'T put logic outside the try...catch block.
  • DON'T forget to return returnEventResult.
  • DON'T use console.log for debugging; use naoLogger or logg.
  • DON'T name variables with single letters (e.g., x, y); use descriptive names (e.g., stockItem, totalCost).
  • DON'T use @bob-api/* imports; use @logic-bee/*.