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/*.