# Data Model: User Profile Dashboard Filter

## Overview

This model defines persistent and transient entities needed to:

1. store per-user dashboard filter preferences,
2. support Superset account lookup by selected environment during profile binding,
3. apply deterministic dashboard filtering on the main dashboards list page.

---

## 1) UserDashboardPreference (persistent)

**Purpose**: Stores the authenticated user’s saved profile settings for dashboard filtering.

### Fields

- `preference_id` (string/uuid, required, unique)
- `user_id` (string, required, unique, FK -> `users.id`)
- `superset_username` (string, optional)
- `superset_username_normalized` (string, optional)
- `show_only_my_dashboards` (boolean, required, default `false`)
- `created_at` (datetime, required)
- `updated_at` (datetime, required)

### Validation Rules

- `user_id` must be unique (one preference record per user).
- If `show_only_my_dashboards = true`, `superset_username` must be non-empty and valid.
- `superset_username_normalized` must be `trim(lower(superset_username))` when username exists.
- A user can mutate only their own preference record.

### Lifecycle Notes

- `unconfigured` -> `configured_disabled` (username optional, toggle off)
- `configured_disabled` -> `configured_enabled` (valid username + toggle on)
- `configured_enabled` -> `configured_disabled` (toggle off, username may be retained)

---

## 2) SupersetAccountLookupRequest (transient)

**Purpose**: Represents a profile-page request to fetch account candidates from a selected Superset environment.

### Fields

- `requester_user_id` (string, required)
- `environment_id` (string, required)
- `search` (string, optional)
- `page_index` (integer, required, default `0`, min `0`)
- `page_size` (integer, required, default `20`, min `1`, max `100`)
- `sort_column` (enum, required, default `username`)  
  Allowed: `username`, `first_name`, `last_name`, `email`
- `sort_order` (enum, required, default `desc`)  
  Allowed: `asc`, `desc`

### Validation Rules

- `requester_user_id` must be authenticated user identity.
- `environment_id` must exist in configured environments.
- Pagination and sort values must respect allowed bounds/enums.

### Integration Note

Backend may translate these fields into Superset-compatible query style (including `pageIndex`, `sortColumn`, `sortOrder`) when contacting selected environment.

---

## 3) SupersetAccountCandidate (transient)

**Purpose**: Canonical account option returned to frontend from selected Superset environment.

### Fields

- `environment_id` (string, required)
- `username` (string, required)
- `display_name` (string, optional)
- `email` (string, optional)
- `is_active` (boolean, optional)

### Validation Rules

- `username` must be non-empty.
- Candidate list should be deduplicated by normalized username per environment response.
- Payload must remain stable even if upstream Superset shape differs.

---

## 4) DashboardActorProjection (derived, transient)

**Purpose**: Normalized actor fields used for deterministic filter matching.

### Fields

- `dashboard_id` (integer, required)
- `owners_tokens` (array[string], required)
- `modified_by_token` (string, optional)
- `match_reason` (enum, required)  
  Allowed: `owners`, `modified_by`, `none`

### Validation Rules

- `owners_tokens` must contain trimmed unique non-empty tokens.
- `modified_by_token` must be trimmed when present.
- Matching uses case-insensitive compare against `superset_username_normalized`.

---

## 5) DashboardProfileFilterContext (transient)

**Purpose**: Carries effective profile-filter state for dashboards list response.

### Fields

- `user_id` (string, required)
- `apply_profile_default` (boolean, required)
- `override_show_all` (boolean, required)
- `effective_filter_applied` (boolean, required)
- `effective_username` (string, optional)
- `source_page` (enum, required)  
  Allowed: `dashboards_main`, `other`

### Validation Rules

- Auto-apply is valid only when `source_page = dashboards_main`.
- If `override_show_all = true`, `effective_filter_applied` must be `false`.
- If preference toggle is disabled, `effective_filter_applied` must be `false`.

---

## 6) ProfileSaveResult (transient)

**Purpose**: Normalized save response used by profile page UX feedback.

### Fields

- `status` (enum, required)  
  Allowed: `success`, `error`
- `message` (string, optional)
- `validation_errors` (array[string], optional)
- `saved_preference` (`UserDashboardPreference`, optional)

### Validation Rules

- `saved_preference` present only for successful save.
- `validation_errors` present only for invalid input scenarios.

---

## Relationships

1. `User` 1 — 1 `UserDashboardPreference`
2. `Environment` 1 — N `SupersetAccountLookupRequest` (runtime)
3. `SupersetAccountLookupRequest` 1 — N `SupersetAccountCandidate` (runtime)
4. `UserDashboardPreference` + `DashboardActorProjection` -> filtered dashboard list projection
5. `DashboardProfileFilterContext` decorates dashboards response behavior/state

---

## State Model Highlights

### Profile Binding Flow

`idle -> environment_selected -> lookup_loading -> lookup_loaded|lookup_failed -> save_loading -> save_success|save_error`

### Dashboards Filter Flow (main list page)

`default_apply -> active_filtered -> temporary_show_all -> leave_page -> default_apply_restored`

---

## Data Consistency & Security Invariants

- Preference mutations are always scoped to authenticated user identity.
- Bound username normalization is deterministic and identical across save and match paths.
- Temporary "show all" override does not mutate saved preference.
- Account lookup errors never force data loss; manual username fallback remains available.