Version 1.0.0 | CRM(広告代理店向け)
tenant_id カラム方式(全テーブル共通)。RLS ポリシーを PostgreSQL 側で併用。id) を採用。id, tenant_id, created_at, updated_at, deleted_at(論理削除)。{参照先テーブル単数形}_id。| # | テーブル名 | 対応機能 | 概要 |
|---|---|---|---|
| 1 | tenants | F14 | テナント(代理店) |
| 2 | users | F14 | ユーザー |
| 3 | roles | F14 | ロール定義 |
| 4 | permissions | F14 | 権限定義 |
| 5 | role_permissions | F14 | ロール×権限 |
| 6 | user_roles | F14 | ユーザー×ロール |
| 7 | organization_units | F14 | 組織階層 |
| 8 | clients | F01 | クライアント企業 |
| 9 | client_contacts | F01 | クライアント担当者 |
| 10 | client_health_scores | F01 | 健全性スコア履歴 |
| 11 | contracts | F08 | 契約 |
| 12 | insertion_orders | F08 | IO(挿入注文) |
| 13 | invoices | F08 | 請求書 |
| 14 | invoice_line_items | F08 | 請求書明細 |
| 15 | campaigns | F02/F03 | キャンペーン |
| 16 | media_platforms | F03 | 媒体マスタ |
| 17 | media_plans | F03 | メディアプラン |
| 18 | media_plan_items | F03 | メディアプラン明細(媒体別予算配分) |
| 19 | budget_pacing | F03 | 予算ペーシング日次実績 |
| 20 | ad_performance_daily | F02 | 広告パフォーマンス日次データ |
| 21 | kpi_targets | F02 | KPI 目標値 |
| 22 | creatives | F04 | クリエイティブ素材 |
| 23 | creative_versions | F04 | クリエイティブバージョン |
| 24 | approval_workflows | F04 | 承認ワークフロー定義 |
| 25 | approval_steps | F04 | 承認ステップ |
| 26 | approval_requests | F04 | 承認リクエスト |
| 27 | approval_actions | F04 | 承認アクション履歴 |
| 28 | agency_fees | F05 | 代理店手数料 |
| 29 | revenue_entries | F05 | 収益エントリ |
| 30 | projects | F07 | プロジェクト |
| 31 | tasks | F07 | タスク |
| 32 | task_comments | F07 | タスクコメント |
| 33 | report_configs | F06 | レポート設定 |
| 34 | report_schedules | F06 | レポート配信スケジュール |
| 35 | report_executions | F06 | レポート実行履歴 |
| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| id | UUID | PK, DEFAULT gen_random_uuid() | |
| name | VARCHAR(255) | NOT NULL | 代理店名 |
| slug | VARCHAR(100) | NOT NULL, UNIQUE | URL識別子 |
| plan | VARCHAR(50) | NOT NULL, DEFAULT 'standard' | 契約プラン |
| settings | JSONB | DEFAULT '{}' | テナント設定 |
| is_active | BOOLEAN | NOT NULL, DEFAULT true | |
| created_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() | |
| updated_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() |
インデックス: idx_tenants_slug ON (slug)
| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| id | UUID | PK | |
| tenant_id | UUID | NOT NULL, FK → tenants.id | |
| organization_unit_id | UUID | FK → organization_units.id | 所属部署 |
| VARCHAR(255) | NOT NULL | ||
| password_hash | VARCHAR(255) | NOT NULL | |
| first_name | VARCHAR(100) | NOT NULL | |
| last_name | VARCHAR(100) | NOT NULL | |
| avatar_url | TEXT | ||
| is_active | BOOLEAN | NOT NULL, DEFAULT true | |
| last_login_at | TIMESTAMPTZ | ||
| created_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() | |
| updated_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() | |
| deleted_at | TIMESTAMPTZ | 論理削除 |
インデックス:
idx_users_tenant_email UNIQUE ON (tenant_id, email)idx_users_tenant_id ON (tenant_id)idx_users_org_unit ON (organization_unit_id)| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| id | UUID | PK | |
| tenant_id | UUID | NOT NULL, FK → tenants.id | |
| name | VARCHAR(100) | NOT NULL | 例: admin, manager, member |
| description | TEXT | ||
| is_system | BOOLEAN | NOT NULL, DEFAULT false | システム定義ロール |
| created_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() | |
| updated_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() |
インデックス: idx_roles_tenant_name UNIQUE ON (tenant_id, name)
| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| id | UUID | PK | |
| resource | VARCHAR(100) | NOT NULL | 例: clients, campaigns |
| action | VARCHAR(50) | NOT NULL | 例: read, write, delete |
| description | TEXT |
インデックス: idx_permissions_resource_action UNIQUE ON (resource, action)
| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| role_id | UUID | PK(複合), FK → roles.id | |
| permission_id | UUID | PK(複合), FK → permissions.id |
| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| user_id | UUID | PK(複合), FK → users.id | |
| role_id | UUID | PK(複合), FK → roles.id | |
| assigned_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() |
| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| id | UUID | PK | |
| tenant_id | UUID | NOT NULL, FK → tenants.id | |
| parent_id | UUID | FK → organization_units.id | 親部署(NULLならルート) |
| name | VARCHAR(255) | NOT NULL | 部署名 |
| level | INT | NOT NULL, DEFAULT 0 | 階層レベル |
| sort_order | INT | NOT NULL, DEFAULT 0 | 表示順 |
| created_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() | |
| updated_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() |
インデックス:
idx_org_units_tenant_parent ON (tenant_id, parent_id)| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| id | UUID | PK | |
| tenant_id | UUID | NOT NULL, FK → tenants.id | |
| name | VARCHAR(255) | NOT NULL | 企業名 |
| industry | VARCHAR(100) | 業種 | |
| website | TEXT | ||
| phone | VARCHAR(50) | ||
| address | TEXT | ||
| account_manager_id | UUID | FK → users.id | 担当AM |
| status | VARCHAR(30) | NOT NULL, DEFAULT 'active' | active/churned/prospect |
| tier | VARCHAR(20) | DEFAULT 'standard' | premium/standard/small |
| notes | TEXT | ||
| created_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() | |
| updated_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() | |
| deleted_at | TIMESTAMPTZ |
インデックス:
idx_clients_tenant_id ON (tenant_id)idx_clients_tenant_status ON (tenant_id, status)idx_clients_account_manager ON (account_manager_id)| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| id | UUID | PK | |
| tenant_id | UUID | NOT NULL, FK → tenants.id | |
| client_id | UUID | NOT NULL, FK → clients.id | |
| first_name | VARCHAR(100) | NOT NULL | |
| last_name | VARCHAR(100) | NOT NULL | |
| VARCHAR(255) | |||
| phone | VARCHAR(50) | ||
| job_title | VARCHAR(150) | 役職 | |
| is_primary | BOOLEAN | NOT NULL, DEFAULT false | 主担当フラグ |
| created_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() | |
| updated_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() | |
| deleted_at | TIMESTAMPTZ |
インデックス:
idx_client_contacts_client ON (tenant_id, client_id)| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| id | UUID | PK | |
| tenant_id | UUID | NOT NULL, FK → tenants.id | |
| client_id | UUID | NOT NULL, FK → clients.id | |
| score | INT | NOT NULL, CHECK(score BETWEEN 0 AND 100) | 0-100 |
| dimension_scores | JSONB | DEFAULT '{}' | 各観点別スコア |
| calculated_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() | 算出日時 |
| notes | TEXT |
インデックス:
idx_health_scores_client_date ON (tenant_id, client_id, calculated_at DESC)| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| id | UUID | PK | |
| tenant_id | UUID | NOT NULL, FK → tenants.id | |
| client_id | UUID | NOT NULL, FK → clients.id | |
| contract_number | VARCHAR(50) | NOT NULL | 契約番号 |
| title | VARCHAR(255) | NOT NULL | |
| status | VARCHAR(30) | NOT NULL, DEFAULT 'draft' | draft/active/expired/terminated |
| start_date | DATE | NOT NULL | |
| end_date | DATE | NOT NULL | |
| auto_renew | BOOLEAN | NOT NULL, DEFAULT false | |
| total_value | DECIMAL(15,2) | 契約総額 | |
| currency | VARCHAR(3) | NOT NULL, DEFAULT 'JPY' | |
| payment_terms | VARCHAR(100) | 支払条件(例: NET30) | |
| terms_and_conditions | TEXT | 契約条件 | |
| signed_at | TIMESTAMPTZ | 署名日時 | |
| created_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() | |
| updated_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() | |
| deleted_at | TIMESTAMPTZ |
インデックス:
idx_contracts_tenant_client ON (tenant_id, client_id)idx_contracts_number UNIQUE ON (tenant_id, contract_number)idx_contracts_status ON (tenant_id, status)| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| id | UUID | PK | |
| tenant_id | UUID | NOT NULL, FK → tenants.id | |
| contract_id | UUID | NOT NULL, FK → contracts.id | |
| io_number | VARCHAR(50) | NOT NULL | IO番号 |
| title | VARCHAR(255) | NOT NULL | |
| status | VARCHAR(30) | NOT NULL, DEFAULT 'draft' | draft/approved/active/completed |
| start_date | DATE | NOT NULL | |
| end_date | DATE | NOT NULL | |
| total_budget | DECIMAL(15,2) | NOT NULL | 総予算 |
| currency | VARCHAR(3) | NOT NULL, DEFAULT 'JPY' | |
| approved_by_id | UUID | FK → users.id | |
| approved_at | TIMESTAMPTZ | ||
| created_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() | |
| updated_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() |
インデックス:
idx_io_tenant_contract ON (tenant_id, contract_id)idx_io_number UNIQUE ON (tenant_id, io_number)| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| id | UUID | PK | |
| tenant_id | UUID | NOT NULL, FK → tenants.id | |
| client_id | UUID | NOT NULL, FK → clients.id | |
| contract_id | UUID | FK → contracts.id | |
| invoice_number | VARCHAR(50) | NOT NULL | |
| status | VARCHAR(30) | NOT NULL, DEFAULT 'draft' | draft/sent/paid/overdue/void |
| issue_date | DATE | NOT NULL | |
| due_date | DATE | NOT NULL | |
| subtotal | DECIMAL(15,2) | NOT NULL | 小計 |
| tax_rate | DECIMAL(5,4) | NOT NULL, DEFAULT 0.10 | 税率 |
| tax_amount | DECIMAL(15,2) | NOT NULL | 税額 |
| total_amount | DECIMAL(15,2) | NOT NULL | 合計 |
| currency | VARCHAR(3) | NOT NULL, DEFAULT 'JPY' | |
| paid_at | TIMESTAMPTZ | 入金日 | |
| notes | TEXT | ||
| created_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() | |
| updated_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() |
インデックス:
idx_invoices_tenant_client ON (tenant_id, client_id)idx_invoices_number UNIQUE ON (tenant_id, invoice_number)idx_invoices_status ON (tenant_id, status)idx_invoices_due_date ON (tenant_id, due_date) WHERE status != 'paid'| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| id | UUID | PK | |
| tenant_id | UUID | NOT NULL, FK → tenants.id | |
| invoice_id | UUID | NOT NULL, FK → invoices.id | |
| description | TEXT | NOT NULL | |
| quantity | DECIMAL(10,2) | NOT NULL, DEFAULT 1 | |
| unit_price | DECIMAL(15,2) | NOT NULL | |
| amount | DECIMAL(15,2) | NOT NULL | |
| campaign_id | UUID | FK → campaigns.id | 紐付けキャンペーン |
| sort_order | INT | NOT NULL, DEFAULT 0 |
インデックス:
idx_invoice_items_invoice ON (tenant_id, invoice_id)| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| id | UUID | PK | |
| tenant_id | UUID | NOT NULL, FK → tenants.id | |
| client_id | UUID | NOT NULL, FK → clients.id | |
| insertion_order_id | UUID | FK → insertion_orders.id | |
| name | VARCHAR(255) | NOT NULL | |
| status | VARCHAR(30) | NOT NULL, DEFAULT 'draft' | draft/active/paused/completed |
| objective | VARCHAR(100) | awareness/conversion/traffic等 | |
| start_date | DATE | NOT NULL | |
| end_date | DATE | NOT NULL | |
| total_budget | DECIMAL(15,2) | NOT NULL | |
| currency | VARCHAR(3) | NOT NULL, DEFAULT 'JPY' | |
| owner_id | UUID | FK → users.id | 運用担当者 |
| created_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() | |
| updated_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() | |
| deleted_at | TIMESTAMPTZ |
インデックス:
idx_campaigns_tenant_client ON (tenant_id, client_id)idx_campaigns_status ON (tenant_id, status)idx_campaigns_date_range ON (tenant_id, start_date, end_date)| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| id | UUID | PK | |
| name | VARCHAR(100) | NOT NULL, UNIQUE | Google Ads, Meta Ads, LINE等 |
| platform_type | VARCHAR(50) | NOT NULL | search/social/display/video |
| api_supported | BOOLEAN | NOT NULL, DEFAULT false | API連携可否 |
| is_active | BOOLEAN | NOT NULL, DEFAULT true | |
| created_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() |
※ テナント共通マスタ(tenant_id なし)
| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| id | UUID | PK | |
| tenant_id | UUID | NOT NULL, FK → tenants.id | |
| campaign_id | UUID | NOT NULL, FK → campaigns.id | |
| name | VARCHAR(255) | NOT NULL | |
| version | INT | NOT NULL, DEFAULT 1 | プランバージョン |
| status | VARCHAR(30) | NOT NULL, DEFAULT 'draft' | draft/approved/active |
| total_budget | DECIMAL(15,2) | NOT NULL | |
| currency | VARCHAR(3) | NOT NULL, DEFAULT 'JPY' | |
| approved_by_id | UUID | FK → users.id | |
| approved_at | TIMESTAMPTZ | ||
| created_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() | |
| updated_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() |
インデックス:
idx_media_plans_campaign ON (tenant_id, campaign_id)| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| id | UUID | PK | |
| tenant_id | UUID | NOT NULL, FK → tenants.id | |
| media_plan_id | UUID | NOT NULL, FK → media_plans.id | |
| media_platform_id | UUID | NOT NULL, FK → media_platforms.id | |
| ad_format | VARCHAR(100) | 広告フォーマット | |
| allocated_budget | DECIMAL(15,2) | NOT NULL | 配分予算 |
| target_impressions | BIGINT | 目標imp | |
| target_clicks | BIGINT | 目標click | |
| target_conversions | BIGINT | 目標CV | |
| target_cpa | DECIMAL(15,2) | 目標CPA | |
| target_roas | DECIMAL(8,4) | 目標ROAS | |
| start_date | DATE | NOT NULL | |
| end_date | DATE | NOT NULL | |
| notes | TEXT |
インデックス:
idx_mpi_plan ON (tenant_id, media_plan_id)idx_mpi_platform ON (media_platform_id)| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| id | UUID | PK | |
| tenant_id | UUID | NOT NULL, FK → tenants.id | |
| campaign_id | UUID | NOT NULL, FK → campaigns.id | |
| media_platform_id | UUID | NOT NULL, FK → media_platforms.id | |
| date | DATE | NOT NULL | |
| planned_spend | DECIMAL(15,2) | NOT NULL | 計画消化額 |
| actual_spend | DECIMAL(15,2) | NOT NULL, DEFAULT 0 | 実績消化額 |
| cumulative_planned | DECIMAL(15,2) | NOT NULL | 計画累計 |
| cumulative_actual | DECIMAL(15,2) | NOT NULL, DEFAULT 0 | 実績累計 |
| pacing_ratio | DECIMAL(8,4) | 実績/計画 比率 |
インデックス:
idx_pacing_campaign_date UNIQUE ON (tenant_id, campaign_id, media_platform_id, date)| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| id | UUID | PK | |
| tenant_id | UUID | NOT NULL, FK → tenants.id | |
| campaign_id | UUID | NOT NULL, FK → campaigns.id | |
| media_platform_id | UUID | NOT NULL, FK → media_platforms.id | |
| date | DATE | NOT NULL | |
| impressions | BIGINT | NOT NULL, DEFAULT 0 | |
| clicks | BIGINT | NOT NULL, DEFAULT 0 | |
| conversions | BIGINT | NOT NULL, DEFAULT 0 | |
| spend | DECIMAL(15,2) | NOT NULL, DEFAULT 0 | 消化額 |
| revenue | DECIMAL(15,2) | NOT NULL, DEFAULT 0 | 売上(ROAS算出用) |
| video_views | BIGINT | DEFAULT 0 | |
| engagements | BIGINT | DEFAULT 0 | |
| extra_metrics | JSONB | DEFAULT '{}' | 媒体固有指標 |
算出KPI(ビューまたはアプリ側で計算):
インデックス:
idx_ad_perf_unique UNIQUE ON (tenant_id, campaign_id, media_platform_id, date)idx_ad_perf_date ON (tenant_id, date)idx_ad_perf_campaign ON (tenant_id, campaign_id, date)| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| id | UUID | PK | |
| tenant_id | UUID | NOT NULL, FK → tenants.id | |
| campaign_id | UUID | NOT NULL, FK → campaigns.id | |
| period_start | DATE | NOT NULL | 対象期間開始 |
| period_end | DATE | NOT NULL | 対象期間終了 |
| target_cpa | DECIMAL(15,2) | ||
| target_roas | DECIMAL(8,4) | ||
| target_ctr | DECIMAL(8,6) | ||
| target_cvr | DECIMAL(8,6) | ||
| target_spend | DECIMAL(15,2) | ||
| created_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() |
インデックス:
idx_kpi_targets_campaign ON (tenant_id, campaign_id)| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| id | UUID | PK | |
| tenant_id | UUID | NOT NULL, FK → tenants.id | |
| campaign_id | UUID | NOT NULL, FK → campaigns.id | |
| name | VARCHAR(255) | NOT NULL | |
| creative_type | VARCHAR(50) | NOT NULL | image/video/text/html |
| status | VARCHAR(30) | NOT NULL, DEFAULT 'draft' | draft/in_review/approved/rejected |
| current_version_id | UUID | FK → creative_versions.id | 最新バージョン |
| created_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() | |
| updated_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() | |
| deleted_at | TIMESTAMPTZ |
インデックス:
idx_creatives_campaign ON (tenant_id, campaign_id)idx_creatives_status ON (tenant_id, status)| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| id | UUID | PK | |
| tenant_id | UUID | NOT NULL, FK → tenants.id | |
| creative_id | UUID | NOT NULL, FK → creatives.id | |
| version_number | INT | NOT NULL | |
| file_url | TEXT | NOT NULL | ストレージURL |
| file_size_bytes | BIGINT | ||
| mime_type | VARCHAR(100) | ||
| width | INT | ||
| height | INT | ||
| duration_seconds | DECIMAL(8,2) | 動画の場合 | |
| headline | VARCHAR(255) | ||
| body_text | TEXT | ||
| metadata | JSONB | DEFAULT '{}' | |
| uploaded_by_id | UUID | NOT NULL, FK → users.id | |
| created_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() |
インデックス:
idx_cv_creative_version UNIQUE ON (tenant_id, creative_id, version_number)| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| id | UUID | PK | |
| tenant_id | UUID | NOT NULL, FK → tenants.id | |
| name | VARCHAR(255) | NOT NULL | |
| target_type | VARCHAR(50) | NOT NULL | creative/media_plan/io |
| is_active | BOOLEAN | NOT NULL, DEFAULT true | |
| created_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() | |
| updated_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() |
| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| id | UUID | PK | |
| tenant_id | UUID | NOT NULL, FK → tenants.id | |
| workflow_id | UUID | NOT NULL, FK → approval_workflows.id | |
| step_order | INT | NOT NULL | 順序 |
| approver_role_id | UUID | FK → roles.id | 承認ロール |
| approver_user_id | UUID | FK → users.id | 指名承認者 |
| is_required | BOOLEAN | NOT NULL, DEFAULT true |
インデックス:
idx_as_workflow_order UNIQUE ON (workflow_id, step_order)| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| id | UUID | PK | |
| tenant_id | UUID | NOT NULL, FK → tenants.id | |
| workflow_id | UUID | NOT NULL, FK → approval_workflows.id | |
| target_type | VARCHAR(50) | NOT NULL | creative_version/media_plan/io |
| target_id | UUID | NOT NULL | 対象レコードのID |
| status | VARCHAR(30) | NOT NULL, DEFAULT 'pending' | pending/approved/rejected/cancelled |
| requested_by_id | UUID | NOT NULL, FK → users.id | |
| current_step_order | INT | NOT NULL, DEFAULT 1 | |
| created_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() | |
| updated_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() |
インデックス:
idx_ar_target ON (tenant_id, target_type, target_id)idx_ar_status ON (tenant_id, status)| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| id | UUID | PK | |
| tenant_id | UUID | NOT NULL, FK → tenants.id | |
| approval_request_id | UUID | NOT NULL, FK → approval_requests.id | |
| step_id | UUID | NOT NULL, FK → approval_steps.id | |
| action | VARCHAR(30) | NOT NULL | approved/rejected/commented |
| comment | TEXT | ||
| acted_by_id | UUID | NOT NULL, FK → users.id | |
| acted_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() |
インデックス:
idx_aa_request ON (tenant_id, approval_request_id)| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| id | UUID | PK | |
| tenant_id | UUID | NOT NULL, FK → tenants.id | |
| client_id | UUID | NOT NULL, FK → clients.id | |
| contract_id | UUID | FK → contracts.id | |
| campaign_id | UUID | FK → campaigns.id | |
| fee_type | VARCHAR(50) | NOT NULL | margin_rate/fixed/performance |
| margin_rate | DECIMAL(5,4) | マージン率(例: 0.2000 = 20%) | |
| fixed_amount | DECIMAL(15,2) | 固定手数料 | |
| performance_threshold | JSONB | 成果報酬条件 | |
| effective_from | DATE | NOT NULL | |
| effective_to | DATE | ||
| currency | VARCHAR(3) | NOT NULL, DEFAULT 'JPY' | |
| created_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() | |
| updated_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() |
インデックス:
idx_af_client ON (tenant_id, client_id)idx_af_campaign ON (tenant_id, campaign_id)| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| id | UUID | PK | |
| tenant_id | UUID | NOT NULL, FK → tenants.id | |
| client_id | UUID | NOT NULL, FK → clients.id | |
| campaign_id | UUID | FK → campaigns.id | |
| period_year | INT | NOT NULL | |
| period_month | INT | NOT NULL, CHECK(1-12) | |
| gross_revenue | DECIMAL(15,2) | NOT NULL | 粗利益(媒体費込み) |
| media_cost | DECIMAL(15,2) | NOT NULL | 媒体原価 |
| agency_fee | DECIMAL(15,2) | NOT NULL | 代理店手数料 |
| other_costs | DECIMAL(15,2) | NOT NULL, DEFAULT 0 | その他原価 |
| net_profit | DECIMAL(15,2) | NOT NULL | 純利益 |
| currency | VARCHAR(3) | NOT NULL, DEFAULT 'JPY' | |
| created_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() | |
| updated_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() |
インデックス:
idx_re_client_period UNIQUE ON (tenant_id, client_id, campaign_id, period_year, period_month)idx_re_period ON (tenant_id, period_year, period_month)| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| id | UUID | PK | |
| tenant_id | UUID | NOT NULL, FK → tenants.id | |
| client_id | UUID | NOT NULL, FK → clients.id | |
| campaign_id | UUID | FK → campaigns.id | |
| name | VARCHAR(255) | NOT NULL | |
| description | TEXT | ||
| status | VARCHAR(30) | NOT NULL, DEFAULT 'active' | active/completed/on_hold/cancelled |
| start_date | DATE | ||
| due_date | DATE | ||
| owner_id | UUID | FK → users.id | |
| created_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() | |
| updated_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() | |
| deleted_at | TIMESTAMPTZ |
インデックス:
idx_projects_tenant_client ON (tenant_id, client_id)idx_projects_campaign ON (tenant_id, campaign_id)| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| id | UUID | PK | |
| tenant_id | UUID | NOT NULL, FK → tenants.id | |
| project_id | UUID | NOT NULL, FK → projects.id | |
| parent_task_id | UUID | FK → tasks.id | 親タスク(サブタスク用) |
| title | VARCHAR(255) | NOT NULL | |
| description | TEXT | ||
| status | VARCHAR(30) | NOT NULL, DEFAULT 'todo' | todo/in_progress/in_review/done |
| priority | VARCHAR(20) | NOT NULL, DEFAULT 'medium' | low/medium/high/urgent |
| assignee_id | UUID | FK → users.id | |
| due_date | DATE | ||
| estimated_hours | DECIMAL(6,2) | ||
| actual_hours | DECIMAL(6,2) | ||
| sort_order | INT | NOT NULL, DEFAULT 0 | |
| created_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() | |
| updated_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() | |
| deleted_at | TIMESTAMPTZ |
インデックス:
idx_tasks_project ON (tenant_id, project_id)idx_tasks_assignee ON (tenant_id, assignee_id)idx_tasks_status ON (tenant_id, status)idx_tasks_due_date ON (tenant_id, due_date) WHERE status != 'done'| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| id | UUID | PK | |
| tenant_id | UUID | NOT NULL, FK → tenants.id | |
| task_id | UUID | NOT NULL, FK → tasks.id | |
| user_id | UUID | NOT NULL, FK → users.id | |
| body | TEXT | NOT NULL | |
| created_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() | |
| updated_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() |
インデックス:
idx_task_comments_task ON (tenant_id, task_id, created_at)| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| id | UUID | PK | |
| tenant_id | UUID | NOT NULL, FK → tenants.id | |
| name | VARCHAR(255) | NOT NULL | |
| report_type | VARCHAR(50) | NOT NULL | performance/budget/creative/pl |
| client_id | UUID | FK → clients.id | |
| campaign_ids | UUID[] | 対象キャンペーン群 | |
| metrics | TEXT[] | NOT NULL | 含める指標 |
| dimensions | TEXT[] | NOT NULL | 集計軸 |
| filters | JSONB | DEFAULT '{}' | フィルタ条件 |
| template_config | JSONB | DEFAULT '{}' | テンプレート設定 |
| output_format | VARCHAR(20) | NOT NULL, DEFAULT 'pdf' | pdf/excel/google_slides |
| created_by_id | UUID | NOT NULL, FK → users.id | |
| created_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() | |
| updated_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() |
インデックス:
idx_report_configs_tenant ON (tenant_id)idx_report_configs_client ON (tenant_id, client_id)| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| id | UUID | PK | |
| tenant_id | UUID | NOT NULL, FK → tenants.id | |
| report_config_id | UUID | NOT NULL, FK → report_configs.id | |
| frequency | VARCHAR(30) | NOT NULL | daily/weekly/monthly/quarterly |
| cron_expression | VARCHAR(100) | cron式 | |
| day_of_week | INT | 0-6(weekly時) | |
| day_of_month | INT | 1-31(monthly時) | |
| time_of_day | TIME | NOT NULL, DEFAULT '09:00' | 配信時刻 |
| timezone | VARCHAR(50) | NOT NULL, DEFAULT 'Asia/Tokyo' | |
| recipients | JSONB | NOT NULL | 配信先リスト |
| is_active | BOOLEAN | NOT NULL, DEFAULT true | |
| next_run_at | TIMESTAMPTZ | 次回実行予定 | |
| created_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() | |
| updated_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() |
インデックス:
idx_rs_config ON (tenant_id, report_config_id)idx_rs_next_run ON (next_run_at) WHERE is_active = true| カラム名 | 型 | 制約 | 説明 |
|---|---|---|---|
| id | UUID | PK | |
| tenant_id | UUID | NOT NULL, FK → tenants.id | |
| report_config_id | UUID | NOT NULL, FK → report_configs.id | |
| schedule_id | UUID | FK → report_schedules.id | 手動実行時はNULL |
| status | VARCHAR(30) | NOT NULL | queued/running/completed/failed |
| started_at | TIMESTAMPTZ | ||
| completed_at | TIMESTAMPTZ | ||
| output_url | TEXT | 生成ファイルURL | |
| error_message | TEXT | ||
| triggered_by_id | UUID | FK → users.id | |
| created_at | TIMESTAMPTZ | NOT NULL, DEFAULT now() |
インデックス:
idx_re_config ON (tenant_id, report_config_id, created_at DESC)idx_re_status ON (status) WHERE status IN ('queued', 'running')※ この図はシステム構成図です。詳細は別途ご説明いたします。
v_campaign_kpi_summary (マテリアライズドビュー):
REFRESH MATERIALIZED VIEW CONCURRENTLYv_client_pl_summary (ビュー):
v_budget_pacing_status (ビュー):
全テーブル(media_platforms, permissions を除く)に対して以下の RLS ポリシーを適用:
-- 例: clients テーブル ALTER TABLE clients ENABLE ROW LEVEL SECURITY; CREATE POLICY tenant_isolation ON clients USING (tenant_id = current_setting('app.current_tenant_id')::uuid);
アプリケーション層(Prisma ミドルウェア)でリクエストごとに SET LOCAL app.current_tenant_id = '<uuid>' を発行する。