LIBRE / README.md
RyZ
docs: adding architecture documentation
b44d190
|
Raw
History Blame Contribute Delete
53.3 kB
metadata
title: BP Monitoring Pipeline
emoji: 🩺
colorFrom: red
colorTo: blue
sdk: docker
app_port: 7860
pinned: false

BP Monitoring Pipeline

Clean Architecture & System Design Documentation

Architecture Principles Pipeline Python License

Dokumen ini menjelaskan arsitektur, design patterns, dan keputusan teknis yang digunakan dalam pipeline data monitoring tekanan darah berbasis sinyal PPG (Photoplethysmography) dari perangkat IoT.


Status: Production-Ready Design Β· Versi: 1.0.0 Β· Terakhir Diperbarui: 30 Mei 2026


πŸ“‘ Daftar Isi


1. Executive Summary

BP Monitoring Pipeline adalah sistem data pipeline yang dirancang untuk memproses sinyal PPG (Photoplethysmography) dari perangkat IoT melalui smartphone, kemudian melakukan inferensi menggunakan model deep learning (GAN dan VGTL-Net) untuk memprediksi ABP (Arterial Blood Pressure) secara non-invasif.

Tujuan Utama

# Tujuan Deskripsi
1 Reliability Menjamin data PPG dari sensor IoT tidak hilang selama proses transmisi dan penyimpanan
2 Scalability Arsitektur yang dapat berkembang seiring bertambahnya jumlah sensor dan pengguna
3 Maintainability Codebase yang mudah dipahami, dimodifikasi, dan di-debug oleh seluruh anggota tim
4 Replaceability Setiap komponen eksternal (database, message broker, model AI) dapat diganti tanpa mengubah business logic
5 Testability Setiap layer dapat di-test secara independen melalui unit test dan integration test

Keputusan Arsitektural Utama

Keputusan Pilihan Alasan
Architecture Style Clean Architecture Separation of concerns, dependency inversion, framework independence
Communication Pattern Asynchronous Messaging (Message Queue) Decoupling antara Data Node dan Model Node
Data Pipeline Pattern ETL (Extract-Transform-Load) Data harus di-transform sebelum masuk ke downstream (model dan database)
Deployment Strategy Multi-platform (HF Spaces + Kaggle) Cost optimization ($0) dengan memanfaatkan free tier

2. Architecture Overview

2.1. High-Level System Architecture

Sistem terdiri dari tiga node utama yang berkomunikasi secara asinkron:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        SYSTEM ARCHITECTURE                         β”‚
β”‚                                                                     β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚   β”‚ IoT Node │───────→│  Data Node   │───────→│   Model Node     β”‚  β”‚
β”‚   β”‚ (Sensor  β”‚  PPG   β”‚ (ETL #1)     β”‚ Queue  β”‚   (ETL #2)       β”‚  β”‚
β”‚   β”‚  + HP)   β”‚ Signal β”‚              β”‚        β”‚                  β”‚  β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜        β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚        β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚  β”‚
β”‚                       β”‚  β”‚FastAPI β”‚  β”‚        β”‚  β”‚ GAN        β”‚  β”‚  β”‚
β”‚                       β”‚  β”‚+ ETL   β”‚  β”‚        β”‚  β”‚ + VGTL-Net β”‚  β”‚  β”‚
β”‚                       β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚        β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚  β”‚
β”‚                       β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜        β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                              β”‚                         β”‚            β”‚
β”‚                              β–Ό                         β–Ό            β”‚
β”‚                       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”          β”‚
β”‚                       β”‚          Database                β”‚          β”‚
β”‚                       β”‚    (Raw PPG + Predictions)       β”‚          β”‚
β”‚                       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜          β”‚
β”‚                              β–²                                      β”‚
β”‚                              β”‚                                      β”‚
β”‚                       β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”                              β”‚
β”‚                       β”‚ Application  β”‚                              β”‚
β”‚                       β”‚    Node      β”‚                              β”‚
β”‚                       β”‚ (Frontend +  β”‚                              β”‚
β”‚                       β”‚  Backend)    β”‚                              β”‚
β”‚                       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

2.2. Clean Architecture Layers

Seluruh codebase diorganisasi ke dalam empat layer konsentris sesuai prinsip Clean Architecture oleh Robert C. Martin:

    ╔═══════════════════════════════════════════════════════╗
    β•‘                                                       β•‘
    β•‘    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β•‘
    β•‘    β”‚           INTERFACE LAYER                  β”‚      β•‘
    β•‘    β”‚     (FastAPI Routes, CLI, Consumer)        β”‚      β•‘
    β•‘    β”‚                                           β”‚      β•‘
    β•‘    β”‚    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚      β•‘
    β•‘    β”‚    β”‚     INFRASTRUCTURE LAYER          β”‚   β”‚      β•‘
    β•‘    β”‚    β”‚  (PostgreSQL, RabbitMQ, SciPy,    β”‚   β”‚      β•‘
    β•‘    β”‚    β”‚   Model Service Implementations)  β”‚   β”‚      β•‘
    β•‘    β”‚    β”‚                                   β”‚   β”‚      β•‘
    β•‘    β”‚    β”‚    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚   β”‚      β•‘
    β•‘    β”‚    β”‚    β”‚   APPLICATION LAYER       β”‚   β”‚   β”‚      β•‘
    β•‘    β”‚    β”‚    β”‚  (Use Cases, DTOs)        β”‚   β”‚   β”‚      β•‘
    β•‘    β”‚    β”‚    β”‚                           β”‚   β”‚   β”‚      β•‘
    β•‘    β”‚    β”‚    β”‚    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚   β”‚   β”‚      β•‘
    β•‘    β”‚    β”‚    β”‚    β”‚  DOMAIN LAYER   β”‚    β”‚   β”‚   β”‚      β•‘
    β•‘    β”‚    β”‚    β”‚    β”‚  (Entities,     β”‚    β”‚   β”‚   β”‚      β•‘
    β•‘    β”‚    β”‚    β”‚    β”‚   Interfaces,   β”‚    β”‚   β”‚   β”‚      β•‘
    β•‘    β”‚    β”‚    β”‚    β”‚   Value Objects)β”‚    β”‚   β”‚   β”‚      β•‘
    β•‘    β”‚    β”‚    β”‚    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚   β”‚   β”‚      β•‘
    β•‘    β”‚    β”‚    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚   β”‚      β•‘
    β•‘    β”‚    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚      β•‘
    β•‘    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β•‘
    β•‘                                                       β•‘
    β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•

2.3. Dependency Rule

"Source code dependencies harus selalu mengarah KE DALAM (ke arah Domain Layer)."
β€” Robert C. Martin, Clean Architecture (2017)

Interface ──depends on──→ Application ──depends on──→ Domain
                                                        β–²
Infrastructure ──────────────implementsβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Implikasi penting:

  • Domain Layer tidak mengetahui keberadaan PostgreSQL, RabbitMQ, FastAPI, atau framework apapun.
  • Application Layer (Use Cases) bergantung pada interfaces yang didefinisikan di Domain, bukan pada implementasi konkret.
  • Infrastructure Layer mengimplementasikan interfaces Domain, sehingga bisa di-swap tanpa mengubah business logic.
  • Interface Layer bertindak sebagai entry point β€” hanya melakukan wiring/composition.

3. Layer-by-Layer Breakdown

3.1. Domain Layer

Lokasi: src/domain/

Domain Layer adalah inti dari sistem β€” berisi business rules murni yang tidak bergantung pada teknologi apapun. Layer ini harus bisa berjalan tanpa framework, tanpa database, tanpa network.

3.1.1. Entities

Entity merepresentasikan objek bisnis utama dengan identitas dan lifecycle.

Entity File Deskripsi Key Properties
PPGSignal entities/ppg_signal.py Representasi sinyal PPG yang masuk dari sensor device_id, user_id, timestamp, sampling_rate, ppg_values, duration_seconds
BPPrediction entities/prediction.py Hasil prediksi tekanan darah dari model AI predicted_sbp, predicted_dbp, model_version, inference_time_ms

Karakteristik Entity:

  • Menggunakan @dataclass murni Python β€” bukan SQLAlchemy model, bukan Pydantic model.
  • Berisi domain validation (validate()) yang merepresentasikan business rules.
  • Berisi computed properties (e.g., num_samples, mean_arterial_pressure).

3.1.2. Value Objects

Value Object adalah objek immutable yang didefinisikan oleh atributnya, bukan identitasnya.

Value Object File Deskripsi
DeviceInfo value_objects/device_info.py Informasi perangkat sensor IoT
SignalMetadata value_objects/signal_metadata.py Metadata sinyal (sampling rate, durasi, jumlah sampel)

3.1.3. Interfaces (Contracts)

Interfaces mendefinisikan kontrak yang harus dipenuhi oleh Infrastructure Layer. Menggunakan Abstract Base Class (ABC).

Interface File Kontrak
BaseRepository[T] interfaces/repositories/base_repository.py Generic CRUD: add(), get_by_id(), get_all(), delete()
PPGRepository interfaces/repositories/ppg_repository.py Extends BaseRepository[PPGSignal] + get_by_user(), get_by_device()
PredictionRepository interfaces/repositories/prediction_repository.py Extends BaseRepository[BPPrediction] + query spesifik prediksi
MessageBroker interfaces/services/message_broker.py publish(), consume(), connect(), disconnect()
SignalProcessor interfaces/services/signal_processor.py filter_signal(), normalize(), segment(), process()
ModelService interfaces/services/model_service.py load_model(), predict()

πŸ“Œ Catatan Penting: Interface MessageBroker tidak menyebut "RabbitMQ" dimanapun. Jika di kemudian hari ingin berpindah ke Apache Kafka atau Redis Streams, cukup buat implementasi baru tanpa mengubah satu baris pun di Domain atau Application Layer.

3.1.4. Domain Exceptions

DomainException (base)
β”œβ”€β”€ InvalidSignalError
β”œβ”€β”€ PredictionOutOfRangeError
└── EntityNotFoundError

3.2. Application Layer

Lokasi: src/application/

Application Layer berisi use cases β€” orkestrasi langkah-langkah business logic untuk memenuhi satu kebutuhan pengguna yang spesifik.

3.2.1. Use Cases

Use Case File Deskripsi Input β†’ Output
IngestPPGUseCase use_cases/ingest_ppg.py ETL #1: Terima PPG β†’ Store β†’ Publish PPGIngestRequest β†’ PPGIngestResponse
ProcessAndPredictUseCase use_cases/process_and_predict.py ETL #2: Consume β†’ Preprocess β†’ Predict β†’ Store dict (message) β†’ BPPrediction
GetPredictionHistoryUseCase use_cases/get_prediction_history.py Query riwayat prediksi per user user_id, date_range β†’ list[BPPrediction]

Prinsip Use Case:

  • Setiap use case memiliki satu method publik: execute().
  • Dependencies di-inject melalui constructor (Dependency Inversion).
  • Use case tidak mengetahui dari mana dia dipanggil (API? CLI? Consumer?).
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                     IngestPPGUseCase                         β”‚
β”‚                                                              β”‚
β”‚  __init__(ppg_repo: PPGRepository, broker: MessageBroker)    β”‚
β”‚                  β–²                        β–²                  β”‚
β”‚                  β”‚ interface               β”‚ interface        β”‚
β”‚                  β”‚                        β”‚                  β”‚
β”‚  execute(request: PPGIngestRequest) β†’ PPGIngestResponse      β”‚
β”‚      1. Create PPGSignal entity                              β”‚
β”‚      2. entity.validate()                                    β”‚
β”‚      3. ppg_repo.add(entity)                                 β”‚
β”‚      4. broker.publish("ppg_queue", message)                 β”‚
β”‚      5. Return response DTO                                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

3.2.2. Data Transfer Objects (DTOs)

DTO digunakan untuk transfer data antar layer boundary. Menggunakan Pydantic untuk validasi otomatis.

DTO Tipe Deskripsi
PPGIngestRequest Input Data yang diterima dari HP via API
PPGIngestResponse Output Response setelah ingest berhasil
PredictionResponse Output Hasil prediksi untuk ditampilkan ke frontend

Kenapa bukan Entity langsung?
Entity adalah representasi domain murni. DTO adalah representasi "bentuk data" yang masuk/keluar dari sistem. Memisahkan keduanya mencegah domain entity terkontaminasi oleh kebutuhan serialization/validation framework.


3.3. Infrastructure Layer

Lokasi: src/infrastructure/

Infrastructure Layer berisi implementasi konkret dari interfaces yang didefinisikan di Domain Layer. Layer ini berhubungan langsung dengan teknologi pihak ketiga.

3.3.1. Database

Komponen File Deskripsi
connection.py database/connection.py SQLAlchemy async engine + session factory
Base database/models/base.py Declarative base dengan id dan created_at otomatis
PPGModel database/models/ppg_model.py ORM model untuk tabel raw_ppg
PredictionModel database/models/prediction_model.py ORM model untuk tabel predictions
SQLAlchemyBaseRepository database/repositories/sqlalchemy_base.py Generic CRUD implementation (DRY)
SQLAlchemyPPGRepository database/repositories/ppg_repository.py Implementasi PPGRepository
SQLAlchemyPredictionRepository database/repositories/prediction_repository.py Implementasi PredictionRepository

Mapping Pattern:

Domain Entity (PPGSignal)     ←─── _to_entity() ───    ORM Model (PPGModel)
                              ─── _to_model()   ───→

Setiap repository konkret wajib mengimplementasikan dua method mapping:

  • _to_entity(model) β†’ entity β€” Mengkonversi ORM model ke domain entity.
  • _to_model(entity) β†’ model β€” Mengkonversi domain entity ke ORM model.

3.3.2. Messaging

Komponen File Deskripsi
RabbitMQBroker messaging/rabbitmq_broker.py Implementasi MessageBroker menggunakan aio-pika

Mendukung koneksi AMQP (lokal) dan AMQPS (CloudAMQP β€” SSL) melalui konfigurasi URL.

3.3.3. Signal Processing

Komponen File Deskripsi
ScipySignalProcessor processing/scipy_signal_processor.py Implementasi SignalProcessor menggunakan SciPy

Pipeline pemrosesan sinyal:

Raw PPG Signal
     β”‚
     β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Bandpass Filter │────→│   Normalization  │────→│   Segmentation  β”‚
β”‚  (0.5 – 8.0 Hz) β”‚     β”‚   (Z-score)      β”‚     β”‚  (8s windows)   β”‚
β”‚  Butterworth 4th β”‚     β”‚                  β”‚     β”‚                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                        β”‚
                                                        β–Ό
                                                  Processed Segments
                                                  shape: (N, window_size)

3.3.4. Model Service

Komponen File Deskripsi
MockModelService model/mock_model_service.py Mock implementation untuk testing tanpa model asli
GANVGTLNetService model/gan_vgtlnet_service.py Implementasi production: GAN + VGTL-Net inference

3.4. Interface Layer

Lokasi: src/interface/

Interface Layer adalah entry point ke sistem. Layer ini bertanggung jawab atas:

  • Menerima input dari dunia luar (HTTP request, message queue, CLI command).
  • Melakukan dependency wiring (composition root).
  • Memanggil use case yang sesuai.
  • Mengembalikan output dalam format yang diharapkan.

3.4.1. API (Entry Point 1 β€” HF Spaces)

Komponen File Deskripsi
create_app() api/app.py FastAPI application factory
dependencies.py api/dependencies.py Dependency injection wiring menggunakan Depends()
ppg_routes.py api/routes/ppg_routes.py REST endpoint untuk ingest PPG
prediction_routes.py api/routes/prediction_routes.py REST endpoint untuk query predictions

3.4.2. Consumer (Entry Point 2 β€” Kaggle)

Komponen File Deskripsi
run_consumer.py consumer/run_consumer.py Standalone consumer service
colab_notebook.ipynb consumer/colab_notebook.ipynb Jupyter notebook untuk menjalankan consumer di Colab

πŸ“Œ Kedua entry point menggunakan use case, repository, dan interface yang PERSIS SAMA. Perbedaannya hanya pada cara bootstrapping dan dependency wiring.


3.5. Shared Module

Lokasi: src/shared/

Cross-cutting concerns yang digunakan oleh seluruh layer.

Komponen File Deskripsi
Settings config.py Konfigurasi aplikasi dari environment variables (Pydantic Settings)
get_logger() logger.py Logging factory dengan format konsisten
constants.py constants.py Named constants (menghilangkan magic numbers)

4. Design Principles

4.1. SOLID Principles

S β€” Single Responsibility Principle

"Sebuah class harus memiliki satu, dan hanya satu, alasan untuk berubah."

Komponen Responsibility Tunggal
PPGSignal Merepresentasikan sinyal PPG dan validasi domain-nya
IngestPPGUseCase Mengorkestrasikan alur ingest data PPG
ScipySignalProcessor Memproses sinyal menggunakan SciPy
SQLAlchemyPPGRepository Mempersist PPGSignal ke PostgreSQL
RabbitMQBroker Mengirim/menerima pesan via RabbitMQ
ppg_routes.py Menangani HTTP routing untuk endpoint PPG

O β€” Open/Closed Principle

"Entitas software harus terbuka untuk ekstensi, tertutup untuk modifikasi."

Skenario Solusi (Tanpa Modifikasi)
Ganti PostgreSQL β†’ MongoDB Buat MongoDBPPGRepository yang implement PPGRepository. Use case tidak berubah.
Ganti RabbitMQ β†’ Kafka Buat KafkaBroker yang implement MessageBroker. Use case tidak berubah.
Ganti SciPy β†’ PyTorch preprocessing Buat TorchSignalProcessor yang implement SignalProcessor. Use case tidak berubah.
Tambah model baru selain GAN+VGTL-Net Buat NewModelService yang implement ModelService. Use case tidak berubah.

L β€” Liskov Substitution Principle

"Objek dari superclass harus bisa digantikan oleh objek subclass tanpa merusak program."

# Keduanya bisa digunakan di mana pun PPGRepository dibutuhkan
repo: PPGRepository = SQLAlchemyPPGRepository(session)   # βœ… Production
repo: PPGRepository = InMemoryPPGRepository()             # βœ… Testing

# Keduanya bisa digunakan di mana pun MessageBroker dibutuhkan
broker: MessageBroker = RabbitMQBroker()                  # βœ… Production
broker: MessageBroker = InMemoryBroker()                  # βœ… Testing

I β€” Interface Segregation Principle

"Client tidak boleh dipaksa bergantung pada interface yang tidak mereka gunakan."

                    β”Œβ”€β”€β”€β”€ PPGRepository ────┐
                    β”‚  get_by_user()        β”‚
BaseRepository[T]   β”‚  get_by_device()      β”‚
  add()             β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  get_by_id()
  get_all()         β”Œβ”€β”€ PredictionRepository ──┐
  delete()          β”‚  get_by_user_latest()     β”‚
                    β”‚  get_by_date_range()      β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  • IngestPPGUseCase hanya bergantung pada PPGRepository dan MessageBroker β€” bukan pada PredictionRepository atau SignalProcessor.
  • ProcessAndPredictUseCase bergantung pada PPGRepository, PredictionRepository, SignalProcessor, dan ModelService β€” masing-masing interface kecil dan fokus.

D β€” Dependency Inversion Principle

"Module high-level tidak boleh bergantung pada module low-level. Keduanya harus bergantung pada abstraksi."

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Use Case        β”‚       β”‚   Interface (ABC)     β”‚
β”‚ (High-Level)      │──────→│  PPGRepository        β”‚
β”‚                   β”‚       β”‚  MessageBroker        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                      β”‚
                                      β”‚ implements
                                      β”‚
                           β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                           β”‚   Concrete Class      β”‚
                           β”‚ (Low-Level)           β”‚
                           β”‚  SQLAlchemyPPGRepo    β”‚
                           β”‚  RabbitMQBroker       β”‚
                           β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Use case menerima dependency melalui constructor injection:

class IngestPPGUseCase:
    def __init__(
        self,
        ppg_repo: PPGRepository,        # ← interface, bukan SQLAlchemyPPGRepository
        broker: MessageBroker,           # ← interface, bukan RabbitMQBroker
    ):
        self._ppg_repo = ppg_repo
        self._broker = broker

4.2. DRY (Don't Repeat Yourself)

Penerapan Lokasi Sebelum (Redundant) Sesudah (DRY)
Generic CRUD SQLAlchemyBaseRepository Setiap repository menulis add(), get_by_id(), delete() sendiri-sendiri Tulis sekali di base class, semua repo inherit
ORM Base Model database/models/base.py Setiap ORM model mendefinisikan id dan created_at Definisi di Base, semua model inherit
Magic Numbers shared/constants.py 0.5 dan 8.0 tersebar di banyak file PPG_BANDPASS_LOW = 0.5 didefinisikan sekali
Signal Processing Pipeline SignalProcessor.process() Urutan filter β†’ normalize β†’ segment ditulis ulang di setiap pemanggil Template Method di base class: process() memanggil tiga langkah secara berurutan
Logger Creation shared/logger.py logging.getLogger() + handler setup di setiap file get_logger(__name__) β€” factory function

5. Design Patterns

Pattern Lokasi Penggunaan
Repository Pattern domain/interfaces/repositories/ Abstraksi akses data, memisahkan domain dari persistence layer
Factory Pattern interface/api/app.py β†’ create_app() Membuat instance FastAPI application dengan konfigurasi yang konsisten
Dependency Injection interface/api/dependencies.py Wiring dependencies menggunakan FastAPI Depends()
Template Method SignalProcessor.process() Mendefinisikan skeleton algoritma; subclass override langkah-langkah spesifik
Data Transfer Object (DTO) application/dto/ Transfer data antar layer boundary tanpa mengekspos domain entity
Data Mapper _to_entity() / _to_model() Mapping antara domain entity dan ORM model
Observer (Pub/Sub) MessageBroker + RabbitMQ Publisher (ETL #1) dan Consumer (ETL #2) loosely coupled melalui message queue
Strategy Pattern SignalProcessor, ModelService Algoritma preprocessing dan model inference dapat di-swap melalui interface
Singleton _broker di dependencies.py Satu instance broker di-share ke seluruh request

6. Data Flow & ETL Pipeline

6.1. ETL #1 β€” Data Ingestion

Dijalankan di: πŸ€— Hugging Face Spaces
Trigger: HTTP POST request dari mobile app

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Mobile  β”‚      β”‚              ETL #1 (HF Spaces)                β”‚
β”‚   App    β”‚      β”‚                                                β”‚
β”‚  (HP)    │─────→│  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚          β”‚ POST β”‚  β”‚  EXTRACT  β”‚β†’ β”‚  TRANSFORM   β”‚β†’ β”‚  LOAD  β”‚  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β”‚  β”‚           β”‚  β”‚              β”‚  β”‚        β”‚  β”‚
                 β”‚  β”‚ Parse     β”‚  β”‚ Create       β”‚  β”‚ β”Œβ”€β”€β”€β”€β” β”‚  β”‚
                 β”‚  β”‚ JSON body β”‚  β”‚ PPGSignal    β”‚  β”‚ β”‚ DB β”‚ β”‚  β”‚
                 β”‚  β”‚ Validate  β”‚  β”‚ entity       β”‚  β”‚ β””β”€β”€β”€β”€β”˜ β”‚  β”‚
                 β”‚  β”‚ DTO       β”‚  β”‚ domain       β”‚  β”‚ β”Œβ”€β”€β”€β”€β” β”‚  β”‚
                 β”‚  β”‚           β”‚  β”‚ validation   β”‚  β”‚ β”‚ MQ β”‚ β”‚  β”‚
                 β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚ β””β”€β”€β”€β”€β”˜ β”‚  β”‚
                 β”‚                                   β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
                 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Tahap Aksi Output
Extract Parse JSON request body, validasi melalui Pydantic DTO PPGIngestRequest object
Transform Buat PPGSignal entity, jalankan entity.validate() Validated PPGSignal entity
Load ppg_repo.add() β†’ Supabase; broker.publish() β†’ CloudAMQP Stored record + queued message

6.2. ETL #2 β€” Processing & Inference

Dijalankan di: πŸ§ͺ Kaggle (GPU)
Trigger: Message baru di RabbitMQ queue

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ CloudAMQP β”‚      β”‚              ETL #2 (Kaggle)                  β”‚
β”‚  (Queue)  β”‚      β”‚                                                     β”‚
β”‚           │─────→│  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚           β”‚ msg  β”‚  β”‚  EXTRACT  β”‚β†’ β”‚  TRANSFORM   β”‚β†’ β”‚     LOAD     β”‚  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β”‚  β”‚           β”‚  β”‚              β”‚  β”‚              β”‚  β”‚
                   β”‚  β”‚ Consume   β”‚  β”‚ Bandpass     β”‚  β”‚ GAN predict  β”‚  β”‚
                   β”‚  β”‚ message   β”‚  β”‚ filter       β”‚  β”‚ VGTL-Net     β”‚  β”‚
                   β”‚  β”‚ Fetch PPG β”‚  β”‚ Normalize    β”‚  β”‚ predict      β”‚  β”‚
                   β”‚  β”‚ from DB   β”‚  β”‚ Segment      β”‚  β”‚ Store to DB  β”‚  β”‚
                   β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
                   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Tahap Aksi Output
Extract Consume message dari queue, fetch full PPG signal dari database PPGSignal entity
Transform Bandpass filter β†’ Z-score normalization β†’ 8-second segmentation np.ndarray shape (N, window_size)
Load GAN inference β†’ VGTL-Net inference β†’ prediction_repo.add() BPPrediction stored in database

6.3. End-to-End Data Flow

πŸ“± HP                 πŸ€— HF Spaces           🐰 CloudAMQP        πŸ§ͺ Kaggle        ☁️ Supabase
 β”‚                        β”‚                       β”‚                     β”‚                    β”‚
 β”‚  POST /ppg/ingest      β”‚                       β”‚                     β”‚                    β”‚
 β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β†’β”‚                       β”‚                     β”‚                    β”‚
 β”‚                        β”‚                       β”‚                     β”‚                    β”‚
 β”‚                        │── Store raw PPG ──────────────────────────────────────────────→│
 β”‚                        β”‚                       β”‚                     β”‚                    β”‚
 β”‚                        │── Publish message ───→│                     β”‚                    β”‚
 β”‚                        β”‚                       β”‚                     β”‚                    β”‚
 β”‚  ← 200 OK (response)  β”‚                       β”‚                     β”‚                    β”‚
 │←───────────────────────│                       β”‚                     β”‚                    β”‚
 β”‚                        β”‚                       β”‚                     β”‚                    β”‚
 β”‚                        β”‚                       │── Consume ─────────→│                    β”‚
 β”‚                        β”‚                       β”‚                     β”‚                    β”‚
 β”‚                        β”‚                       β”‚                     │── Fetch raw PPG ──→│
 β”‚                        β”‚                       β”‚                     │←── PPG data ───────│
 β”‚                        β”‚                       β”‚                     β”‚                    β”‚
 β”‚                        β”‚                       β”‚                     β”‚  [ETL #2]          β”‚
 β”‚                        β”‚                       β”‚                     β”‚  Filter β†’ Norm     β”‚
 β”‚                        β”‚                       β”‚                     β”‚  β†’ Segment         β”‚
 β”‚                        β”‚                       β”‚                     β”‚                    β”‚
 β”‚                        β”‚                       β”‚                     β”‚  [Model]           β”‚
 β”‚                        β”‚                       β”‚                     β”‚  GAN β†’ VGTL-Net    β”‚
 β”‚                        β”‚                       β”‚                     β”‚                    β”‚
 β”‚                        β”‚                       β”‚                     │── Store predictionβ†’β”‚
 β”‚                        β”‚                       β”‚                     β”‚                    β”‚

7. Project Structure

bp-monitoring-pipeline/
β”‚
β”œβ”€β”€ README.md                                 # Project overview
β”œβ”€β”€ ARCHITECTURE.md                           # β¬… Dokumen ini
β”œβ”€β”€ docker-compose.yml                        # Local development stack
β”œβ”€β”€ docker-compose.prod.yml                   # Production stack
β”œβ”€β”€ Dockerfile                                # HF Spaces deployment
β”œβ”€β”€ pyproject.toml                            # Project metadata & dependencies
β”œβ”€β”€ alembic.ini                               # Database migration config
β”œβ”€β”€ .env.example                              # Environment variables template
β”‚
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ __init__.py
β”‚   β”‚
β”‚   β”œβ”€β”€ domain/                               # 🟒 LAYER 1: Domain (Innermost)
β”‚   β”‚   β”œβ”€β”€ __init__.py                       #
β”‚   β”‚   β”œβ”€β”€ entities/                         # Core business objects
β”‚   β”‚   β”‚   β”œβ”€β”€ __init__.py                   #
β”‚   β”‚   β”‚   β”œβ”€β”€ ppg_signal.py                 #   PPG signal entity
β”‚   β”‚   β”‚   └── prediction.py                 #   Blood pressure prediction entity
β”‚   β”‚   β”œβ”€β”€ value_objects/                    # Immutable value types
β”‚   β”‚   β”‚   β”œβ”€β”€ __init__.py                   #
β”‚   β”‚   β”‚   β”œβ”€β”€ device_info.py                #   IoT device information
β”‚   β”‚   β”‚   └── signal_metadata.py            #   Signal metadata (rate, duration)
β”‚   β”‚   β”œβ”€β”€ interfaces/                       # Abstract contracts (ABC)
β”‚   β”‚   β”‚   β”œβ”€β”€ __init__.py                   #
β”‚   β”‚   β”‚   β”œβ”€β”€ repositories/                 #   Data persistence contracts
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ __init__.py               #
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ base_repository.py        #     Generic CRUD interface
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ ppg_repository.py         #     PPG-specific queries
β”‚   β”‚   β”‚   β”‚   └── prediction_repository.py  #     Prediction-specific queries
β”‚   β”‚   β”‚   └── services/                     #   External service contracts
β”‚   β”‚   β”‚       β”œβ”€β”€ __init__.py               #
β”‚   β”‚   β”‚       β”œβ”€β”€ message_broker.py         #     Pub/Sub messaging
β”‚   β”‚   β”‚       β”œβ”€β”€ signal_processor.py       #     Signal preprocessing
β”‚   β”‚   β”‚       └── model_service.py          #     AI model inference
β”‚   β”‚   └── exceptions/                       # Domain-specific errors
β”‚   β”‚       β”œβ”€β”€ __init__.py                   #
β”‚   β”‚       └── domain_exceptions.py          #   InvalidSignalError, etc.
β”‚   β”‚
β”‚   β”œβ”€β”€ application/                          # πŸ”΅ LAYER 2: Application
β”‚   β”‚   β”œβ”€β”€ __init__.py                       #
β”‚   β”‚   β”œβ”€β”€ use_cases/                        # Business use case orchestrators
β”‚   β”‚   β”‚   β”œβ”€β”€ __init__.py                   #
β”‚   β”‚   β”‚   β”œβ”€β”€ ingest_ppg.py                 #   ETL #1: Ingest from mobile
β”‚   β”‚   β”‚   β”œβ”€β”€ process_and_predict.py        #   ETL #2: Process + AI predict
β”‚   β”‚   β”‚   └── get_prediction_history.py     #   Query historical predictions
β”‚   β”‚   └── dto/                              # Data Transfer Objects
β”‚   β”‚       β”œβ”€β”€ __init__.py                   #
β”‚   β”‚       β”œβ”€β”€ ppg_dto.py                    #   Request/Response for PPG
β”‚   β”‚       └── prediction_dto.py             #   Request/Response for predictions
β”‚   β”‚
β”‚   β”œβ”€β”€ infrastructure/                       # 🟠 LAYER 3: Infrastructure
β”‚   β”‚   β”œβ”€β”€ __init__.py                       #
β”‚   β”‚   β”œβ”€β”€ database/                         # PostgreSQL implementation
β”‚   β”‚   β”‚   β”œβ”€β”€ __init__.py                   #
β”‚   β”‚   β”‚   β”œβ”€β”€ connection.py                 #   Engine & session factory
β”‚   β”‚   β”‚   β”œβ”€β”€ models/                       #   SQLAlchemy ORM models
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ __init__.py               #
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ base.py                   #     Shared base (id, created_at)
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ ppg_model.py              #     raw_ppg table
β”‚   β”‚   β”‚   β”‚   └── prediction_model.py       #     predictions table
β”‚   β”‚   β”‚   └── repositories/                 #   Concrete repository implementations
β”‚   β”‚   β”‚       β”œβ”€β”€ __init__.py               #
β”‚   β”‚   β”‚       β”œβ”€β”€ sqlalchemy_base.py        #     Generic CRUD impl (DRY)
β”‚   β”‚   β”‚       β”œβ”€β”€ ppg_repository.py         #     PPGRepository impl
β”‚   β”‚   β”‚       └── prediction_repository.py  #     PredictionRepository impl
β”‚   β”‚   β”œβ”€β”€ messaging/                        # RabbitMQ implementation
β”‚   β”‚   β”‚   β”œβ”€β”€ __init__.py                   #
β”‚   β”‚   β”‚   └── rabbitmq_broker.py            #   MessageBroker impl
β”‚   β”‚   β”œβ”€β”€ processing/                       # Signal processing implementation
β”‚   β”‚   β”‚   β”œβ”€β”€ __init__.py                   #
β”‚   β”‚   β”‚   └── scipy_signal_processor.py     #   SignalProcessor impl (SciPy)
β”‚   β”‚   └── model/                            # AI model implementation
β”‚   β”‚       β”œβ”€β”€ __init__.py                   #
β”‚   β”‚       β”œβ”€β”€ mock_model_service.py         #   Mock for testing
β”‚   β”‚       └── gan_vgtlnet_service.py        #   Production GAN + VGTL-Net
β”‚   β”‚
β”‚   β”œβ”€β”€ interface/                            # πŸ”΄ LAYER 4: Interface (Outermost)
β”‚   β”‚   β”œβ”€β”€ __init__.py                       #
β”‚   β”‚   β”œβ”€β”€ api/                              # Entry Point 1: REST API (HF Spaces)
β”‚   β”‚   β”‚   β”œβ”€β”€ __init__.py                   #
β”‚   β”‚   β”‚   β”œβ”€β”€ app.py                        #   FastAPI application factory
β”‚   β”‚   β”‚   β”œβ”€β”€ dependencies.py               #   Dependency injection wiring
β”‚   β”‚   β”‚   └── routes/                       #   HTTP route handlers
β”‚   β”‚   β”‚       β”œβ”€β”€ __init__.py               #
β”‚   β”‚   β”‚       β”œβ”€β”€ ppg_routes.py             #     POST /api/v1/ppg/ingest
β”‚   β”‚   β”‚       └── prediction_routes.py      #     GET  /api/v1/predictions
β”‚   β”‚   └── consumer/                         # Entry Point 2: MQ Consumer (Colab)
β”‚   β”‚       β”œβ”€β”€ __init__.py                   #
β”‚   β”‚       β”œβ”€β”€ run_consumer.py               #   Standalone async consumer
β”‚   β”‚       └── colab_notebook.ipynb          #   Jupyter notebook for Colab
β”‚   β”‚
β”‚   └── shared/                               # 🟣 Cross-cutting Concerns
β”‚       β”œβ”€β”€ __init__.py                       #
β”‚       β”œβ”€β”€ config.py                         #   Settings from .env (Pydantic)
β”‚       β”œβ”€β”€ logger.py                         #   Logging factory
β”‚       └── constants.py                      #   Named constants (no magic numbers)
β”‚
β”œβ”€β”€ tests/                                    # Test suite
β”‚   β”œβ”€β”€ __init__.py                           #
β”‚   β”œβ”€β”€ unit/                                 # Unit tests (no external deps)
β”‚   β”‚   β”œβ”€β”€ test_entities.py                  #   Domain entity tests
β”‚   β”‚   β”œβ”€β”€ test_use_cases.py                 #   Use case tests (mocked deps)
β”‚   β”‚   └── test_signal_processor.py          #   Signal processing tests
β”‚   └── integration/                          # Integration tests
β”‚       β”œβ”€β”€ test_api.py                       #   API endpoint tests
β”‚       └── test_rabbitmq.py                  #   Message broker tests
β”‚
β”œβ”€β”€ migrations/                               # Alembic database migrations
β”‚   β”œβ”€β”€ env.py                                #
β”‚   └── versions/                             #
β”‚
└── scripts/                                  # Utility scripts
    β”œβ”€β”€ mock_iot_sender.py                    #   Simulate IoT data
    └── seed_database.py                      #   Seed initial data

8. Deployment Architecture

8.1. Deployment Topology

                        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                        β”‚         GitHub Repository         β”‚
                        β”‚     bp-monitoring-pipeline        β”‚
                        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                    β”‚          β”‚
                          git push  β”‚          β”‚  git clone
                          (subset)  β”‚          β”‚  (full repo)
                                    β”‚          β”‚
                 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”  β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                 β”‚  πŸ€— Hugging Face     β”‚  β”‚  πŸ§ͺ Kaggle       β”‚
                 β”‚     Spaces           β”‚  β”‚     (GPU: T4)          β”‚
                 β”‚                      β”‚  β”‚                        β”‚
                 β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
                 β”‚  β”‚   Docker       β”‚  β”‚  β”‚  β”‚  run_consumer.py β”‚  β”‚
                 β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚  β”‚  β”‚  β”‚                  β”‚  β”‚
                 β”‚  β”‚  β”‚ FastAPI  β”‚  β”‚  β”‚  β”‚  β”‚  ETL #2          β”‚  β”‚
                 β”‚  β”‚  β”‚ ETL #1   β”‚  β”‚  β”‚  β”‚  β”‚  + GAN           β”‚  β”‚
                 β”‚  β”‚  β”‚ port 7860β”‚  β”‚  β”‚  β”‚  β”‚  + VGTL-Net      β”‚  β”‚
                 β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚  β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
                 β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                 β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜          β”‚        β”‚
                         β”‚    β”‚                    β”‚        β”‚
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”  β”Œβ–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”  β”Œβ”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”
              β”‚ ☁️Supabase β”‚  β”‚πŸ°CloudAMQPβ”‚  β”‚β˜οΈSupa- β”‚  β”‚πŸ°Cloud- β”‚
              β”‚ PostgreSQLβ”‚  β”‚ RabbitMQ   β”‚  β”‚  base  β”‚  β”‚  AMQP   β”‚
              β”‚ (Store)   β”‚  β”‚ (Publish)  β”‚  β”‚ (R/W)  β”‚  β”‚(Consume)β”‚
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

8.2. Technology Stack

Layer Teknologi Versi Justifikasi
Runtime Python 3.11+ Async support, type hints, ecosystem ML matang
Web Framework FastAPI β‰₯ 0.110 Async-native, auto-docs (Swagger), Pydantic integration
ORM SQLAlchemy β‰₯ 2.0 Async support, mature, database-agnostic
Database Driver asyncpg β‰₯ 0.29 Fastest Python PostgreSQL async driver
Database PostgreSQL (Supabase) 15 JSONB support, reliability, free tier 500MB
Message Broker RabbitMQ (CloudAMQP) 3.x AMQP protocol, persistent messages, free tier 1M msg/month
Message Client aio-pika β‰₯ 9.4 Async RabbitMQ client, SSL support
Signal Processing SciPy β‰₯ 1.12 Industry-standard scientific computing
Deep Learning PyTorch β‰₯ 2.0 GPU inference, GAN + VGTL-Net compatibility
Validation Pydantic β‰₯ 2.0 DTO validation, settings management
Containerization Docker β€” Reproducible deployments
Hosting (API) Hugging Face Spaces Free Docker SDK, 2 vCPU, 16GB RAM
Hosting (GPU) Kaggle Free T4 GPU, 15GB VRAM

8.3. Entry Points

# Entry Point Platform Command Fungsi
1 FastAPI Server HF Spaces uvicorn src.interface.api.app:create_app Terima PPG dari HP, store, publish
2 MQ Consumer Kaggle python -m src.interface.consumer.run_consumer Consume, preprocess, predict, store

πŸ“Œ Kedua entry point berbagi ~85% codebase yang sama. Yang berbeda hanyalah bootstrapping dan dependency wiring.


9. Configuration Management

Seluruh konfigurasi dikelola melalui environment variables menggunakan Pydantic Settings. Tidak ada credentials yang di-hardcode.

Environment Variables

Variable Deskripsi Contoh Wajib
DATABASE_URL PostgreSQL connection string (async) postgresql+asyncpg://user:pass@host:6543/db βœ…
RABBITMQ_URL RabbitMQ/CloudAMQP connection string amqps://user:pass@host/vhost βœ…
APP_PORT Port untuk FastAPI (default: 7860 untuk HF) 7860 ❌
APP_HOST Host binding (default: 0.0.0.0) 0.0.0.0 ❌
DEBUG Enable debug mode false ❌
LOG_LEVEL Logging level INFO ❌

Secrets Management per Platform

Platform Metode Lokasi
HF Spaces Space Secrets Settings β†’ Variables and Secrets
Kaggle Colab Secrets πŸ”‘ Sidebar β†’ Secrets
Local Development .env file Root project directory

10. Testing Strategy

Testing Pyramid

         β•±β•²
        β•±  β•²          E2E Tests
       β•±    β•²         (curl β†’ HF Spaces β†’ Supabase β†’ Colab)
      ╱──────╲
     β•±        β•²       Integration Tests
    β•±          β•²      (API + real DB, Consumer + real Queue)
   ╱────────────╲
  β•±              β•²    Unit Tests
 β•±                β•²   (Entities, Use Cases, Processors β€” mocked deps)
╱══════════════════╲

Test Categories

Kategori Scope Dependencies Tools
Unit Domain entities, value objects Tidak ada pytest
Unit Use cases Mocked repositories & services pytest, unittest.mock
Unit Signal processor Tidak ada (pure NumPy/SciPy) pytest, numpy.testing
Integration API endpoints Test database (SQLite/PostgreSQL) pytest, httpx.AsyncClient
Integration Message broker Test RabbitMQ (Docker) pytest, aio-pika
E2E Full pipeline All services running curl, pytest

Testability by Layer

Layer Testable Without External Deps? Bagaimana
Domain βœ… Ya Pure Python β€” tidak ada dependency
Application βœ… Ya Inject mock repositories & services
Infrastructure ⚠️ Perlu test DB/Queue Gunakan testcontainers atau in-memory substitutes
Interface ⚠️ Perlu running app Gunakan TestClient (FastAPI)

11. Glossary

Istilah Definisi
PPG Photoplethysmography β€” teknik optik non-invasif untuk mengukur perubahan volume darah dalam jaringan mikrovaskular
ABP Arterial Blood Pressure β€” tekanan darah arteri yang diprediksi oleh model
SBP Systolic Blood Pressure β€” tekanan darah saat jantung berkontraksi (angka atas)
DBP Diastolic Blood Pressure β€” tekanan darah saat jantung berelaksasi (angka bawah)
GAN Generative Adversarial Network β€” arsitektur deep learning untuk mentranslasikan sinyal PPG ke ECG
VGTL-Net Model deep learning yang menerima PPG + ECG untuk memprediksi ABP
ETL Extract-Transform-Load β€” pola pipeline data
Entity Objek domain dengan identitas unik dan lifecycle
Value Object Objek domain immutable yang didefinisikan oleh atributnya
DTO Data Transfer Object β€” objek untuk transfer data antar layer boundary
Repository Abstraksi akses data yang menyembunyikan detail persistence
Use Case Orkestrasi satu unit business logic yang spesifik
Message Broker Middleware yang mengelola antrian pesan antara producer dan consumer
Dependency Injection Teknik menyediakan dependency dari luar, bukan membuat di dalam class

12. References

# Referensi Penulis
1 Clean Architecture: A Craftsman's Guide to Software Structure and Design Robert C. Martin (2017)
2 Design Patterns: Elements of Reusable Object-Oriented Software Gamma, Helm, Johnson, Vlissides (1994)
3 Patterns of Enterprise Application Architecture Martin Fowler (2002)
4 Domain-Driven Design: Tackling Complexity in the Heart of Software Eric Evans (2003)
5 FastAPI Documentation https://fastapi.tiangolo.com
6 SQLAlchemy 2.0 Documentation https://docs.sqlalchemy.org
7 RabbitMQ Tutorials https://www.rabbitmq.com/tutorials
8 Hugging Face Spaces Docker SDK https://huggingface.co/docs/hub/spaces-sdks-docker


Dokumen ini di-maintain oleh Data Engineering Team.
Untuk pertanyaan, silakan buat issue di repository GitHub.

Β© 2026 BP Monitoring Pipeline β€” All rights reserved.