Kamerplanter verwendet ArangoDB als primäre Datenbank — ein Multi-Modell-System, das Dokument- und Graphdatenbank kombiniert. Alle Entitäten sind als Dokument-Collections organisiert; Beziehungen werden als Kanten-Collections im Named Graph kamerplanter_graph abgebildet.
Das Objektarray-Feld propagation_configs ist das kanonische Modell für die Vermehrung einer Art. Jeder PropagationConfig-Eintrag beschreibt eine Vermehrungsmethode mit eigenem Timing, eigener Holzreife, Schwierigkeit und Notizen — und ersetzt damit die früheren Flatfelder propagation_methods/propagation_months/propagation_notes. Teilfelder:
months (list[int], Wertebereich 1–12) — Monate, in denen diese Methode am besten geeignet ist; serverseitig dedupliziert und aufsteigend sortiert, unabhängig von den anderen Configs. Die art-weiten Aussaatzeiträume für die generative Vermehrung bleiben in den separaten Feldern direct_sow_months, indoor_start_months und transplant_months.
wood_stage (WoodStage \| null) — softwood / semi_hardwood / hardwood / herbaceous; nur für Steckling-Methoden relevant.
notes (string \| null, max. 1000 Zeichen) — fachlicher Freitext zu dieser Methode: typische Fehlerquellen, artspezifische Substrat- oder Temperaturanforderungen, Akklimatisierungsschritte.
Das Array ist optional in SpeciesCreate (Standard: leere Liste) und in SpeciesResponse immer vorhanden (leere Liste, wenn nicht gepflegt). Es ist für die meisten Arten in den Seed-Daten gepflegt.
Hinweis (abgekündigte Flatfelder): Die Flatfelder propagation_methods/propagation_months/propagation_notes sind zugunsten von propagation_configsabgekündigt. Alte Flatwerte werden weiterhin akzeptiert und beim Import adaptiert — eine Config je Methode, alle mit den gemeinsamen propagation_months, wobei propagation_notes nur an die erste Methode angehängt wird. Neue Daten verwenden propagation_configs.
Das Objektfeld toxicity erfasst die Giftigkeit einer Art getrennt für Katzen, Hunde und Kinder (is_toxic_cats/is_toxic_dogs/is_toxic_children), die betroffenen Pflanzenteile (toxic_parts), die verantwortlichen Wirkstoffe (toxic_compounds) sowie den Schweregrad (severity: none/mild/moderate/severe). allergen_info ergänzt Kontakt- und Pollenallergen-Flags. Das flache Passthrough-Feld toxicity_severity (low/moderate/high) bleibt aus historischen Daten erhalten und wird nicht auf toxicity.severity gemappt. Alle Felder sind optional (null, wenn nicht gepflegt).
Das Objektfeld seed_profile bündelt echte Saatgut-/Keim-Metadaten für samenvermehrte Arten: Keimtemperatur-Bereich (germination_temp_min_c/_max_c), Saattiefe (sowing_depth_cm), Tage bis Keimung (days_to_germination), Keimfähigkeitsdauer (seed_viability_years), Licht-/Dunkelkeimung (light_germination: light/dark/indifferent), Vorbehandlung (pretreatment: cold_stratification/warm_stratification/scarification/presoak), Tausendkornmasse (thousand_seed_weight_g) und Aussaatdichte (sowing_density_per_m2). Alle Felder sind optional; rein vegetativ vermehrte Arten lassen das Objekt leer (null).
Kamerplanter legt beim Start automatisch folgende Indizes an:
Collection
Index-Feld
Typ
Eindeutig
species
scientific_name
Persistent
Ja
botanical_families
name
Persistent
Ja
slots
slot_id
Persistent
Ja
plant_instances
instance_id
Persistent
Ja
users
email
Persistent
Ja
tenants
slug
Persistent
Ja
memberships
user_key, tenant_key
Persistent
Ja
fertilizers
tenant_key, product_name, brand
Persistent
Ja
harvest_batches
batch_id
Persistent (sparse)
Ja
tanks
tenant_key, name
Persistent
Ja
activities
tenant_key, name
Persistent
Ja
workflow_templates
tenant_key, name
Persistent
Ja
refresh_tokens
token_hash
Persistent
Ja
calendar_feeds
token_hash
Persistent (sparse)
Ja
tasks
status, plant_key
Persistent
Nein
feeding_events
plant_key, timestamp
Persistent
Nein
Sparse-Indizes
Ein als sparse markierter Index berücksichtigt nur Dokumente, in denen das Feld tatsächlich gesetzt ist. Bei harvest_batches.batch_id ist das erforderlich, weil die Chargen-ID ein optionales Feld ist: Leere Eingaben werden auf null normalisiert, und beliebig viele Chargen dürfen gleichzeitig ohne Chargen-ID existieren, während gesetzte Kennungen weiterhin eindeutig bleiben müssen. Bestandsdaten werden von Migration v0030 angepasst (leere Zeichenketten → null, Index-Neuanlage als unique + sparse). Auf Datenbanken, die vor Juni 2026 angelegt wurden, führt ArangoDB den alten Index als Typ hash. v0030 übersieht ihn dort, und erst v0073 entfernt ihn.
Alle mandantengebundenen Ressourcen tragen ein tenant_key-Feld. Beim Zugriff löst die FastAPI-Dependency get_current_tenant den Mandanten aus dem URL-Segment /t/{tenant_slug}/ auf und lehnt ab, wenn der anfragende Nutzer dort keine aktive Mitgliedschaft hat. Schreibende Endpunkte fordern zusätzlich eine Berechtigung: require_permission(resource, action) für Anlegen/Ändern/Löschen mandantengebundener Ressourcen, require_tenant_role für eine reine Mindestrolle und require_admin_scope für administrative Flächen (Mitgliederverwaltung, Integrationen). Auf Datenebene entsteht die Isolierung zusätzlich dadurch, dass jeder Schreibpfad tenant_key aus dem aufgelösten Mandantenkontext stempelt und jede Abfrage nach diesem Feld filtert.
Rechtedurchsetzung: require_permission ist verdrahtet
require_permission(resource, action) entscheidet allein anhand der Mandantenrolle über die reinen MembershipEngine-Prädikate: can_edit_resource (lead/grower) für create/update, can_delete_resource (nur lead, die Unumkehrbarkeitsgrenze aus REQ-049 §2.3) für delete. Lesen bleibt für jedes Mitglied offen. Die feinkörnige Rechtematrix (Ressourcentyp × Aktion × Rolle) im Backend trägt heute den Anhang-Guard und die Schnittstelle für externe KI-Clients; ihr delete-Recht auf Domänenressourcen wurde auf lead-only korrigiert, damit beide Durchsetzungswege übereinstimmen. Ein pro Ressourcentyp differenzierendes Matrix-Backend hinter require_permission (das resource-Argument wird bereits mitgeführt) ist die verbleibende künftige Verfeinerung.