Pembuatan modul fondasi data

Meskipun Cortex Framework menyediakan modul fondasi data siap pakai untuk sistem ERP perusahaan seperti SAP (cortex.sap), Anda juga dapat membuat modul fondasi data kustom baru dalam namespace kustom. Hal ini memungkinkan Anda menentukan perilaku build kustom dan memperluas dukungan ke sistem sumber baru. Hal ini dapat mencakup sistem pengelolaan database seperti PostgreSQL, MySQL, dll. yang mereplikasi data mentahnya ke BigQuery.

Panduan ini akan memandu Anda melalui contoh menyeluruh tentang cara membuat modul fondasi data baru untuk Sistem Tiket Layanan Pelanggan yang datanya (tabel customers, tickets, ticketlogitem) telah direplikasi dari database PostgreSQL ke set data BigQuery mentah bernama ticketing_data_raw.

Saat membuat modul fondasi data kustom, sebaiknya gunakan namespace kustom khusus untuk meningkatkan pengelolaan siklus proses dengan memisahkan ekstensi dan penyesuaian dari artefak Cortex Framework.

Ringkasan contoh skenario

Dalam panduan ini, kita akan:

  1. Membuat namespace kustom khusus ticketing untuk mengisolasi aset fondasi data.
  2. Menentukan modul fondasi data baru dengan jalur ticketing.ticketing.foundations.ticketing_system.
  3. Mengonfigurasi setelan tabel (table_settings.default.yaml) untuk tabel customers, tickets, dan ticketlogitem.
  4. Membuat anotasi metadata tingkat kolom dan kolom untuk setiap tabel.
  5. Mendaftarkan sumber data mentah (ticketing_data_raw), set data yang sesuai target (data_foundation_ticketing), dan modul fondasi baru di config/config.yaml.

Struktur folder dan file modul

Semua file fisik untuk modul fondasi data baru Anda berada di dalam namespace kustom di bagian src/data_modules/. Tabel dan diagram direktori berikut menguraikan tempat untuk menempatkan setiap file:

config/
└── config.yaml                                           # Global configuration & module registration
src/data_modules/ticketing/ticketing/foundations/ticketing_system/
├── manifest.yaml                                         # Declares module category, type, and builder
├── table_settings.default.yaml                           # Table materialization, bigQueryLabels, dataformTags, and layouts
├── builder.py                                            # (Optional) Custom Dataform generator class for this module
└── annotations/                                          # Field and column-level schema descriptions
    ├── customers.yaml
    ├── tickets.yaml
    └── ticketlogitem.yaml

Penting: Sebelum memulai, pastikan tabel sumber yang ingin Anda proses ada di set data lapisan mentah.

Jalur file atau direktori Tujuan dan deskripsi
config/config.yaml Mendaftarkan namespace ticketing, sumber data mentah PostgreSQL, set data BigQuery target, dan instance modul fondasi.
src/data_modules/ticketing/ticketing/foundations/ticketing_system/manifest.yaml Mendeklarasikan metadata modul, nama tampilan, kategori (misalnya, foundation), jenis modul (misalnya, generic), dan class builder generator yang digunakan selama kompilasi.
src/data_modules/ticketing/ticketing/foundations/ticketing_system/table_settings.default.yaml Mengonfigurasi tabel sumber dari ticketing_data_raw yang harus disesuaikan, beserta dataformTags BigQuery, bigQueryLabels, detail partisi, dan detail cluster.
src/data_modules/ticketing/ticketing/foundations/ticketing_system/annotations/*.yaml Berisi metadata YAML lengkap yang menjelaskan definisi tabel dan kolom. Metadata ini otomatis digabungkan ke dalam definisi Dataform yang dikompilasi sehingga deskripsi tetap ada di metadata tabel BigQuery.
src/data_modules/ticketing/ticketing/foundations/ticketing_system/builder.py Opsional. Jika database sumber Anda memerlukan pembersihan data kustom atau transformasi SQL khusus dialek selama kompilasi, Anda dapat menentukan class builder tingkat modul di sini.

Langkah 1: Daftarkan namespace, sumber data, dan target di config.yaml

Sebelum membuat file fisik, buka file konfigurasi deployment (config/config.yaml) dan deklarasikan namespace kustom, set data sumber PostgreSQL mentah, dan set data tujuan tempat tabel yang sesuai akan dibuat:

data:
  namespaces:
    - name: cortex
      path: ../src/data_modules/cortex
    - name: ticketing                              # <-- Name of custom namespace
      path: ../src/data_modules/ticketing          # <-- Points to subdirectory under 'src/data_modules/'

  datasets:
    - id: ticketing_data_raw                       # <-- Unique source ID
      projectId: "source_project_id"
      datasetId: ticketing_data_raw                # <-- Raw dataset containing PostgreSQL replication tables
    - id: data_foundation_ticketing                # <-- Unique target ID
      projectId: "target_project_id"
      datasetId: data_foundation_ticketing         # <-- Target dataset for conformed foundation tables

Langkah 2: Daftarkan modul fondasi data di config.yaml

Di bagian data.modules.foundations dari config/config.yaml, daftarkan instance modul fondasi data baru, yang menautkan sumber data (ticketing_data_raw) ke target data (data_foundation_ticketing):

data:
  modules:
    foundations:
      - moduleId: ticketing_foundation
        modulePath: ticketing.ticketing.foundations.ticketing_system   # Format: {namespace}.{systemtype}.{module_type:foundations}.{subsystemtype}
        dataSourceId: ticketing_data_raw
        dataTargetId: data_foundation_ticketing
        # Custom table settings file relative to 'config/' directory
        # Recommended path: '{namespace_dir}/{system_type}/foundations/{system_sub_type}/table_settings.yaml'
        # If omitted, defaults to "../src/data_modules/ticketing/ticketing/foundations/ticketing_system/table_settings.default.yaml"
        tableSettings: "ticketing/ticketing/foundations/ticketing_system/table_settings.yaml"

Langkah 3: Buat file manifes modul

Buat file manifes yang mendeklarasikan metadata modul Anda: src/data_modules/ticketing/ticketing/foundations/ticketing_system/manifest.yaml.

displayName: Ticketing System Data Foundation
description: Conformed foundation tables for PostgreSQL raw ticketing database.
category: foundation
type: generic
builder: ticketing_foundation

Langkah 4: Buat file setelan tabel (table_settings.default.yaml)

Buat file konfigurasi tabel default src/data_modules/ticketing/ticketing/foundations/ticketing_system/table_settings.default.yaml. File ini menentukan cara tabel PostgreSQL yang direplikasi (customers, tickets, ticketlogitem) diwujudkan, dipartisi, dan dikelompokkan dalam BigQuery:

common:
  - source:
      tableName: customers
    target:
      bigQueryLabels:
        - key: data_class
          value: master
      dataformTags: [ticketing, foundation, masterdata]
      clusterDetails:
        columns: [customer_id]

  - source:
      tableName: tickets
    target:
      bigQueryLabels:
        - key: data_class
          value: transactional
      dataformTags: [ticketing, foundation, transactional]
      partitionDetails:
        column: created_at
        partitionType: time
        timeGrain: day
      clusterDetails:
        columns: [ticket_id, customer_id]

  - source:
      tableName: ticketlogitem
    target:
      bigQueryLabels:
        - key: data_class
          value: transactional
      dataformTags: [ticketing, foundation, transactional]
      partitionDetails:
        column: log_timestamp
        partitionType: time
        timeGrain: day
      clusterDetails:
        columns: [ticket_id, log_id]

Langkah 5: Buat anotasi metadata tingkat kolom

Untuk memastikan tabel yang sesuai berisi dokumentasi yang jelas di BigQuery, buat file YAML anotasi untuk setiap tabel di dalam src/data_modules/ticketing/ticketing/foundations/ticketing_system/annotations/. Nama file harus sama persis dengan nama tabel sumber.

annotations/customers.yaml

description: "Customer master data conformed from PostgreSQL raw ticketing database."
fields:
  - name: "customer_id"
    description: "Unique customer identifier, PK"
  - name: "email"
    description: "Primary email address associated with the customer"
  - name: "full_name"
    description: "Customer full name or account contact name"
  - name: "created_at"
    description: "Timestamp when the customer record was originally created in PostgreSQL"

annotations/tickets.yaml

description: "Customer service tickets conformed from PostgreSQL raw ticketing database."
fields:
  - name: "ticket_id"
    description: "Unique ticket identifier, PK"
  - name: "customer_id"
    description: "Foreign key referencing customers.customer_id"
  - name: "subject"
    description: "Summary or subject line of the customer inquiry"
  - name: "status"
    description: "Current ticket lifecycle status (e.g., OPEN, IN_PROGRESS, RESOLVED, CLOSED)"
  - name: "priority"
    description: "Priority severity level (e.g., LOW, MEDIUM, HIGH, URGENT)"
  - name: "created_at"
    description: "Timestamp when the ticket was created"
  - name: "updated_at"
    description: "Timestamp when the ticket was last modified"

annotations/ticketlogitem.yaml

description: "Audit log history and activity events for customer service tickets."
fields:
  - name: "log_id"
    description: "Unique log event identifier, PK"
  - name: "ticket_id"
    description: "Foreign key referencing tickets.ticket_id"
  - name: "action"
    description: "Action or event performed on the ticket"
  - name: "description"
    description: "Notes and description on performed events on the ticket"
  - name: "performed_by"
    description: "User, agent, or automated system that performed the action"
  - name: "log_timestamp"
    description: "Exact timestamp when the activity log event occurred"

Langkah 6: (Opsional) Tentukan builder fondasi kustom

Jika fondasi data PostgreSQL Anda memerlukan logika selama kompilasi (seperti transmisi jenis data otomatis, konversi stempel waktu, atau aturan pembersihan data di semua tabel), Anda dapat menentukan builder kustom yang dicakup ke modul ini.

Buat src/data_modules/ticketing/ticketing/foundations/ticketing_system/builder.py:

import logging
import pathlib
import yaml
from common.builders.base import FoundationBuilder, Source
from common.registry import builder_registry
from common.schemas import config_schema, manifest_schema

logger = logging.getLogger(__name__)

@builder_registry.register("ticketing_foundation")
class TicketingFoundationBuilder(FoundationBuilder[config_schema.BaseModuleConfig]):
    """Custom Dataform generator for PostgreSQL ticketing data foundation."""

    def build(
        self,
        *,
        module_id: str,
        module_config: config_schema.BaseModuleConfig,
        global_config: config_schema.GlobalConfig,
        manifest: manifest_schema.ManifestConfig,
        base_dir: pathlib.Path,
        annotations_dir: pathlib.Path,
        output_dir: pathlib.Path,
        module_dir_name: str,
        sources_registry: set[Source],
        table_settings_file: pathlib.Path | None = None,
        required_tables: set[str] | None = None,
    ) -> None:
        logger.info("Building ticketing data foundation for module: %s", module_id)
        
        # 1. Load table settings
        if not table_settings_file or not table_settings_file.exists():
            logger.warning("No valid table settings found for %s", module_id)
            return

        with open(table_settings_file, encoding="utf-8") as f:
            settings = yaml.safe_load(f) or {}

        tables = settings.get("common", [])
        source_config = global_config.get_data_source(module_config.data_source_id)
        target_dataset = global_config.get_data_target(module_config.data_target_id)

        # 2. Generate Dataform .sqlx files for each table
        for table_item in tables:
            source_table = table_item["source"]["tableName"]
            if required_tables and source_table not in required_tables and not table_item.get("deployAlways"):
                continue

            # Register source table for centralized source generation
            sources_registry.add(Source(source_config.project_id, source_config.dataset_id, source_table))

            # Retrieve labels if configured
            bigquery_config = {}
            if "bigQueryLabels" in table_item["target"]:
                labels_dict = {label["key"]: label["value"] for label in table_item["target"]["bigQueryLabels"]}
                bigquery_config["labels"] = labels_dict

            dataform_tags = table_item["target"].get("dataformTags", ["ticketing", "foundation"])

            sqlx_content = f"""config {{
  type: "table",
  schema: "{target_dataset.dataset_id}",
  name: "{source_table}",
  tags: {dataform_tags}"""
            
            if bigquery_config:
                sqlx_content += f",\n  bigquery: {bigquery_config}"
                
            sqlx_content += f"""
}}

SELECT *
FROM `${{source_config.project_id}}.${{source_config.dataset_id}}.{source_table}`
"""
            out_file = output_dir / f"{source_table}.sqlx"
            out_file.write_text(sqlx_content, encoding="utf-8")
            logger.info("Generated %s", out_file)

Verifikasi modul fondasi baru

Untuk memverifikasi dan men-deploy modul fondasi data yang baru dibuat:

  1. Jalankan skrip build dan deployment Cortex Framework: bash uv run cortex-build-and-deploy --config "config/config.yaml"
  2. Periksa apakah kompilasi Dataform berhasil tanpa error dan skrip .sqlx dibuat untuk customers, tickets, dan ticketlogitem.
  3. Ikuti Langkah-langkah pasca-deployment untuk menjalankan tindakan pipeline Dataform dan memverifikasi kumpulan data yang sesuai di dalam set data data_foundation_ticketing di BigQuery.

Untuk memverifikasi bahwa modul fondasi data kustom berhasil dikompilasi dan di-deploy, lihat bagian Verifikasi di halaman ekstensibilitas produk data.