start
Differences
This shows you the differences between two versions of the page.
| start [2025/11/11 15:45] – created admin | start [2026/05/06 06:01] (current) – external edit 127.0.0.1 | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | Title: Consistency Manager (Edges + Policy-Aware Deletion) | + | ====== orydio — User Manual ====== |
| - | Version: 1.2 | + | |
| - | Updated: 2025-11-11 | + | |
| - | --- | + | **Platform: |
| + | **Operator: | ||
| + | **Updated: | ||
| - | 1) Purpose | + | This manual covers all modules available in orydio from a user perspective. |
| - | ---------- | + | For technical / developer documentation see the separate developer wiki. |
| - | Maintain application-level referential integrity across PHP models (Invoice, InvoiceLine, | + | |
| - | - An edges registry table (`consistency_edges`) that stores directed links like `invoice → user` with a relation label (e.g., `invoice: | + | |
| - | - A centralized policy map that decides what to do when deleting a node: **RESTRICT | NULLIFY | CASCADE | DETACH**. | + | |
| - | - A single, policy-aware deletion method: `_destroyMySelf()` on every model. | + | |
| - | **What changed today** | + | ---- |
| - | - Edges can reliably reference **string identifiers** (e.g., `partners.uniqueid`) as `dst_id`. | + | |
| - | - Per-edge **resolve_by** support: pass `[' | + | |
| - | - Optional **edge UID templating** saved in `meta_json.uid`. | + | |
| - | - A **registry-driven reindex CLI** builds all edges from a single PHP registry file. | + | |
| - | - Safer table-name resolution for `\Lib\GlobalOptions:: | + | |
| - | - Inbound/ | + | |
| - | --- | + | ===== Getting Started ===== |
| - | 2) One deletion method | + | * [[user:dashboard|Dashboard — Home Screen & Widgets]] |
| - | ---------------------- | + | |
| - | Only call `_destroyMySelf()` from application code. It is policy-aware by default. It: | + | |
| - | - Inspects **inbound** edges into the node being deleted. | + | |
| - | - Applies the policy for that node’s table. | + | |
| - | - Performs **NULLIFY/ | + | |
| - | - Physically deletes the row and removes its edges. | + | |
| - | No separate `delete()` or wrapper is required. | + | ---- |
| - | --- | + | ===== Communications ===== |
| - | 3) GlobalOptions table names | + | * [[user:communications|Missed Calls — AI Receptionist Messages]] |
| - | ---------------------------- | + | |
| - | In model edge maps and in the policy map, table names are configured as `\Lib\GlobalOptions::*` identifiers. | + | |
| - | At runtime, these identifiers are resolved to physical table names by calling the corresponding `GlobalOptions` method. | + | |
| - | Examples: | + | ---- |
| - | - `\Lib\GlobalOptions:: | + | |
| - | - `\Lib\GlobalOptions:: | + | |
| - | Models set `$this-> | + | ===== Master Data ===== |
| - | --- | + | * [[user: |
| - | 4) Edges map (per model) | + | ---- |
| - | ------------------------- | + | |
| - | Each model defines `$edgesMap` to declare **outbound** relations. Example (Invoice): | + | |
| - | ``` | + | ===== CRM ===== |
| - | protected array $edgesMap | + | |
| - | ' | + | |
| - | ' | + | |
| - | ' | + | |
| - | ], | + | |
| - | ' | + | |
| - | ' | + | |
| - | ' | + | |
| - | ], | + | |
| - | ' | + | |
| - | ' | + | |
| - | ' | + | |
| - | ], | + | |
| - | ' | + | |
| - | ' | + | |
| - | ' | + | |
| - | ], | + | |
| - | // SPECIAL: invoice.partner_id stores the Partner’s UNIQUE string key (partners.uniqueid) | + | |
| - | ' | + | |
| - | ' | + | |
| - | ' | + | |
| - | // choose ONE of the following, depending on how you want to store: | + | |
| - | // A) Keep edges.dst_id as the UNIQUE string (no lookup): | + | |
| - | // (no resolve_by set) | + | |
| - | // B) Resolve the unique string to partner.id before storing: | + | |
| - | ' | + | |
| - | // Optional audit UID template (goes to meta_json.uid): | + | |
| - | // ' | + | |
| - | ], | + | |
| - | ]; | + | |
| - | ``` | + | |
| - | On every `_save()`, the base model: | + | * [[user:crm|CRM — Leads & Contracts]] |
| - | - Deletes old **outgoing** edges for this record. | + | |
| - | - Inserts new edges derived from current field values (using the rules above). | + | |
| - | --- | + | ---- |
| - | 5) Policy map | + | ===== Financial Instruments ===== |
| - | ------------- | + | |
| - | Defined in `Lib/ | + | |
| - | ``` | + | * [[user:instruments|Financial Instruments — Securities & Subscriptions]] |
| - | $T_USER | + | |
| - | $T_INVOICES | + | |
| - | $T_INVOICE_LINES = ' | + | |
| - | return [ | + | ---- |
| - | $T_USER => [ | + | |
| - | ' | + | |
| - | ' | + | |
| - | ' | + | |
| - | ' | + | |
| - | [' | + | |
| - | ], | + | |
| - | ], | + | |
| - | ' | + | |
| - | ], | + | |
| - | ], | + | |
| - | $T_INVOICES => [ | + | |
| - | ' | + | |
| - | ' | + | |
| - | ' | + | |
| - | ], | + | |
| - | ], | + | |
| - | $T_INVOICE_LINES => [ | + | |
| - | ' | + | |
| - | ' | + | |
| - | ], | + | |
| - | ], | + | |
| - | ]; | + | |
| - | ``` | + | |
| - | **Actions** | + | ===== Document Management ===== |
| - | - **RESTRICT**: | + | |
| - | - **NULLIFY** : set referencing field(s) to `NULL` based on `nullify` list. | + | |
| - | - **CASCADE** : recursively delete referencing sources (policy-aware). | + | |
| - | - **DETACH** | + | |
| - | --- | + | * [[user: |
| - | 6) Storage model & SQL schema | + | ---- |
| - | ------------------------------ | + | |
| - | **What the runtime stores** | + | |
| - | - `src_table` / `dst_table`: | + | |
| - | - `src_id`: integer (the source record’s `id`). | + | |
| - | - `dst_id`: **string** (can be a numeric id or a unique string such as `partners.uniqueid`). | + | |
| - | - `meta_json`: | + | |
| - | **Recommended schema (`sql/ | + | ===== Finance ===== |
| - | ``` | + | |
| - | CREATE TABLE `consistency_edges` ( | + | |
| - | `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, | + | |
| - | `src_table` VARCHAR(128) NOT NULL, | + | |
| - | `src_id` BIGINT UNSIGNED NOT NULL, | + | |
| - | `relation` VARCHAR(128) NOT NULL, | + | |
| - | `dst_table` VARCHAR(128) NOT NULL, | + | |
| - | `dst_id` VARCHAR(128) NOT NULL, -- CHANGED: allow string identifiers | + | |
| - | `weight` INT NOT NULL DEFAULT 1, | + | |
| - | `meta_json` JSON NULL, | + | |
| - | `created` DATETIME NOT NULL, | + | |
| - | `updated` DATETIME NOT NULL, | + | |
| - | PRIMARY KEY (`id`), | + | |
| - | UNIQUE KEY `u_edge` (`src_table`, | + | |
| - | KEY `i_dst` (`dst_table`, | + | |
| - | KEY `i_src` (`src_table`, | + | |
| - | KEY `i_rel` (`relation`) | + | |
| - | ); | + | |
| - | ``` | + | |
| - | **Migration note** | + | |
| - | - If you previously had `dst_id BIGINT`, migrate to `VARCHAR(128)` if you want to store string keys. | + | |
| - | - If you prefer to keep `dst_id` numeric, use `resolve_by` (see §7) so the manager resolves the string to the destination’s numeric `id` before insert. | + | |
| - | --- | + | ---- |
| - | 7) How destination identifiers are chosen (numeric vs string) | + | ===== Banking ===== |
| - | ------------------------------------------------------------- | + | |
| - | There are **two supported modes** per edge: | + | |
| - | **A) Store the string key as `dst_id` (no resolution)** | + | |
| - | - Do **not** set `resolve_by`. | + | |
| - | - The edge stores whatever the model field contains (e.g., `partner_id = ' | + | |
| - | - Schema must allow strings for `dst_id`. | + | |
| - | **B) Resolve the string key → destination numeric `id`** | + | ---- |
| - | - In the edge definition (model or registry), set: `' | + | |
| - | - The manager runs: `SELECT id FROM partners WHERE uniqueid = :val LIMIT 1`. | + | |
| - | - If found, it stores that numeric `id` as `dst_id`, and writes a hint into `meta_json._resolved`. | + | |
| - | - If not found, it keeps the original value and logs a warning. | + | |
| - | **Which is correct? | + | ===== Administration ===== |
| - | Both are supported. Pick a **single convention** per table/ | + | |
| - | - Prefer **resolution to numeric `id`** when you control the destination table and want faster joins. | + | |
| - | - Prefer **string `dst_id`** when referencing external identifiers you don’t want to dereference now. | + | |
| - | --- | + | * [[user: |
| - | 8) CLI (with registry-based reindex) | + | ---- |
| - | ------------------------------------ | + | |
| - | Usage: | + | |
| - | ``` | + | |
| - | php bin/ | + | |
| - | php bin/ | + | |
| - | php bin/ | + | |
| - | php bin/ | + | |
| - | # NEW | + | ===== Additional Sections ===== |
| - | php bin/ | + | |
| - | php bin/ | + | |
| - | ``` | + | |
| - | - **Registry file**: `Lib/ | + | |
| - | | + | * [[user: |
| + | | ||
| - | **Registry example (Invoice)** | + | ---- |
| - | ``` | + | |
| - | return [ | + | |
| - | ' | + | |
| - | ' | + | |
| - | ' | + | |
| - | ' | + | |
| - | ' | + | |
| - | ' | + | |
| - | ' | + | |
| - | ' | + | |
| - | ], | + | |
| - | ' | + | |
| - | ' | + | |
| - | ' | + | |
| - | ' | + | |
| - | ], | + | |
| - | ' | + | |
| - | ' | + | |
| - | ' | + | |
| - | ], | + | |
| - | ' | + | |
| - | ' | + | |
| - | ' | + | |
| - | ], | + | |
| - | // SPECIAL | + | |
| - | ' | + | |
| - | ' | + | |
| - | ' | + | |
| - | ' | + | |
| - | ], | + | |
| - | ], | + | |
| - | ], | + | |
| - | ]; | + | |
| - | ``` | + | |
| - | **UID templating** | + | > **Note:** Screenshot placeholders are marked with '' |
| - | You can add a stable edge identifier (for audits) via `uid`: | + | |
| - | - Example: `{src_table}: | + | |
| - | - Example: `inv: | + | |
| - | The CLI and runtime write this into `meta_json.uid`. | + | |
| - | --- | ||
| - | |||
| - | 9) Runtime hooks (where edges are written) | ||
| - | ------------------------------------------ | ||
| - | In the base model, the simplified hook: | ||
| - | |||
| - | ``` | ||
| - | protected function registerConsistencyEdges(): | ||
| - | { | ||
| - | if (!class_exists(' | ||
| - | |||
| - | $mgr = \Lib\Model\_ConsistencyManager:: | ||
| - | $tbl = $this-> | ||
| - | if (!$mgr || !$tbl || $this-> | ||
| - | |||
| - | // Use raw table name (resolved already in fetchTableName) | ||
| - | $srcSpec = $tbl; | ||
| - | |||
| - | // Remove old outbound edges | ||
| - | $mgr-> | ||
| - | |||
| - | // Recreate outbound edges | ||
| - | foreach ($this-> | ||
| - | $mgr-> | ||
| - | [' | ||
| - | $edge[' | ||
| - | [ | ||
| - | ' | ||
| - | ' | ||
| - | // Pass-through: | ||
| - | ' | ||
| - | ], | ||
| - | $edge[' | ||
| - | 1 | ||
| - | ); | ||
| - | } | ||
| - | } | ||
| - | ``` | ||
| - | |||
| - | And the minimal `edgesFromSelf()` update: | ||
| - | |||
| - | ``` | ||
| - | public function edgesFromSelf(): | ||
| - | { | ||
| - | $edges = []; | ||
| - | foreach ($this-> | ||
| - | $raw = $this-> | ||
| - | if ($raw === null || $raw === '' | ||
| - | |||
| - | $edges[] = [ | ||
| - | ' | ||
| - | ' | ||
| - | ' | ||
| - | ' | ||
| - | ' | ||
| - | ]; | ||
| - | } | ||
| - | return $edges; | ||
| - | } | ||
| - | ``` | ||
| - | |||
| - | --- | ||
| - | |||
| - | 10) Worked examples | ||
| - | ------------------- | ||
| - | 1) **Delete a User who owns invoices (owner_user_id)** | ||
| - | | ||
| - | | ||
| - | |||
| - | 2) **Delete a Partner referenced by invoices** | ||
| - | | ||
| - | | ||
| - | |||
| - | 3) **Delete an Invoice that has lines** | ||
| - | | ||
| - | | ||
| - | |||
| - | 4) **Delete an Account referenced by invoice lines** | ||
| - | | ||
| - | | ||
| - | |||
| - | 5) **Delete an InvoiceLine** | ||
| - | With default `' | ||
| - | |||
| - | 6) **DETACH-only scenario** | ||
| - | If an inbound relation is DETACH, deletion removes the edge row, data stays untouched. | ||
| - | |||
| - | 7) **Partner unique key on Invoice** | ||
| - | - If `edgesMap[' | ||
| - | - If omitted: the edge stores the **string** `NVG-2025-…` directly as `dst_id` (schema must allow strings). | ||
| - | |||
| - | --- | ||
| - | |||
| - | 11) Tips | ||
| - | -------- | ||
| - | - Always call `_destroyMySelf()` to delete. It’s policy-aware. | ||
| - | - Keep `edgesMap` minimal and meaningful. | ||
| - | - Prefer **NULLIFY** for optional FKs that can be cleared. | ||
| - | - Use **CASCADE** sparingly and deliberately (e.g., Invoice → InvoiceLine). | ||
| - | - **RESTRICT** is a safe default when in doubt. | ||
| - | - Decide **one convention** per relation for `dst_id` (numeric vs string) and stick to it; if you need numeric, add `resolve_by`. | ||
| - | |||
| - | --- | ||
| - | |||
| - | 12) Quick migration checklist | ||
| - | ----------------------------- | ||
| - | - If you will store string `dst_id` values: | ||
| - | `ALTER TABLE consistency_edges MODIFY dst_id VARCHAR(128) NOT NULL;` | ||
| - | - (Optional) Add an **edge UID** to meta via registry `uid` templates (no schema change). | ||
| - | - Run CLI reindex to rebuild edges from the new **registry**: | ||
| - | - One table: `php bin/ | ||
| - | - All: `php bin/ | ||
| - | - Verify deletion flows through `_destroyMySelf()` against your policy map. | ||
start.1762875916.txt.gz · Last modified: by admin
