# Personal Dashboard Rollout ## Table: `user_tag_dashboards` Purpose: capture per-user widget selections and configuration for upcoming personal dashboards. One row represents a single widget/tag on a personal page. | Column | Type | Notes | | --- | --- | --- | | `id` | INT UNSIGNED PK | Auto-increment identifier. | | `user_id` | INT | References `members.member_id`; cascades on delete/update. | | `dashboard_key` | VARCHAR(64) | Allows multiple saved pages per user (e.g., `default`, `boilers`, `lab`). | | `widget_type` | VARCHAR(32) | `trend`, `stat`, `gauge`, etc. Defaults to `trend`. | | `panel_size` | VARCHAR(16) | Layout hint (`full`, `half`, `card`). | | `position_index` | SMALLINT UNSIGNED | Zero-based ordering for rendering widgets. | | `tag_name` | VARCHAR(255) | Historian/OPC tag identifier. | | `display_label` | VARCHAR(255) | Optional friendly label shown on the UI. | | `series_color` | VARCHAR(32) | Optional color override (hex/RGB). | | `preferred_axis` | VARCHAR(16) | Left/right axis preference for trend widgets. | | `update_interval_ms` | INT UNSIGNED | Polling cadence in milliseconds (default 5000). | | `time_window_minutes` | SMALLINT UNSIGNED | Historical span for trend charts (default 180). | | `rollup_function` | VARCHAR(16) | Server-side aggregation hint (`raw`, `avg`, `min`, `max`, `sum`, `delta`). | | `scale_min` / `scale_max` | DECIMAL(14,4) | Optional manual bounds for chart scaling. | | `threshold_low` / `threshold_high` | DECIMAL(14,4) | Alert thresholds for future highlighting. | | `is_active` | TINYINT(1) | Soft delete flag; inactive rows stay archived. | | `config_json` | LONGTEXT | Free-form JSON for extended configuration (annotations, alert styles, etc.). | | `last_viewed_at` | DATETIME | Updated when a user loads the dashboard. | | `created_at` / `updated_at` | TIMESTAMP | Audit columns managed by MySQL. | ### Indexing - `uniq_user_dashboard_tag` ensures each user/dashboard/widget/tag combo is unique. - `idx_user_dashboard` supports fast lookups while rendering the personal page. > **FK note:** the `user_id` column is left signed (no `UNSIGNED`) so it matches the existing `members.member_id` definition in production. MySQL requires the parent and child column types to be identical (size and sign) for foreign keys to succeed. ### Seed Checklist 1. Run `sql/create_user_tag_dashboards.sql` in the LASUCA MySQL schema. 2. Insert starter rows for the pilot account (use your `members.member_id`). 3. Verify `SELECT * FROM user_tag_dashboards WHERE user_id = ?;` returns the seeded tags. ### Implemented - Read endpoint: `data/personal/get_user_tags.php` returns active rows for the authenticated user and accepts an optional `dashboard` query parameter (defaults to `default`). - Prototype personal page: `personal/dashboard.php` renders saved widgets, surfaces metadata, and links out to the live trend view. ## Table: `dashboard_row_catalog` Purpose: master reference of displayable rows (friendly labels, units, rendering hints) that users can pin to their personal dashboard. | Column | Type | Notes | | --- | --- | --- | | `id` | INT UNSIGNED PK | Auto-increment identifier. | | `row_key` | VARCHAR(64) | Stable identifier used by code/user selections. Unique. | | `friendly_name` | VARCHAR(255) | Picker label shown to users. | | `source_type` | VARCHAR(32) | Data origin (`historian`, `mysql`, `computed`, etc.). | | `source_id` | VARCHAR(128) | Identifier consumed by the source system (historian ID, OPC tag, etc.). | | `unit` | VARCHAR(32) | Unit of measure (psi, %, °F, rpm, etc.). | | `is_level_indicator` | TINYINT(1) | `1` = render with a level indicator/UI instead of plain numeric output. | | `value_precision` | TINYINT UNSIGNED | Optional decimal precision hint. | | `display_template` | VARCHAR(128) | Optional PHP include or template key for rendering the row. | | `requires_include` | VARCHAR(128) | Name of prerequisite include (e.g., `items.php`). | | `sort_order` | SMALLINT UNSIGNED | Default order when listing catalog entries. | | `metadata_json` | LONGTEXT | Extra configuration (thresholds, grouping, color hints). | | `created_at` / `updated_at` | TIMESTAMP | Audit columns managed by MySQL. | Seed checklist mirrors the prior pattern: 1. Run `sql/create_dashboard_row_catalog.sql` in the LASUCA MySQL schema. 2. Insert catalog rows for each displayable metric (include unit/level flag). 3. Verify lookups via `SELECT * FROM dashboard_row_catalog ORDER BY sort_order, friendly_name;`. ### Next Steps - Prototype a personal dashboard page that hydrates from the endpoint and renders the tags in slot order. - Build write endpoints/UI for managing selections, expose threshold alerts, and support multiple dashboards via `dashboard_key`.