Files
gala-ki-spielwiese/database/docs/plan_pck_net_storage.md

12 KiB

Plan: PCK_NET_STORAGE

Stand: 2026-04-08 Status: Implementiert


Ziel

PL/SQL Package PCK_NET_STORAGE kapselt alle Zugriffe auf OCI Object Storage über REST API. Wird in Oracle APEX für einen Dateimanager genutzt (Browse, Upload, Download, Rename, Move, Delete).


Dateien

tables/
  lg_app_log.tab

types/
  t_net_storage_row.typ     ← Schema-Level Type (siehe Hinweis)
  t_net_storage_tab.typ     ← Nested Table von t_net_storage_row

packages/
  pck_log.pkh / pck_log.pkb
  pck_net_storage.pkh / pck_net_storage.pkb
  pck_auto_import.pkh / pck_auto_import.pkb

Hinweis Schema-Level Types: TABLE() in SQL erfordert in Oracle schema-level Types. t_net_storage_row / t_net_storage_tab werden ausschließlich intern für den sys_refcursor von f_list_objects benötigt — keine Auswirkung auf die öffentliche API.


Authentifizierung

APEX Web Credentials (Typ: Oracle Cloud Infrastructure) Static ID: OCI_OBJ_STORE_CRED Wird in APEX Admin UI einmalig angelegt mit: OCI User OCID, Tenancy OCID, Fingerprint, Private Key (PEM). In PL/SQL referenziert via p_credential_static_id => c_credential_id in apex_web_service.make_rest_request.

Grund: DBMS_CLOUD ist auf dieser DB nicht installiert. APEX übernimmt OCI HTTP Signature V1 (SHA-256) automatisch.


Konfigurationsparameter

Alle zur Laufzeit via pck_system.f_get_par_wert_by_programmid:

Parameter-ID Inhalt
NETSTORE_BUCKET Bucket-Name
NETSTORE_NAMESPACE OCI Object Storage Namespace
NETSTORE_REGION z.B. eu-frankfurt-1
NETSTORE_TENANT_ID Erlaubter Root-Prefix, z.B. mandant_42/
NETSTORE_CRED_ID Credential Static ID für apex_web_service calls, z.B. 'OCI_OBJ_STORE_CRED'
NETSTORE_MARKER_DB Name der Marker-Datei im Object Store, der von Automaton abgelegt wird, um zu signalisieren, dass der entsprechende Unterordner komplett hochgeladen wurde. Verhindert die Verarbeitung von unvollständig hochgeladenen Ordnern. z.B.: _READY_FOR_DB_PROCESSING_
NETSTORE_MARKER_SB Name der Marker-Datei im Object Store, der von DB beim Verarbeiten angelegt wird, wenn eine oder mehrere Dateien eines ZIPs nicht automatisiert importiert werden konnten. Das soll signalisieren, dass ein Sachbearbeiter die Dateien in diesem Unterordner manuell prüfen und importieren muss. z.B.: _BITTE_PRÜFEN_
NETSTORE_BA_PREFIX Pfad in Object Storage, wo BA-Daten liegen. Muss mit einem / enden, z.B. BA/Eingang/
NETSTORE_BA_IMPORT Name des Unterordners von NETSTORE_BA_PREFIX im Object Storage, wo entpackte Dateien, die noch importiert werden müssen, zwischengespeichert werden.
BA_IMPORT_SB_MIT_ID Mitarbeiter-ID für Import von BA Daten (z.B. Korrespondenzen). Diese Mitarbeiter-ID bekommt eine Wiedervorlage, für jede Datei, die nicht automatisch importiert werden konnte.

Öffentliche Schnittstelle (Package Spec)

Record Type t_object_meta

Feld Typ
object_name varchar2(1024)
object_size number
last_modified date
content_type varchar2(256)
etag varchar2(256)

Öffentliche Prozeduren und Funktionen

Namenskonvention: Prozeduren p_-Präfix, Funktionen f_-Präfix. Parameter immer i_-Präfix.

Name Typ Signatur Rückgabe Anmerkung
f_list_objects Funktion (i_prefix, i_delimiter, i_start_with, i_limit) sys_refcursor Cursor-Spalten: object_name, object_size, last_modified, is_folder(Y/N), etag
f_download_object Funktion (i_object_key) blob
p_upload_object Prozedur (i_object_key, i_content blob, i_content_type)
p_delete_object Prozedur (i_object_key)
p_delete_folder Prozedur (i_prefix) intern: f_list_objects-Loop + p_delete_object
p_rename_object Prozedur (i_object_key, i_new_name) intern: OCI RenameObject API
p_move_object Prozedur (i_object_key, i_target_prefix) intern: OCI RenameObject API
p_create_folder Prozedur (i_prefix, i_folder_name) PUT leeres Objekt mit trailing /
f_get_object_metadata Funktion (i_object_key) t_object_meta HEAD Request

Rechteprüfungen:

Zu beginn von delete-operationen muss folgender Aufruf durchgeführt werden, um die Rechte des nutzers zu prüfen: pck_mitarbeiterrecht.p_hat_recht('ADMIN');

Bei anderen schreib-Operationen, wie rename oder move muss die Prüfung von folgendem Recht erfolgen: pck_mitarbeiterrecht.p_hat_recht('SCHREIBEN_ALLES');

Bei lese-Operationen wie f_get_object_metadata und f_download_object muss folgendes Recht geprüft werden:

pck_mitarbeiterrecht.p_hat_recht('LESEN_ALLES');

Schlägt eine Prüfung fehl, wirft die p_hat_recht Prozedur einen speziellen Application Error mit Fehlermeldung für den Benutzer.


Private Helpers (nur Body)

Name Typ Zweck
f_get_cfg Funktion Wrapper für pck_system.f_get_par_wert_by_programmid
f_build_url Funktion Baut vollständige OCI REST URL (/n/{ns}/b/{bucket}/o/{key})
p_assert_allowed Prozedur Tenant-Prefix-Guard + Path-Traversal-Prüfung
f_make_request Funktion Wrapper für apex_web_service.make_rest_request, wertet HTTP-Status aus, gibt Response-Body zurück

Pagination (f_list_objects)

OCI liefert max. 1000 Objekte pro Request. f_list_objects ruft OCI intern in einer Schleife auf (nextStartWith-Token aus JSON-Response) bis alle Seiten geladen sind. Ergebnis wird in einer lokalen Collection gesammelt, am Ende als sys_refcursor geöffnet. i_limit = 0 → unbegrenzt, i_limit > 0 → Abbruch wenn Limit erreicht.

OCI-Response trennt Unterordner (prefixes-Array) von Dateien (objects-Array) — beide werden eingesammelt, Ordner mit is_folder = 'Y'.


Fehlerbehandlung

f_make_request wirft bei HTTP-Fehler:

HTTP-Status Fehlercode Meldung
404 -20001 Object not found: {key}
401 / 403 -20002 OCI authentication failed
409 -20007 Object already exists: {key}
sonstige 4xx/5xx -20006 OCI API error {status}: {response body}

p_assert_allowed wirft:

Fall Fehlercode Meldung
.. im Pfad -20004 Path traversal attempt detected
Pfad außerhalb Tenant-Prefix -20005 Access denied: outside tenant scope

Bucket nicht erreichbar → -20003 via f_make_request


Sicherheit / Tenant-Isolation

p_assert_allowed wird am Anfang jeder öffentlichen Funktion/Prozedur aufgerufen:

  1. Tenant-Prefix laden via f_get_cfg('NET_STORAGE_TENANT_ID')
  2. ..-Sequenzen im übergebenen Key prüfen → -20004
  3. Prüfen ob Key mit Tenant-Prefix beginnt → -20005

Dateieingang-Verarbeitung

OCI-Struktur

Der Quarkus Automaton legt Dateien in einem Unterordner ab, der nach der ZIP-Datei benannt ist. Unterordner innerhalb der ZIP werden beibehalten:

eingang/<zip-name>/datei1.csv
eingang/<zip-name>/unterordner/datei3.csv
eingang/<zip-name>/_READY_FOR_DB_PROCESSING_    ← Marker

Marker-Datei

Der Quarkus Automaton legt nach erfolgreichem Upload aller Dateien eine leere Marker-Datei ab: eingang/<zip-name>/_READY_FOR_DB_PROCESSING_

Die DB verarbeitet einen Unterordner ausschließlich wenn der Marker vorhanden ist. Der Marker wird erst gelöscht wenn alle Dateien des Unterordners erfolgreich verarbeitet wurden — so werden fehlgeschlagene Dateien beim nächsten Lauf erneut versucht.

Prozedur p_process_incoming_ba_data (in pck_auto_import, nicht in pck_net_storage)

1. Unterordner von eingang/ auflisten (f_list_objects mit delimiter='/')
2. Für jeden Unterordner:
   a. Marker eingang/<zip-name>/_READY_FOR_DB_PROCESSING_ vorhanden?
      → nein: überspringen (unvollständiger Upload)
   b. Alle Dateien in eingang/<zip-name>/ auflisten (ohne Marker)
   c. Für jede Datei einzeln:
      begin
          Fachliche Verarbeitung (Import) — noch kein Commit
          log_object_ref := 'eingang/<zip-name>/datei.csv'  ← ZIP aus Pfad ableitbar
          pck_net_storage.p_move_object(datei → Zielordner/<zip-name>/)
          commit
          pck_log.p_info(...)
      exception when others then
          rollback
          pck_log.p_error(i_object_ref => 'eingang/<zip-name>/datei.csv', ...)
      end
   d. Noch Dateien in eingang/<zip-name>/ (außer Marker)?
      → nein: pck_net_storage.p_delete_object(Marker) — Batch abgeschlossen
      → ja:  Marker bleibt — nächster Lauf versucht verbleibende Dateien

Rollback nach fehlgeschlagenem p_move_object macht auch den Import rückgängig. Kein Verhalten wird aus lg_app_log abgeleitet — es dient ausschließlich dem Audit.

ORDS-Endpunkt

POST /ords/.../net_storage/process_incoming_ba_data → ruft p_process_incoming_ba_data auf. Wird von automaton nach erfolgreichem Upload aufgerufen. Schlägt der Aufruf fehl: APEX Automation greift beim nächsten Stundenlauf.


APEX REST Data Source (manuell einrichten)

Für das APEX Interactive Report im Dateimanager-Browser:

Name:              NET_STORAGE_LIST_OBJECTS
Base-URL:          https://objectstorage.{region}.oraclecloud.com
Endpoint:          /n/{namespace}/b/{bucket}/o
Method:            GET
Web Credential:    OCI_OBJ_STORE_CRED

URL-Parameter:
  prefix      → aktueller Ordner-Prefix (Bind-Variable aus APEX)
  delimiter   → /
  limit       → 1000
  start       → für Pagination (optional)

Spalten-Mapping:
  objects[*].name           → OBJECT_NAME
  objects[*].size           → OBJECT_SIZE
  objects[*].timeModified   → LAST_MODIFIED
  objects[*].etag           → ETAG

Hinweis: prefixes (Unterordner) und objects (Dateien) sind zwei separate JSON-Arrays. Für ein gemeinsames IR entweder zwei REST Sources mit UNION, oder f_list_objects über eine APEX Collection als IR-Quelle nutzen.


Logging: lg_app_log + pck_log

Tabelle lg_app_log

Allgemeine Anwendungs-Log-Tabelle, modulübergreifend nutzbar. Keine Indizes (Log-Volumen ist gering, Ad-hoc-Suche reicht ohne Index).

Spalte Typ Pflicht Beschreibung
lg_app_log_id number generated by default as identity ja PK
log_timestamp timestamp ja Zeitpunkt des Log-Eintrags
log_level varchar2(10 char) ja INFO, WARN, ERROR
log_module varchar2(100 char) ja z.B. PCK_NET_STORAGE
log_action varchar2(100 char) nein z.B. PROCESS_FILE
log_object_ref varchar2(512 char) nein z.B. eingang/datei.csv
log_message varchar2(4000 char) nein Kurzmeldung
log_detail clob nein Stack Trace, JSON, etc.
log_user varchar2(100 char) nein APEX- oder DB-User
log_session_id number nein Oracle Session-ID

Keine Audit-Spalten (Log-Tabelle ist self-auditing durch log_timestamp + log_user).

Package pck_log

Öffentliche Prozeduren:

Name Signatur
p_info (i_module, i_action, i_message, i_object_ref default null)
p_warn (i_module, i_action, i_message, i_object_ref default null)
p_error (i_module, i_action, i_message, i_detail default null, i_object_ref default null)

Intern immer PRAGMA AUTONOMOUS_TRANSACTION + COMMIT — Log-Einträge sind transaktionsunabhängig und überleben Rollbacks der Haupttransaktion.


OCI API Endpunkte (Referenz)

Operation Method Pfad
List Objects GET /n/{ns}/b/{bucket}/o?prefix=...&delimiter=/
Get Object GET /n/{ns}/b/{bucket}/o/{objectName}
Put Object PUT /n/{ns}/b/{bucket}/o/{objectName}
Delete Object DELETE /n/{ns}/b/{bucket}/o/{objectName}
Head Object HEAD /n/{ns}/b/{bucket}/o/{objectName}
Rename Object POST /n/{ns}/b/{bucket}/actions/renameObject