Skip to Content
IoT-App-EntwicklungDateispeicher

Dateispeicher

Jedes App-Data-Backend erhält neben seinen Tabellen einen privaten Objektspeicher. Während das Data Backend Ihre Zeitreihen-Zeilen aufbewahrt, hält der Dateispeicher alles, was nicht in eine Zeile passt: Kamerabilder, PDF-Berichte, Firmware-Blobs, Audioclips, Exporte.

Die beiden sind dafür gemacht, zusammen verwendet zu werden. Das Ablegen einer Datei liefert Ihnen eine permanente URL zurück, und das vorgesehene Muster ist, diese URL im selben Zug in eine Tabellenspalte zu schreiben — ein Dashboard-Widget stellt das Bild dann ohne weiteres Zutun dar:

info = await ironflock.files.put("part-1.jpg", jpeg_bytes, content_type="image/jpeg") await ironflock.publish_to_table("inspections", part_id="1", photo_url=info.url)

Die vollständige Client-API — Lesen, Auflisten, Speicherbelegung, Freigabelinks, große Objekte, Fehlercodes — ist in der SDK-Referenz dokumentiert. Diese Seite behandelt die Plattformseite: wie Speicher deklariert, verwaltet, freigegeben und betrieben wird.

Funktionsweise

  1. Deklarieren Sie optional einen files:-Abschnitt in .ironflock/data-template.yml.
  2. Wenn ein Benutzer Ihre App in einem Projekt installiert, stellt IronFlock einen privaten Speicherbereich dafür bereit — genau so, wie es die Projektdatenbank bereitstellt.
  3. Ihr Edge-Code speichert und liest Objekte über die files-API des SDK.
  4. Beim Deinstallieren der App wird ihr Speicher vollständig entfernt: jedes Objekt und alle Zugangsdaten, genau wie das Datenbankschema verworfen wird.

Wie die Datenbank ist auch der Speicher projektweise. Dieselbe App, in zwei Projekten installiert, erhält zwei vollständig getrennte Speicherbereiche, und als App-Entwickler haben Sie auf keinen von beiden Zugriff — die Daten gehören dem Benutzer, der Ihre App ausführt.

Keine Konfiguration ist eine gültige Konfiguration: Auch eine App ohne files:-Abschnitt erhält einen Namespace mit dem Namen default, sodass files.put(...) bei jeder App von Haus aus funktioniert.

Speicher im Data Template deklarieren

Der files:-Abschnitt steht neben data: in data-template.yml:

files: description: Camera frames and generated inspection reports. # Speicher-Budget, das die App für sich selbst VORSCHLÄGT, in Bytes (hier 5 GiB). # Der Projektnutzer kann es überschreiben; durchgesetzt wird seine Einstellung. quotaBytes: 5368709120 namespaces: - name: frames description: Raw camera frames, one JPEG per inspected part. contentTypes: ["image/jpeg"] maxObjectBytes: 20971520 retention: { deleteAfter: 30 days } - name: reports description: Generated PDF inspection reports. contentTypes: ["application/pdf"] private: true

Namespaces

Ein Namespace ist ein Schlüsselpräfix, das Richtlinien mitführt. Er ist kein separater Bucket — jeder Namespace einer App liegt innerhalb des einen Speicherbereichs der App, und der Namespace-Name wird schlicht zum ersten Segment des Speicherpfads jedes Objekts.

Diese Unterscheidung sagt Ihnen, wann Sie einen deklarieren sollten:

  • Dateien organisieren? Verwenden Sie Schlüsselpfade — 2026/03/part-1.jpg — innerhalb des default-Namespace. Ordnerartige Schlüssel sind der Normalfall.
  • Andere Regeln für eine Menge von Objekten? Deklarieren Sie einen Namespace. Regeln sind das Einzige, was ein Namespace hinzufügt.

Die Regeln, die ein Namespace mitführen kann:

FeldBedeutung
nameKleinbuchstaben, Ziffern und Bindestriche, beginnend mit einem Buchstaben. sys, system, ironflock und ironflock-* sind reserviert
descriptionWird Benutzern angezeigt und ist von KI-Agenten lesbar
privateSchließt den Namespace vom App-übergreifenden Zugriff aus. Standardwert ist false (geteilt) — genau wie bei Tabellen
contentTypesErlaubte MIME-Typen, Globs zulässig (image/*). Standard: beliebig
maxObjectBytesGrößtes Einzelobjekt, bis zu 5 GiB. Standard 100 MiB
retention.deleteAfterObjekte, die älter sind, werden automatisch gelöscht (30 days, 2 weeks, 1 year, …)

Das Speicher-Budget

quotaBytes wird einmal für die gesamte App deklariert, nicht pro Namespace. Ein Namespace ist nur ein Schlüsselpräfix, sodass es nichts gibt, wogegen sich ein Budget pro Präfix durchsetzen ließe — das Kontingent gilt für den einen Speicherbereich der App, und der Objektspeicher selbst setzt es auf jedem Schreibpfad durch, einschließlich direkter Uploads.

Es gibt zwei Zahlen, und der Unterschied ist gewollt:

  • Das vorgeschlagene Kontingent — was Ihr Template anfordert. Wird angewendet, wenn die App zum ersten Mal installiert wird.
  • Das durchgesetzte Kontingent — was der Projektnutzer eingestellt hat. Sobald ein Nutzer das Budget in den Speichereinstellungen der App ändert, gewinnt sein Wert, und ein erneutes Deployment Ihrer App setzt ihn nicht zurück.

Sagt Ihr Template nichts, gilt der Plattform-Standard (1 GiB für Entwicklungs-Backends, 10 GiB für Produktions-Backends).

Aufbewahrung

Objekte, die das deleteAfter-Alter ihres Namespace überschritten haben, werden automatisch entfernt — das dateiseitige Gegenstück zur dropAfter-Richtlinie einer Tabelle. Die Aufbewahrung läuft innerhalb des Objektspeichers, wo dieser sie unterstützt, und andernfalls als täglicher Plattform-Job (On-Premises-Appliances), sodass sich eine deklarierte Aufbewahrung überall gleich verhält.

Permanente URLs und Dashboards

Jedes gespeicherte Objekt hat eine stabile URL der Form https://files.ironflock.com/f/<backend>/<namespace>/<key>. Drei Eigenschaften machen sie zum Richtigen, um sie in eine Tabellenspalte zu schreiben:

  • Sie läuft nie ab. Die URL ist eine reine Adresse; sie bleibt für die gesamte Lebensdauer des Objekts gültig.
  • Sie ist kein öffentlicher Link. Jede Anfrage durchläuft einen Authentifizierungs-Proxy, der prüft, ob der Anfragende angemeldet ist und READ-Zugriff auf dieses Data Backend besitzt — bei jeder einzelnen Anfrage erneut. Wird einem Benutzer der Zugriff entzogen, verliert er sofort die Möglichkeit, jede Datei abzurufen.
  • Sie funktioniert in einem <img>. Der Browser sendet sein Session-Cookie automatisch, sodass ein Dashboard-Widget die URL in <img src>, <video src> oder einem Download-Link verwenden kann — ohne jegliches JavaScript.

Um eine Datei an jemanden außerhalb des Projekts weiterzugeben, erzeugt das share_url des SDK stattdessen einen ablaufenden Bearer-Link — siehe Objekte freigeben, wann Sie welchen verwenden.

Große Dateien

Übertragungen bis zu 6 MiB laufen als einzelner Aufruf durch das Messaging-System. Alles Größere wird direkt zwischen dem Gerät und dem Objektspeicher über HTTPS übertragen — das SDK schaltet automatisch um, streamt von und auf die Festplatte, und eine mehrere Gigabyte große Datei muss niemals in den Arbeitsspeicher passen. Die Obergrenze für einen einzelnen Upload liegt bei 5 GiB.

Der direkte Pfad setzt voraus, dass das Gerät den Host des Objektspeichers (s3.ironflock.com) erreicht, nicht nur den Messaging-Router. Lässt ein Fabrik-Proxy nur den Router zu, schlagen große Übertragungen mit dem eindeutigen Code PRESIGN_UNREACHABLE statt mit einem generischen Fehler fehl — und eine Geräteuhr, die mehr als 15 Minuten abweicht, scheitert mit CLOCK_SKEW, was ein Hinweis ist, NTP zu prüfen, nicht die Zugangsdaten.

Dateien zwischen Apps teilen

Der App-übergreifende Dateizugriff nutzt dieselbe Zustimmung wie der App-übergreifende Tabellenzugriff. Es gibt einen einzigen Schalter: Wenn ein Projektnutzer App B Zugriff auf die Daten von App A gewährt (die data_access-Zustimmung in den App-Einstellungen), deckt diese Freigabe die Tabellen von A und die nicht privaten Datei-Namespaces von A ab. Ein Widerruf hebt beides auf.

Was Ihre App als Anbieter steuert, ist das private-Flag pro Namespace:

  • private: false (der Standard) — Apps mit einer Data-Access-Freigabe können den Namespace lesen (niemals schreiben).
  • private: true — der Namespace ist für andere Apps unsichtbar, Punkt, auch mit einer Freigabe.

Das entspricht genau Daten anderer Apps nutzen: Namespaces und Tabellen haben denselben Standard. Ohne die Freigabe des Projektnutzers wird nichts geteilt — private: schränkt nur ein, was ein bereits zugelassener Leser sieht, es ist nicht die Zustimmung selbst.

Die Sicht des Benutzers

Projektnutzer sehen und verwalten den Speicher Ihrer App an zwei Stellen:

  • Die Daten-Ansicht zeigt neben den Tabellen und Views jeder App einen Eintrag Dateien — eine durchsuchbare Auflistung jedes gespeicherten Objekts mit Größe, Typ und Änderungsdatum sowie Download pro Datei.
  • Die Speichereinstellungen der App zeigen die Belegung (Bytes und Objektanzahl), das durchgesetzte Budget neben dem Vorschlag Ihrer App, ein Bedienelement zum Ändern des Budgets und eine Aktion Alle Dateien löschen — das dateiseitige Pendant zum Leeren aller Tabellen. Das Löschen wird durch Eingabe des App-Namens bestätigt und kann nicht rückgängig gemacht werden.
  • Der KI-Assistent kann diese Dateien im Auftrag eines Benutzers auflisten, durchsuchen und lesen. Es gilt dieselbe DATABACKEND/READ-Prüfung, sodass nie eine Datei erscheint, die der Benutzer nicht selbst öffnen könnte. Gesucht wird in Dateipfaden, nicht in Dateiinhalten; Textdateien, Bilder und PDFs kann er lesen — Archive und andere Binärformate nicht.

Wie bei Tabellen sind dies die Daten des Benutzers: Er kann sie inspizieren, begrenzen und löschen, ohne Sie einzubeziehen.

Direkter S3-Zugriff

Für alles jenseits des SDK — ein Analyst mit DuckDB, ein nächtliches rclone-Backup, eine BI-Pipeline — kann ein Projektnutzer aus den Speichereinstellungen der App schreibgeschützte S3-Zugangsdaten pro App ausstellen.

Jeder Satz Zugangsdaten ist auf den Speicherbereich dieser einen App beschränkt: Zugangsdaten, die für App A ausgestellt wurden, funktionieren strukturell nicht für die Dateien von App B — die Speicherrichtlinie von B benennt sie schlicht nie. Ein Projekt kann mehrere Sätze Zugangsdaten pro App vorhalten (einen pro Konsument: einen CI-Job, ein Backup-Skript, einen Laptop), und der Widerruf eines Satzes lässt die anderen weiterlaufen. Das ist zugleich die Rotationsstrategie: Wenn ein Schlüssel abhandenkommt, stellen Sie einen zweiten Satz Zugangsdaten aus, stellen Sie den Konsumenten um und widerrufen Sie den ersten — kein anderer Konsument wird gestört.

Das Secret wird einmalig bei der Erstellung angezeigt. Das Ausstellen erfordert Lesezugriff auf das Data Backend der jeweiligen App — dieselbe Berechtigung, die das Lesen der Dateien überhaupt erst erlaubt, sodass die Zugangsdaten niemandes Reichweite erweitern können.

# rclone rclone config create myapp s3 provider=Other \ endpoint=https://s3.ironflock.com \ access_key_id=ifs-key-3317-x7k2m secret_access_key=<shown once> rclone ls myapp:if-1042-3317
# DuckDB CREATE SECRET (TYPE S3, KEY_ID 'ifs-key-3317-x7k2m', SECRET '<shown once>', ENDPOINT 's3.ironflock.com'); SELECT * FROM read_parquet('s3://if-1042-3317/exports/*.parquet');

Die Speichereinstellungen zeigen den Endpunkt und den exakten Bucket-Namen, auf den ein Client verweisen soll. Beachten Sie, dass eine Auflistung der Buckets auf oberster Ebene (aws s3 ls ohne Argument) bewusst nichts zurückgibt — die Zugangsdaten besitzen keine Buckets; ihnen wird der Zugriff auf einen gewährt. Adressieren Sie den Bucket direkt, wie oben.

On-Premises-Appliances

Der Dateispeicher funktioniert auf einer On-Premises-Appliance identisch, mit drei Unterschieden, die sich aus dem Design der Appliance ergeben:

  • Dateien werden same-origin unter der eigenen Adresse der Appliance ausgeliefert (/files/...) — kein zusätzlicher DNS-Name, kein zusätzliches Zertifikat, und es funktioniert auch in reinen HTTP-Installationen. Permanente URLs und <img src> verhalten sich genau wie in der Cloud.
  • Das Speicher-Backend der Appliance streamt Datei-Downloads durch die Plattform, statt auf einen separaten Speicher-Host umzuleiten, sodass der Speicherdienst nie als zweite Origin nach außen tritt.
  • Direkte S3-Zugangsdaten sind nicht verfügbar auf Appliances — der eingebettete Objektspeicher kann keine Zugriffsgewährungen pro Zugangsdaten-Satz ausdrücken. Der Abschnitt erscheint dort schlicht nicht in den Speichereinstellungen. Alles andere, einschließlich des Verhaltens für große Dateien über das SDK und der deklarierten Aufbewahrung, funktioniert gleich.

Eine Air-Gap-Appliance bedient den gesamten Dateiverkehr lokal: App-Logos, Dashboard-Bilder und Datei-Downloads benötigen keine Internetverbindung.

Limits auf einen Blick

LimitWertWoher es stammt
Inline-Übertragung (einzelner Aufruf)6 MiBWird zur Laufzeit gemeldet; kann serverseitig angehoben werden
Einzelobjekt100 MiB Standard, 5 GiB maxmaxObjectBytes pro Namespace
Einzelner Upload5 GiBObergrenze des Objektspeichers für einen einzelnen PUT; Multipart ist noch nicht verfügbar
Speicher-Budget1 GiB Dev / 10 GiB Prod (Standard)Vom Template vorgeschlagen, vom Benutzer entschieden
Schlüssellänge & -zeichenUTF-8, /-getrennte Pfade../, Steuerzeichen und reservierte Präfixe werden abgelehnt
Last updated on