Skip to content

Databázové schema

PostgreSQL 16 databáze s 17 tabulkami. Schema je definováno v sql/init.sql. TypeORM entity jsou v src/entities/.

Přehled tabulek

┌──────────────────────────────────────────────────────────────────┐
│                         DATABÁZOVÉ SCHEMA                        │
├──────────────────┬───────────────────────────────────────────────┤
│ Uživatelé        │ users, super_admins, app_admins               │
│ Aplikace         │ applications                                   │
│ Oprávnění        │ permissions, roles, role_permissions           │
│ Přiřazení        │ user_app_roles, user_resource_permissions      │
│ Profily          │ user_profiles, user_app_preferences           │
│ Notifikace       │ notifications, notification_types,            │
│                  │ notification_templates,                        │
│                  │ user_notification_preferences                  │
│ Push             │ push_subscriptions                             │
│ Brandy           │ brands                                         │
└──────────────────┴───────────────────────────────────────────────┘

Tabulka users — registr uživatelů

Centrální registr všech uživatelů. Email je primární klíč.

sql
CREATE TABLE users (
  email      VARCHAR PRIMARY KEY,
  active     BOOLEAN NOT NULL DEFAULT TRUE,
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
SloupecTypPopis
emailPKPrimární identifikátor
activebooleanAktivní/deaktivovaný účet
created_attimestampDatum registrace

Uživatelé se vytváří automaticky (lazy) při prvním přiřazení role nebo oprávnění.


Tabulka applications

sql
CREATE TABLE applications (
  id          SERIAL PRIMARY KEY,
  code        VARCHAR UNIQUE NOT NULL,
  name        VARCHAR NOT NULL,
  description TEXT,
  created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

Tabulka permissions — definice oprávnění

sql
CREATE TABLE permissions (
  id                   SERIAL PRIMARY KEY,
  application_id       INT NOT NULL REFERENCES applications(id) ON DELETE CASCADE,
  code                 VARCHAR NOT NULL,
  description          TEXT,
  type                 VARCHAR NOT NULL CHECK (type IN ('binary', 'tiered')),
  parent_permission_id INT REFERENCES permissions(id) ON DELETE SET NULL,
  group_name           VARCHAR,
  created_at           TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  UNIQUE (application_id, code)
);
SloupecPopis
codeUnikátní kód v rámci aplikace
typebinary nebo tiered
parent_permission_idSelf-reference pro UI tree
group_nameSkupina pro UI groupování

Tabulka roles

sql
CREATE TABLE roles (
  id             SERIAL PRIMARY KEY,
  application_id INT NOT NULL REFERENCES applications(id) ON DELETE CASCADE,
  code           VARCHAR NOT NULL,
  description    TEXT,
  mdi_icon       VARCHAR,
  created_at     TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  UNIQUE (application_id, code)
);

Tabulka role_permissions — M:N role ↔ oprávnění

sql
CREATE TABLE role_permissions (
  role_id        INT NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
  permission_id  INT NOT NULL REFERENCES permissions(id) ON DELETE CASCADE,
  access_level   VARCHAR NOT NULL CHECK (access_level IN ('allowed', 'view', 'edit')),
  PRIMARY KEY (role_id, permission_id)
);

Compound PK — každá role může mít každé oprávnění nejvýše jednou.


Tabulka user_app_roles — přiřazení rolí uživatelům

sql
CREATE TABLE user_app_roles (
  id             SERIAL PRIMARY KEY,
  email          VARCHAR NOT NULL REFERENCES users(email) ON DELETE CASCADE,
  application_id INT NOT NULL REFERENCES applications(id) ON DELETE CASCADE,
  role_id        INT NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
  created_at     TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  UNIQUE (email, application_id, role_id)
);

CREATE INDEX idx_user_app_roles_email ON user_app_roles(email);
CREATE INDEX idx_user_app_roles_app ON user_app_roles(application_id);

Tabulka user_resource_permissions — resource-level overrides

sql
CREATE TABLE user_resource_permissions (
  id             SERIAL PRIMARY KEY,
  email          VARCHAR NOT NULL REFERENCES users(email) ON DELETE CASCADE,
  application_id INT NOT NULL REFERENCES applications(id) ON DELETE CASCADE,
  resource_type  VARCHAR NOT NULL,
  resource_id    VARCHAR NOT NULL,
  permission_id  INT NOT NULL REFERENCES permissions(id) ON DELETE CASCADE,
  granted        BOOLEAN NOT NULL,
  created_at     TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  UNIQUE (email, application_id, resource_type, resource_id, permission_id)
);

Tabulky app_admins a super_admins

sql
CREATE TABLE super_admins (
  id         SERIAL PRIMARY KEY,
  email      VARCHAR UNIQUE NOT NULL REFERENCES users(email) ON DELETE CASCADE,
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE app_admins (
  id             SERIAL PRIMARY KEY,
  email          VARCHAR NOT NULL REFERENCES users(email) ON DELETE CASCADE,
  application_id INT NOT NULL REFERENCES applications(id) ON DELETE CASCADE,
  created_at     TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  UNIQUE (email, application_id)
);

Tabulka user_profiles

sql
CREATE TABLE user_profiles (
  id           SERIAL PRIMARY KEY,
  email        VARCHAR UNIQUE NOT NULL,
  display_name VARCHAR,
  avatar_url   TEXT,
  locale       VARCHAR NOT NULL DEFAULT 'cs',
  theme        VARCHAR NOT NULL DEFAULT 'light' CHECK (theme IN ('light', 'dark', 'system')),
  brand        VARCHAR NOT NULL DEFAULT 'atrea',
  created_at   TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at   TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

Tabulka user_app_preferences

sql
CREATE TABLE user_app_preferences (
  id                     SERIAL PRIMARY KEY,
  user_profile_id        INT NOT NULL REFERENCES user_profiles(id) ON DELETE CASCADE,
  application_id         INT NOT NULL REFERENCES applications(id) ON DELETE CASCADE,
  show_help              BOOLEAN NOT NULL DEFAULT TRUE,
  notifications_enabled  BOOLEAN NOT NULL DEFAULT TRUE,
  created_at             TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at             TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  UNIQUE (user_profile_id, application_id)
);

Tabulky notifikací

notification_types

sql
CREATE TABLE notification_types (
  id               SERIAL PRIMARY KEY,
  application_id   INT NOT NULL REFERENCES applications(id) ON DELETE CASCADE,
  code             VARCHAR NOT NULL,
  name             VARCHAR NOT NULL,
  description      TEXT,
  email_enabled    BOOLEAN NOT NULL DEFAULT TRUE,
  push_enabled     BOOLEAN NOT NULL DEFAULT FALSE,
  user_can_disable BOOLEAN NOT NULL DEFAULT TRUE,
  default_email    BOOLEAN NOT NULL DEFAULT TRUE,
  default_push     BOOLEAN NOT NULL DEFAULT FALSE,
  created_at       TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at       TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  UNIQUE (application_id, code)
);

notification_templates

sql
CREATE TABLE notification_templates (
  id               SERIAL PRIMARY KEY,
  application_id   INT NOT NULL REFERENCES applications(id) ON DELETE CASCADE,
  type             VARCHAR NOT NULL,
  locale           VARCHAR NOT NULL,
  subject_template TEXT NOT NULL,
  body_template    TEXT NOT NULL,
  description      TEXT,
  created_at       TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at       TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  UNIQUE (application_id, type, locale)
);

notifications — audit log

sql
CREATE TABLE notifications (
  id              SERIAL PRIMARY KEY,
  recipient_email VARCHAR NOT NULL,
  application_id  INT REFERENCES applications(id) ON DELETE SET NULL,
  type            VARCHAR NOT NULL,
  subject         VARCHAR,
  status          VARCHAR NOT NULL CHECK (status IN ('sent', 'failed', 'skipped')),
  status_reason   TEXT,
  locale          VARCHAR,
  payload         JSONB,
  created_at      TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX idx_notifications_recipient ON notifications(recipient_email, application_id, created_at);

user_notification_preferences

sql
CREATE TABLE user_notification_preferences (
  id                   SERIAL PRIMARY KEY,
  user_profile_id      INT NOT NULL REFERENCES user_profiles(id) ON DELETE CASCADE,
  notification_type_id INT NOT NULL REFERENCES notification_types(id) ON DELETE CASCADE,
  email                BOOLEAN NOT NULL DEFAULT TRUE,
  push                 BOOLEAN NOT NULL DEFAULT FALSE,
  created_at           TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at           TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  UNIQUE (user_profile_id, notification_type_id)
);

Tabulka push_subscriptions

sql
CREATE TABLE push_subscriptions (
  id              SERIAL PRIMARY KEY,
  user_profile_id INT NOT NULL REFERENCES user_profiles(id) ON DELETE CASCADE,
  endpoint        TEXT UNIQUE NOT NULL,
  key_p256dh      TEXT NOT NULL,
  key_auth        TEXT NOT NULL,
  device_label    VARCHAR,
  created_at      TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at      TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX idx_push_subscriptions_user ON push_subscriptions(user_profile_id);

Tabulka brands

sql
CREATE TABLE brands (
  id            SERIAL PRIMARY KEY,
  slug          VARCHAR UNIQUE NOT NULL,
  name          VARCHAR NOT NULL,
  primary_color VARCHAR NOT NULL,
  primary_dark  VARCHAR NOT NULL,
  background    VARCHAR DEFAULT '#FFFFFF',
  font_color    VARCHAR DEFAULT '#212121',
  link_color    VARCHAR NOT NULL,
  logo_url      TEXT NOT NULL,
  footer_text   TEXT,
  email_from    VARCHAR NOT NULL,
  is_default    BOOLEAN NOT NULL DEFAULT FALSE,
  created_at    TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at    TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

Seed data (brands)

sql
INSERT INTO brands (slug, name, primary_color, primary_dark, link_color, logo_url, email_from, is_default)
VALUES
  ('atrea', 'Atrea', '#1976D2', '#1565C0', '#1976D2', '/assets/img/atrea/logo.svg', 'noreply@atrea.eu', TRUE),
  ('vallox', 'Vallox', '#E53935', '#C62828', '#E53935', '/assets/img/vallox/logo.svg', 'noreply@vallox.cz', FALSE),
  ('airflow', 'Airflow', '#2E7D32', '#1B5E20', '#2E7D32', '/assets/img/airflow/logo.svg', 'noreply@airflow.cz', FALSE);

ER diagram (zjednodušený)

applications ──────────────────────────────────────────────┐
    │                                                       │
    ├── permissions (application_id FK)                     │
    │       └── role_permissions (permission_id FK)         │
    │                   └── roles (role_id FK) ─────────────┤
    │                                                       │
    ├── user_app_roles (application_id FK)                  │
    │       └── users (email FK) ◄──────────────────────────┤
    │               └── super_admins                        │
    │               └── app_admins (application_id FK) ─────┘
    │               └── user_resource_permissions
    │               └── user_profiles
    │                       └── user_app_preferences
    │                       └── user_notification_preferences
    │                       └── push_subscriptions

    ├── notification_types (application_id FK)
    │       └── notification_templates
    │       └── user_notification_preferences (notification_type_id FK)

    └── notifications (application_id FK)

brands (nezávislá tabulka — odkazována z user_profiles.brand jako slug)

Inicializace databáze

bash
# Vytvoření tabulek
psql -h localhost -U app -d atrea-user-db < sql/init.sql

# Seed data (brandy)
psql -h localhost -U app -d atrea-user-db < sql/data.sql

# Reset databáze (POZOR — smaže všechna data!)
psql -h localhost -U app -d atrea-user-db < sql/drop.sql

Atrea User API — interní dokumentace