Back to Blog

Data Onboarding: From External Sources to Ontology Objects

Typical enterprise data source landscape:

CoomiaPublished on August 15, 202517 min read
Share this articleTwitter / X

Data Onboarding: From External Sources to Ontology Objects

Series: S4 Ontology Modeling · Article 11 | Level: Intermediate | Reading Time: 18 min

#TL;DR

  • Data Onboarding is the process of mapping external data sources to the Ontology model — raw data from CSV files, database tables, REST APIs, and message queues is transformed into ObjectType instances through mapping rules, bringing data "alive" in the Ontology.
  • Three synchronization modes (Full/Incremental/Real-time) cover every scenario from historical data migration to real-time data streams, each with clear applicability conditions, performance characteristics, and consistency guarantees.
  • Data Quality Gates execute validation before data enters the Ontology — type checks, required field checks, uniqueness checks, and referential integrity checks ensure "garbage data" never pollutes the Ontology.

#1. Why Data Onboarding Is a Key Challenge

#1.1 Diversity of Data Sources

Code
Typical enterprise data source landscape:

┌─────────────────────────────────────────────────┐
│         Enterprise Data Source Panorama           │
│                                                  │
│  Structured Data:                                │
│  ├── PostgreSQL (orders, customers, products)    │
│  ├── MySQL (inventory, warehousing)              │
│  ├── Oracle (ERP system)                         │
│  ├── SQL Server (financial system)               │
│  └── CSV/Excel (manual reports, historical data) │
│                                                  │
│  Semi-Structured Data:                           │
│  ├── REST API (third-party services)             │
│  ├── GraphQL API (partner platforms)             │
│  ├── JSON files (configs, logs)                  │
│  └── XML files (EDI, government data)            │
│                                                  │
│  Streaming Data:                                 │
│  ├── Kafka (event streams)                       │
│  ├── RabbitMQ (message queues)                   │
│  ├── WebSocket (real-time push)                  │
│  └── IoT device data streams                     │
│                                                  │
│  Challenges:                                     │
│  ├── Each data source has a different format     │
│  ├── Each data source has different connectivity │
│  ├── Data quality varies wildly                  │
│  └── All must be unified into the Ontology model │
└─────────────────────────────────────────────────┘

#1.2 coomia-dip Data Onboarding Architecture

Code
Data onboarding pipeline:

External Source → Connector → Mapper → Validator → Loader → Ontology

  Connector: Connects to data source, reads raw data
  Mapper: Maps raw fields to ObjectType properties
  Validator: Executes data quality checks
  Loader: Loads validated data into the Ontology

Each step is configurable, monitorable, and rollbackable.

#2. Connector: Data Source Connection

#2.1 Database Connector

Code
Database connector configuration:

connector:
  connectorId: "conn-pg-orders"
  type: DATABASE
  config:
    dialect: POSTGRESQL
    host: "orders-db.internal"
    port: 5432
    database: "orders"
    username: "${ORDERS_DB_USER}"
    password: "${ORDERS_DB_PASS}"
    schema: "public"
    ssl: true
    connectionPool:
      minSize: 2
      maxSize: 10
      idleTimeout: 300s

  tables:
    - tableName: "orders"
      targetObjectType: "Order"
      syncMode: INCREMENTAL
      incrementalColumn: "updated_at"
      primaryKey: "order_id"

    - tableName: "customers"
      targetObjectType: "Customer"
      syncMode: INCREMENTAL
      incrementalColumn: "modified_at"
      primaryKey: "customer_id"

  schedule:
    type: CRON
    expression: "*/5 * * * *"    # Every 5 minutes
    timezone: "UTC"

#2.2 REST API Connector

Code
REST API connector configuration:

connector:
  connectorId: "conn-api-weather"
  type: REST_API
  config:
    baseUrl: "https://api.weather.com/v3"
    authentication:
      type: API_KEY
      header: "X-API-Key"
      value: "${WEATHER_API_KEY}"
    rateLimit:
      requestsPerSecond: 10
      retryPolicy:
        maxRetries: 3
        backoffMultiplier: 2

  endpoints:
    - path: "/weather/current"
      method: GET
      parameters:
        city: "{{objectId}}"
      targetObjectType: "CityWeather"
      syncMode: FULL
      responseMapping:
        root: "$.data"

  schedule:
    type: INTERVAL
    interval: 15m

#2.3 Kafka Connector

Code
Kafka streaming connector configuration:

connector:
  connectorId: "conn-kafka-events"
  type: KAFKA
  config:
    bootstrapServers: "kafka-1:9092,kafka-2:9092"
    groupId: "coomia-dip-ingestion"
    topics:
      - topic: "order-events"
        targetObjectType: "Order"
        keyField: "orderId"
        format: JSON
      - topic: "user-activities"
        targetObjectType: "UserActivity"
        keyField: "userId"
        format: AVRO
        schemaRegistry: "http://schema-registry:8081"

    consumer:
      autoOffsetReset: EARLIEST
      maxPollRecords: 500
      sessionTimeout: 30s

    syncMode: REALTIME
    errorHandling:
      deadLetterTopic: "coomia-dip-dlq"
      maxRetries: 5

#2.4 CSV/File Connector

Code
File connector configuration:

connector:
  connectorId: "conn-csv-products"
  type: FILE
  config:
    source:
      type: S3
      bucket: "data-imports"
      prefix: "products/"
      filePattern: "*.csv"
    format:
      type: CSV
      delimiter: ","
      header: true
      encoding: "UTF-8"
      quoteChar: '"'
      escapeChar: '\\'
      nullValues: ["", "NULL", "N/A"]

    targetObjectType: "Product"
    syncMode: FULL
    primaryKey: "product_id"

    postProcess:
      archiveProcessed: true
      archivePath: "products/processed/"
      deleteAfterProcess: false

  schedule:
    type: FILE_WATCHER
    pollInterval: 30s

#3. Mapper: Field Mapping

#3.1 Mapping Rule Definition

Code
Field mapping configuration:

mapping:
  sourceConnector: "conn-pg-orders"
  sourceTable: "orders"
  targetObjectType: "Order"

  fieldMappings:
    # Direct mapping (field name and type match)
    - source: "order_id"
      target: "orderId"
      type: DIRECT

    # Type conversion mapping
    - source: "total_amount"
      target: "totalAmount"
      type: CAST
      castConfig:
        from: NUMERIC
        to: DECIMAL
        precision: 18
        scale: 4

    # Enum mapping
    - source: "status"
      target: "orderStatus"
      type: ENUM_MAP
      enumMapping:
        "0": "PENDING"
        "1": "CONFIRMED"
        "2": "SHIPPED"
        "3": "DELIVERED"
        "9": "CANCELLED"

    # Expression mapping
    - source: null
      target: "displayName"
      type: EXPRESSION
      expression: "CONCAT('Order #', order_id, ' - ', customer_name)"

    # Date format conversion
    - source: "created_at"
      target: "createdAt"
      type: DATE_FORMAT
      sourceFormat: "yyyy-MM-dd HH:mm:ss"
      targetFormat: "ISO8601"

    # JSON field extraction
    - source: "metadata"
      target: "shippingAddress"
      type: JSON_PATH
      jsonPath: "$.shipping.address"

    # Relation mapping
    - source: "customer_id"
      target: "customer"
      type: RELATION
      relationConfig:
        relationType: "OrderBelongsToCustomer"
        targetObjectType: "Customer"
        targetProperty: "customerId"

    # Constant value
    - source: null
      target: "dataSource"
      type: CONSTANT
      value: "orders-db"

#3.2 Multi-Source Merging

Code
Multiple data sources mapping to the same ObjectType:

Scenario: Customer data spread across 3 systems

Source 1: CRM System (basic info)
  customer_id → customerId
  full_name → name
  email → email
  phone → phone
  created_date → createdAt

Source 2: Order System (spending info)
  customer_id → customerId (join key)
  total_orders → orderCount
  total_spent → totalSpent
  last_order_date → lastOrderAt

Source 3: Support System (service info)
  cust_id → customerId (join key)
  satisfaction_score → satisfactionScore
  ticket_count → supportTicketCount
  last_contact → lastContactAt

Merge strategy:
  mergeStrategy:
    primarySource: "crm-system"     # Basic info from CRM as authority
    mergeKey: "customerId"          # Join via customerId
    conflictResolution:
      name: PREFER_PRIMARY           # Name from primary source
      email: MOST_RECENT             # Email uses most recent update
      phone: PREFER_PRIMARY           # Phone from primary source
      default: MOST_RECENT           # Other fields use most recent

Merged Customer object contains data from all 3 systems.
Any system's data update reflects in the unified Customer object.

#3.3 Mapping Validation

Code
Mapping rules are auto-validated at registration:

Validation checks:
├── Source field existence: Does the field exist in source table/API
├── Target property existence: Is the property defined in ObjectType
├── Type compatibility: Can source type safely convert to target type
├── Required coverage: All required properties have mappings
├── Primary key mapping: Is primary key mapping defined
├── Relation references: Does the target ObjectType exist
└── Expression syntax: Is the expression syntax correct

Validation report example:
┌─────────────────────────────────────────────────┐
│  Mapping Validation Report                       │
│  Source: orders (PostgreSQL)                     │
│  Target: Order (ObjectType)                      │
├─────────────────────────────────────────────────┤
│  Field mappings: 12                              │
│  Valid: 11                                       │
│  Warnings: 1                                    │
│  Errors: 0                                      │
│                                                  │
│  Warning:                                        │
│  ├── Field "discount_code" in source has no      │
│  │   mapping. Data will be ignored.              │
│                                                  │
│  Coverage:                                       │
│  ├── Source fields mapped: 11/15 (73%)           │
│  ├── Target properties covered: 12/14 (86%)     │
│  ├── Unmapped target: "priority" (has default)   │
│  │   "tags" (nullable)                           │
│  └── All required properties covered: YES        │
└─────────────────────────────────────────────────┘

#4. Validator: Data Quality Gate

#4.1 Quality Check Rules

Code
Layered data quality checking strategy:

Layer 1 — Format checks (fast, per-row):
├── Type matching: Can string parse to target type
├── Length limits: Does string exceed max length
├── Format matching: Date, email, URL format validation
├── Range checks: Is numeric value within allowed range
└── Null checks: Are required fields populated

Layer 2 — Semantic checks (slower, batch):
├── Uniqueness: Are primary keys unique
├── Referential integrity: Do referenced objects exist
├── Enum value check: Is value in enum list
├── Business rules: Custom validation logic
└── Cross-field checks: Logical relationships between fields

Layer 3 — Statistical checks (after batch completes):
├── Anomaly detection: Does value deviate from historical distribution
├── Completeness: Does missing rate exceed threshold
├── Consistency: Comparison with other data sources
└── Trend check: Are there abnormal value fluctuations

#4.2 Quality Check Configuration

Code
Quality check rule configuration:

qualityRules:
  objectType: "Order"
  rules:
    - ruleId: "qr-001"
      name: "Order amount non-negative"
      field: "totalAmount"
      check: RANGE
      config:
        min: 0
        max: 10000000
      severity: ERROR          # Reject if fails

    - ruleId: "qr-002"
      name: "Customer reference integrity"
      field: "customer"
      check: REFERENTIAL_INTEGRITY
      config:
        targetObjectType: "Customer"
        targetField: "customerId"
      severity: ERROR

    - ruleId: "qr-003"
      name: "Email format"
      field: "customerEmail"
      check: REGEX
      config:
        pattern: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
      severity: WARNING        # Mark warning if fails

    - ruleId: "qr-004"
      name: "Order date reasonable"
      field: "orderDate"
      check: EXPRESSION
      config:
        expression: "orderDate <= NOW() AND orderDate >= '2020-01-01'"
      severity: ERROR

    - ruleId: "qr-005"
      name: "Amount anomaly detection"
      field: "totalAmount"
      check: ANOMALY
      config:
        method: Z_SCORE
        threshold: 3.0
        baseline: LAST_30_DAYS
      severity: WARNING

#4.3 Quality Report

Code
Quality report generated for each data onboarding batch:

┌──────────────────────────────────────────────────────┐
│  Data Quality Report                                  │
│  Source: orders (PostgreSQL)                          │
│  Batch: batch-20250115-001                           │
│  Records: 10,000                                     │
├──────────────────────────────────────────────────────┤
│                                                       │
│  Summary:                                             │
│  ├── Total records: 10,000                            │
│  ├── Passed: 9,823 (98.23%)                          │
│  ├── Warnings: 145 (1.45%)                           │
│  ├── Rejected: 32 (0.32%)                            │
│  └── Quality Score: 98.23 / 100                      │
│                                                       │
│  Rule Results:                                        │
│  ├── qr-001 (Amount non-neg): PASS 9,998 / FAIL 2   │
│  ├── qr-002 (Customer ref):  PASS 9,970 / FAIL 30   │
│  ├── qr-003 (Email format):  PASS 9,855 / WARN 145  │
│  ├── qr-004 (Date valid):    PASS 10,000 / FAIL 0   │
│  └── qr-005 (Amount anomaly): PASS 9,980 / WARN 20  │
│                                                       │
│  Rejected Records (sample):                           │
│  ├── Row 3421: totalAmount = -500 (qr-001)           │
│  ├── Row 5892: customer_id = "CUST-9999" not found   │
│  └── Row 7234: totalAmount = -200 (qr-001)           │
│                                                       │
│  Action:                                              │
│  ├── 9,823 records loaded to Ontology                │
│  ├── 145 records loaded with WARNING flag            │
│  ├── 32 records sent to quarantine                   │
│  └── Quarantine records available for manual review  │
└──────────────────────────────────────────────────────┘

#5. Synchronization Modes

#5.1 Full Sync

Code
Applicable scenarios:
├── First-time data import
├── Small data volume (< 1 million rows)
├── Data source has no incremental identifier
└── Requires full consistency

Flow:
  1. Read all data from source table
  2. Map + Validate
  3. Compare with existing Ontology data
  4. Execute INSERT / UPDATE / DELETE
  5. Record sync results

Comparison strategy:
  Source has + Ontology doesn't → INSERT
  Source has + Ontology has + values changed → UPDATE
  Source has + Ontology has + values same → SKIP
  Source doesn't + Ontology has → DELETE (or mark STALE)

Full sync configuration:
syncConfig:
  mode: FULL
  batchSize: 1000
  parallelism: 4
  deletePolicy: SOFT_DELETE    # Don't physically delete, mark inactive
  conflictResolution: SOURCE_WINS
  timeout: 30m

#5.2 Incremental Sync

Code
Applicable scenarios:
├── Data source has updated_at / version field
├── Medium to large data volume (1M ~ 100M rows)
├── Regular sync needed (every 5 min ~ every hour)
└── Brief inconsistency acceptable

Flow:
  1. Read last sync watermark
  2. Query records where updated_at > watermark
  3. Map + Validate
  4. Execute INSERT / UPDATE
  5. Update watermark

Watermark management:
  watermarkStore:
    connectorId: "conn-pg-orders"
    tableName: "orders"
    watermarkColumn: "updated_at"
    currentWatermark: "2025-01-15T10:25:00Z"
    lastSyncRecords: 342
    lastSyncDuration: 12.5s

Incremental sync pitfalls:
├── Deletes: Incremental sync can't detect DELETE in source
│   → Solution: Soft delete field (is_deleted) or periodic full compare
├── Backfill: If someone modifies records before updated_at
│   → Solution: Periodic full validation (e.g., daily)
├── Clock skew: Source database clock may be imprecise
│   → Solution: Watermark overlap (e.g., rewind 30 seconds)
└── Bulk updates: Updating 1M rows at once, incremental query is slow
    → Solution: Batch processing + timeout fallback to full mode

#5.3 Real-time Sync

Code
Applicable scenarios:
├── Second-level latency required
├── Data source supports CDC or message queues
├── Critical business data
└── Batch latency unacceptable

CDC (Change Data Capture) approach:
  1. Listen to database binlog / WAL
  2. Capture INSERT / UPDATE / DELETE events
  3. Map + Validate
  4. Write to Ontology in real-time

  Configuration example:
  connector:
    type: CDC
    config:
      database: POSTGRESQL
      host: "orders-db.internal"
      replicationSlot: "coomia-dip_cdc"
      publication: "orders_pub"
      tables: ["orders", "customers", "line_items"]

  Advantages:
  ├── Low latency (seconds)
  ├── Captures all changes (including DELETE)
  ├── No additional load on source database (reads WAL, not table)
  └── Guarantees ordering

Message queue approach:
  1. Application sends events to Kafka
  2. coomia-dip consumes events
  3. Map + Validate
  4. Write to Ontology

  Even lower latency (milliseconds)
  But requires application cooperation to send events

#6. Data Onboarding Orchestration

#6.1 Dependency Ordering

Code
Multiple ObjectType onboarding has ordering dependencies:

Scenario: E-commerce data onboarding

Dependencies:
  Customer → no dependency (import first)
  Product → no dependency (import first)
  Order → depends on Customer (Customer must exist first)
  LineItem → depends on Order + Product
  Payment → depends on Order

Onboarding order orchestration:
  Phase 1 (parallel): Customer, Product
  Phase 2 (parallel): Order (waits for Phase 1)
  Phase 3 (parallel): LineItem, Payment (waits for Phase 2)

Orchestration configuration:
orchestration:
  name: "ecommerce-full-import"
  phases:
    - phase: 1
      parallel: true
      connectors:
        - "conn-crm-customers"
        - "conn-pim-products"
    - phase: 2
      dependsOn: [1]
      connectors:
        - "conn-oms-orders"
    - phase: 3
      dependsOn: [2]
      parallel: true
      connectors:
        - "conn-oms-lineitems"
        - "conn-pay-payments"

  errorPolicy:
    phaseFailure: STOP_ALL    # Phase failure stops subsequent phases
    connectorFailure: CONTINUE # One connector failure doesn't affect others

#6.2 Backfill Strategies

Code
Backfill strategies for first-time historical data onboarding:

Scenario: Onboarding 5 years of historical order data (50M rows)

Strategy 1 — Time-sliced backfill:
  Slice 5 years of data by month
  Each slice imported independently
  Process multiple slices in parallel

  timeline:
    sliceBy: MONTH
    startDate: "2020-01-01"
    endDate: "2025-01-15"
    parallelSlices: 4

  Result:
  60 months x 830K rows/month
  4 parallel slices
  Estimated time: ~2 hours

Strategy 2 — Priority backfill:
  Import most recent data first (users can use immediately)
  Backfill historical data in background

  priority:
    - range: "LAST_30_DAYS"    # Import last 30 days first
      parallelism: 8
    - range: "LAST_365_DAYS"   # Then past year
      parallelism: 4
    - range: "ALL"             # Then all history
      parallelism: 2

Strategy 3 — Gradual backfill:
  Run at low load during business hours
  Run at high load during off-hours

  schedule:
    daytime:   # 09:00-18:00
      parallelism: 2
      batchSize: 500
    nighttime: # 18:00-09:00
      parallelism: 8
      batchSize: 5000

#7. Error Handling and Quarantine

#7.1 Quarantine Zone

Code
Records that fail validation enter the quarantine zone:

Quarantine purposes:
├── Prevent bad data from entering Ontology
├── Preserve original data for manual review
├── Record failure reasons
├── Support re-import after fixing
└── Provide quality trend analysis

Quarantine record:
{
  "quarantineId": "q-20250115-001",
  "connectorId": "conn-pg-orders",
  "batchId": "batch-20250115-001",
  "sourceRecord": {
    "order_id": "ORD-999",
    "customer_id": "CUST-9999",
    "total_amount": -500,
    "status": "1"
  },
  "targetObjectType": "Order",
  "failedRules": [
    {
      "ruleId": "qr-001",
      "ruleName": "Order amount non-negative",
      "field": "totalAmount",
      "value": -500,
      "reason": "Value -500 is below minimum 0"
    },
    {
      "ruleId": "qr-002",
      "ruleName": "Customer reference integrity",
      "field": "customer_id",
      "value": "CUST-9999",
      "reason": "Customer CUST-9999 not found in Ontology"
    }
  ],
  "quarantinedAt": "2025-01-15T10:30:00Z",
  "status": "PENDING_REVIEW"
}

Quarantine operations:
  Manual review → Fix data → Re-validate → Import to Ontology
  or
  Manual review → Confirm as garbage data → Permanently discard

#7.2 Retry Mechanism

Code
Retry strategy for transient errors:

Transient error types:
├── Network timeout
├── Database connection lost
├── Message queue unavailable
├── API rate limited (429)
└── Target storage temporarily unavailable

Retry configuration:
retryPolicy:
  maxRetries: 5
  backoff:
    type: EXPONENTIAL
    initialDelay: 1s
    maxDelay: 60s
    multiplier: 2
  retryableErrors:
    - CONNECTION_TIMEOUT
    - TEMPORARY_UNAVAILABLE
    - RATE_LIMITED
  nonRetryableErrors:
    - VALIDATION_FAILED
    - MAPPING_ERROR
    - AUTHENTICATION_FAILED

Retry example:
  Attempt 1: Failed (timeout) → wait 1s
  Attempt 2: Failed (timeout) → wait 2s
  Attempt 3: Failed (timeout) → wait 4s
  Attempt 4: Success ✓

Dead Letter Queue (DLQ):
  All 5 retries failed → message goes to DLQ
  DLQ messages are not auto-retried
  Requires manual investigation then manual replay

#8. Data Onboarding Monitoring

#8.1 Onboarding Status Dashboard

Code
Data onboarding monitoring panel:

┌──────────────────────────────────────────────────────┐
│  Data Onboarding Dashboard                            │
├──────────────────────────────────────────────────────┤
│                                                       │
│  Active Connectors: 12 / 15                          │
│  ├── Healthy: 10                                     │
│  ├── Warning: 2 (lag > 5min)                         │
│  └── Error: 0                                        │
│                                                       │
│  Last 24h Summary:                                   │
│  ├── Records processed: 2,345,678                    │
│  ├── Records loaded: 2,310,234 (98.5%)              │
│  ├── Records quarantined: 35,444 (1.5%)             │
│  ├── Average latency: 3.2s                          │
│  └── Peak throughput: 12,500 records/s              │
│                                                       │
│  Connector Health:                                   │
│  ┌──────────────────┬────────┬─────────┬──────────┐ │
│  │ Connector        │ Status │ Lag     │ Quality  │ │
│  ├──────────────────┼────────┼─────────┼──────────┤ │
│  │ pg-orders        │ OK     │ 30s    │ 99.2%    │ │
│  │ kafka-events     │ OK     │ 2s     │ 97.8%    │ │
│  │ api-weather      │ WARN   │ 8m     │ 100%     │ │
│  │ csv-products     │ OK     │ 0s     │ 98.5%    │ │
│  │ cdc-inventory    │ OK     │ 1s     │ 99.9%    │ │
│  └──────────────────┴────────┴─────────┴──────────┘ │
└──────────────────────────────────────────────────────┘

#8.2 Data Lineage Tracking

Code
Every Ontology record is traceable to its data source:

Data Lineage:

Query: Where did this Order's data come from?

GET /api/v1/objects/Order/ORD-001/lineage

{
  "objectId": "ORD-001",
  "objectType": "Order",
  "sources": [
    {
      "connector": "conn-pg-orders",
      "table": "orders",
      "primaryKey": "ORD-001",
      "lastSyncAt": "2025-01-15T10:30:00Z",
      "syncMode": "INCREMENTAL",
      "batchId": "batch-20250115-042"
    }
  ],
  "propertyLineage": {
    "orderId": {"source": "orders.order_id", "transform": "DIRECT"},
    "totalAmount": {"source": "orders.total_amount", "transform": "CAST(DECIMAL)"},
    "orderStatus": {"source": "orders.status", "transform": "ENUM_MAP(0→PENDING,1→CONFIRMED...)"},
    "customer": {"source": "orders.customer_id", "transform": "RELATION(Customer)"}
  },
  "qualityFlags": {
    "customerEmail": "WARNING: invalid format"
  }
}

Purposes:
├── Quality debugging: Where did this odd value come from?
├── Compliance audit: What's the source of this customer data?
├── Impact analysis: If source schema changes, which Ontology objects are affected?
└── Debugging: Why doesn't this object's value match the source data?

#9. Practical Example: E-Commerce Data Onboarding

#9.1 Complete Onboarding Plan

Code
E-commerce platform data onboarding panorama:

┌─────────────────────────────────────────────────────┐
│                                                      │
│  [CRM MySQL] ──CDC──→ Customer (real-time)           │
│  [PIM PostgreSQL] ──Incr──→ Product (5 min)          │
│  [OMS PostgreSQL] ──CDC──→ Order, LineItem (real-time)│
│  [Payment Gateway API] ──Incr──→ Payment (1 min)     │
│  [Kafka Events] ──RT──→ UserActivity (real-time)     │
│  [Logistics API] ──Incr──→ Shipment (15 min)         │
│  [CSV Reports] ──Full──→ FinancialReport (daily)     │
│  [IoT MQTT] ──RT──→ WarehouseDevice (real-time)      │
│                                                      │
│  Onboarding order:                                   │
│  Phase 1: Customer, Product (master data)            │
│  Phase 2: Order (depends on Customer)                │
│  Phase 3: LineItem, Payment, Shipment (depend on Order)│
│  Phase 4: UserActivity, WarehouseDevice (independent) │
│  Phase 5: FinancialReport (daily summary)            │
│                                                      │
│  Volume estimates:                                   │
│  Customer: 5M, incremental ~1,000/day                │
│  Product: 1M, incremental ~500/day                   │
│  Order: 50M, incremental ~50,000/day                 │
│  LineItem: 200M, incremental ~200,000/day            │
│  UserActivity: ~10M/day (event stream)               │
└─────────────────────────────────────────────────────┘

#10. Comparison with Palantir Foundry

Code
Data onboarding capability comparison:

┌──────────────────┬────────────────────┬────────────────────┐
│ Feature          │ coomia-dip          │ Palantir Foundry   │
├──────────────────┼────────────────────┼────────────────────┤
│ Connector types  │ DB/API/Kafka/File  │ 200+ connectors    │
│ Mapping approach │ Declarative YAML   │ Pipeline Builder   │
│ Quality checks   │ Multi-layer valid. │ Checks framework   │
│ CDC support      │ PostgreSQL/MySQL   │ Multi-database     │
│ Real-time stream │ Kafka/MQTT         │ Multiple platforms │
│ Data lineage     │ Property-level     │ Column-level       │
│ Quarantine       │ Yes                │ Yes                │
│ Multi-source     │ Yes                │ Yes                │
│ Orchestration    │ Phase-based        │ Pipeline DAG       │
│ Visualization    │ Dashboard          │ Pipeline visual    │
│ Community conn.  │ In development     │ Rich ecosystem     │
└──────────────────┴────────────────────┴────────────────────┘

coomia-dip data onboarding goal is not to replicate Foundry's 200+ connectors,
but to provide a flexible framework where 80% of common scenarios
(relational databases, REST APIs, Kafka, CSV) work out of the box.

#Key Takeaways

  1. Data onboarding is the Ontology's "lifeline" — no matter how perfect the ObjectType definitions, without reliable data onboarding pipelines, the Ontology is an empty shell. The Connector + Mapper + Validator + Loader four-step pipeline ensures data flows reliably from external sources into the Ontology.
  2. Three sync modes cover all scenarios — Full (first import, small data), Incremental (periodic sync, medium-large data), Real-time (CDC/Kafka, second-level latency). Choose based on business needs and data source capabilities.
  3. Data Quality Gates are the core defense — format checks, semantic checks, and statistical checks in three layers ensure "garbage data" is intercepted outside the Ontology. The quarantine zone preserves original data for manual review and repair.
  4. Multi-source merging creates a unified view — a Customer's data may come from CRM, order system, and support system. The merge strategy auto-handles conflicts, and consumers see a unified Customer object.
  5. Data lineage is the foundation of trust — every piece of data traces back to its original source, mapping rules, and quality flags. When data issues arise, you can quickly pinpoint which data source and which sync batch introduced the problem.

#Next Article

The next article S4-12 Auto-Provisioning discusses automated infrastructure provisioning for the Ontology — when a new ObjectType is registered, the system automatically creates storage tables, indexes, API endpoints, and permission configurations, achieving "define and deploy" with zero manual intervention.

#ontology #data-onboarding #etl #connector #data-quality #cdc #incremental-sync #data-lineage #mapping