Optical Extensions (Hooks, Endpoints, Modules)




๐Ÿš€ Understanding Optical (Directus) Extensions — Full Detailed Guide With Real Examples


Optical = Directus + Custom Extensions + Flows + Integrations


Extensions เคšाเคฐ เคธ्เคคเคฐों เคชเคฐ เค•ाเคฎ เค•เคฐเคคे เคนैं:

  1. Hooks → Events listener (เคœเคฌ data create/update เคนो)

  2. Endpoints → Custom API routes

  3. Modules → Custom UI (Admin panel เคฎें custom page)

  4. Interfaces / Displays → Custom form fields / data displays


๐ŸŸฃ 1. HOOKS — Event-Based Automation

Event Meaning
items.create.before New item insert เคนोเคจे เคธे เคชเคนเคฒे
items.create.after Insert เคนोเคจे เค•े เคฌाเคฆ
items.update.after Record update เค•े เคฌाเคฆ
items.delete.after Delete เค•े เคฌाเคฆ
auth.login.after เค•िเคธी user เคจे login เค•िเคฏा
files.upload เค•िเคธी asset เค•ो upload เค•िเคฏा


Hook เคซ़ाเค‡เคฒ เคนเคฎेเคถा เคฏเคนाँ เคฐเคนเคคी เคนै:

extensions/hooks/<hook-name>/index.js


✔️ Example 1: PRJ User Audit Hook

Whenever a User Profile updates → insert audit log.


module.exports = function registerHook({ services }) {
  const { ItemsService } = services;

  return {
    'items.update.after': async function(input) {
      const service = new ItemsService('PRJ_User_Audit', {
        schema: input.schema,
        accountability: input.accountability,
      });

      await service.createOne({
        user_id: input.key,
        updated_at: new Date(),
        changes: input.payload
      });
    }
  };
};


What this does:

  • Any update in user_profile

  • Makes a new row inside PRJ_User_Audit

  • Stores timestamp + changes

✔️ Example 2: Auto-Approval Logic (BCA Worker POC)

If worker confidence_score > 80 → auto approve


module.exports = ({ services }) => {

  const { ItemsService } = services;


  return {

    'items.create.after': async (ctx) => {

      if (ctx.collection !== 'Worker_Profile') return;


      const score = ctx.payload.confidence_score;

      const service = new ItemsService('Worker_Profile', {

        schema: ctx.schema,

        accountability: ctx.accountability

      });


      if (score >= 80) {

        await service.updateOne(ctx.key, {

          Status: "Approved"

        });

      }

    }

  };

};



๐Ÿ”ต 2. ENDPOINTS — Custom API Routes

Use cases: lightweight API server inside Optical.

  • Passport OCR API

  • MOM WPOL Simulation API

  • BCA Worker Test Result Aggregation API

  • ICA ACK API

  • Health check endpoints

  • Bulk fetch APIs


extensions/endpoints/<endpoint-name>/index.js

Define endpoint:

module.exports = {
  id: 'passport-ocr',
  handler: async (router, ctx) => {

    router.post('/run', async (req, res) => {
      const file_id = req.body.passport_asset_id;

      // call external KIE OCR
      const extracted = await runOCR(file_id);

      res.json({
        status: "success",
        extracted
      });
    });

  }
};

Call API from Postman:
POST http://localhost:8055/passport-ocr/run


✔️ Real Example: MOM Work Permit Generator Endpoint


router.post('/generate-wp', async (req, res) => {
  const worker_id = req.body.worker_id;

  const wpno = "WP2025-" + Math.floor(100000 + Math.random()*900000);

  await workerService.updateOne(worker_id, {
    work_permit_number: wpno,
    Status: "Approved - Pending Work Permit Application"
  });

  res.json({ worker_id, wpno });
});


๐ŸŸข 3. MODULES — Custom Screens in Admin Panel

Modules = Optical เค•े Admin Panel เคฎें new menu + custom UI.

Use cases:

  • BCA Monitoring Dashboard

  • Firm-based Test Score summary

  • Assessor Allocation UI

  • Worker Passport OCR Tools

  • CSO Tools

  • PRJ Tools dashboard

  • MOM simulation dashboard


Files in:
extensions/modules/<module-name>/src/

Main entry:
index.js

Example:
export default {
  id: 'bca-dashboard',
  name: 'BCA Dashboard',
  icon: 'dashboard',
  routes: [
    {
      path: '',
      component: () => import('./Dashboard.vue')
    }
  ]
}

This automatically creates:

๐Ÿ“Œ A new menu item in left navigation
๐Ÿ“Œ Clicking it shows your custom Vue UI (Dashboard.vue)


✔️ Example BCA Dashboard Module

Dashboard.vue contains:

  • Total workers

  • Pass/Fail rate

  • Arrival rate

  • Test Participation

  • Confidence Score (firm-based)

  • Random Audit candidates

This is exactly what we did in BCA demo.


๐ŸŸก 4. INTERFACES — Custom Input Field Components

Interface = เคจเคฏी form input type.

Use cases:

  • ICA date selector with YYYYMMDD

  • Passport MRZ scanner input

  • FIN validator input

  • Trade specialization picker

  • Firm-selector popup

  • Auto complete from external API

Structure:

extensions/interfaces/<interface-name>/src/

Example:

export default {

  id: 'fin-input',

  name: 'FIN Input (Validator)',

  type: 'string',

  icon: 'badge',

  component: () => import('./fin-input.vue')

}


๐ŸŸ  5. DISPLAYS — Custom Display Component (Read-only)

Display = List view เคฏा detail view เคฎें custom look

Examples:

  • Status badge (green/red/orange)

  • Confidence Score color-coded

  • Passport expiry warning (red)

  • Worker Age calculation

Location:

extensions/displays/<display-name>/src/

Example:
export default {
  id: 'status-badge',
  name: 'Status Badge',
  component: () => import('./status.vue')
}


๐Ÿง  How All Extensions Work Together (Real PRJ/BCA Example)

Here’s a real scenario combining all extension types:

Scenario: Passport Upload → Extract → Validate → Update CMS

Step 1 — User uploads passport

(Directus event fires)

Step 2 — Hook files.upload

→ Sends passport to OCR API
→ Gets extracted values
→ Updates User Profile

Step 3 — Endpoint /passport-ocr/run

→ Can be used manually for reprocessing

Step 4 — Module “Passport Tools”

→ Admins can trigger extraction
→ View extracted results
→ Correct values manually

Step 5 — Display “Expiry Warning”

→ If passport_expiry < 1 month → show RED ⚠️


๐ŸŒ Folder Summary (Everything Together)


extensions/

├── hooks/

│   ├── prjourney-user-audit/

│   ├── passport-auto-extract/

├── endpoints/

│   ├── passport-ocr/

│   ├── mom-wp-generator/

│   ├── test-result-api/

├── modules/

│   ├── bca-dashboard/

│   ├── prj-tools/

├── interfaces/

│   ├── fin-input/

│   ├── date-yyyymmdd/

└── displays/

    ├── status-badge/

    ├── expiry-warning/



๐ŸŽฏ Where to Use What? (Cheat Guide)

Requirement Use Why
Auto update database fields Hook Data event triggered
Create custom API Endpoint Public/Private programmatic access
Create custom UI page Module New admin panel screen
Create custom form input Interface For editors/data entry
Display custom-colored values Display For lists & details

Comments