feat: first database migration

This commit is contained in:
2026-04-23 12:14:54 +02:00
parent 5c1399a061
commit 28141deb8b
2 changed files with 728 additions and 0 deletions

View File

@@ -0,0 +1,347 @@
defmodule BDS.Repo.Migrations.CreatePersistenceContract do
use Ecto.Migration
def change do
create table(:projects, primary_key: false) do
add :id, :string, primary_key: true
add :name, :string, null: false
add :slug, :string, null: false
add :description, :text
add :data_path, :string
add :created_at, :integer, null: false
add :updated_at, :integer, null: false
add :is_active, :boolean, null: false, default: false
end
create unique_index(:projects, [:slug])
create table(:posts, primary_key: false) do
add :id, :string, primary_key: true
add :project_id, references(:projects, type: :string, on_delete: :delete_all), null: false
add :title, :string, null: false
add :slug, :string, null: false
add :excerpt, :text
add :content, :text
add :status, :string, null: false, default: "draft"
add :author, :string
add :created_at, :integer, null: false
add :updated_at, :integer, null: false
add :published_at, :integer
add :file_path, :string, null: false, default: ""
add :checksum, :string
add :tags, :text
add :categories, :text
add :template_slug, :string
add :language, :string
add :do_not_translate, :boolean, null: false, default: false
add :published_title, :text
add :published_content, :text
add :published_tags, :text
add :published_categories, :text
add :published_excerpt, :text
end
create unique_index(:posts, [:project_id, :slug], name: :posts_project_slug_idx)
create table(:post_translations, primary_key: false) do
add :id, :string, primary_key: true
add :project_id, references(:projects, type: :string, on_delete: :delete_all), null: false
add :translation_for, references(:posts, column: :id, type: :string, on_delete: :delete_all),
null: false
add :language, :string, null: false
add :title, :string, null: false
add :excerpt, :text
add :content, :text
add :status, :string, null: false, default: "draft"
add :created_at, :integer, null: false
add :updated_at, :integer, null: false
add :published_at, :integer
add :file_path, :string, null: false, default: ""
add :checksum, :string
end
create unique_index(:post_translations, [:translation_for, :language],
name: :post_translations_translation_language_idx
)
create table(:media, primary_key: false) do
add :id, :string, primary_key: true
add :project_id, references(:projects, type: :string, on_delete: :delete_all), null: false
add :filename, :string, null: false
add :original_name, :string, null: false
add :mime_type, :string, null: false
add :size, :integer, null: false
add :width, :integer
add :height, :integer
add :title, :string
add :alt, :text
add :caption, :text
add :author, :string
add :file_path, :string, null: false
add :sidecar_path, :string, null: false
add :created_at, :integer, null: false
add :updated_at, :integer, null: false
add :checksum, :string
add :tags, :text
add :language, :string
end
create table(:media_translations, primary_key: false) do
add :id, :string, primary_key: true
add :project_id, references(:projects, type: :string, on_delete: :delete_all), null: false
add :translation_for, references(:media, column: :id, type: :string, on_delete: :delete_all),
null: false
add :language, :string, null: false
add :title, :string
add :alt, :text
add :caption, :text
add :created_at, :integer, null: false
add :updated_at, :integer, null: false
end
create unique_index(:media_translations, [:translation_for, :language],
name: :media_translations_translation_language_idx
)
create table(:tags, primary_key: false) do
add :id, :string, primary_key: true
add :project_id, references(:projects, type: :string, on_delete: :delete_all), null: false
add :name, :string, null: false
add :color, :string
add :post_template_slug, :string
add :created_at, :integer, null: false
add :updated_at, :integer, null: false
end
create unique_index(:tags, [:project_id, :name], name: :tags_project_name_idx)
create table(:templates, primary_key: false) do
add :id, :string, primary_key: true
add :project_id, references(:projects, type: :string, on_delete: :delete_all), null: false
add :slug, :string, null: false
add :title, :string, null: false
add :kind, :string, null: false
add :enabled, :boolean, null: false, default: true
add :version, :integer, null: false, default: 1
add :file_path, :string, null: false
add :status, :string, null: false, default: "draft"
add :content, :text
add :created_at, :integer, null: false
add :updated_at, :integer, null: false
end
create unique_index(:templates, [:project_id, :slug], name: :templates_project_slug_idx)
create table(:scripts, primary_key: false) do
add :id, :string, primary_key: true
add :project_id, references(:projects, type: :string, on_delete: :delete_all), null: false
add :slug, :string, null: false
add :title, :string, null: false
add :kind, :string, null: false
add :entrypoint, :string, null: false
add :enabled, :boolean, null: false, default: true
add :version, :integer, null: false, default: 1
add :file_path, :string, null: false
add :status, :string, null: false, default: "draft"
add :content, :text
add :created_at, :integer, null: false
add :updated_at, :integer, null: false
end
create unique_index(:scripts, [:project_id, :slug], name: :scripts_project_slug_idx)
create table(:post_links, primary_key: false) do
add :id, :string, primary_key: true
add :source_post_id, references(:posts, column: :id, type: :string, on_delete: :delete_all),
null: false
add :target_post_id, references(:posts, column: :id, type: :string, on_delete: :delete_all),
null: false
add :link_text, :text
add :created_at, :integer, null: false
end
create table(:post_media, primary_key: false) do
add :id, :string, primary_key: true
add :project_id, references(:projects, type: :string, on_delete: :delete_all), null: false
add :post_id, references(:posts, column: :id, type: :string, on_delete: :delete_all), null: false
add :media_id, references(:media, column: :id, type: :string, on_delete: :delete_all), null: false
add :sort_order, :integer, null: false, default: 0
add :created_at, :integer, null: false
end
create unique_index(:post_media, [:post_id, :media_id], name: :post_media_post_media_idx)
create table(:settings, primary_key: false) do
add :key, :string, primary_key: true
add :value, :text, null: false
add :updated_at, :integer, null: false
end
create table(:generated_file_hashes, primary_key: false) do
add :project_id, references(:projects, type: :string, on_delete: :delete_all), null: false
add :relative_path, :string, null: false
add :content_hash, :string, null: false
add :updated_at, :integer, null: false
end
create unique_index(:generated_file_hashes, [:project_id, :relative_path],
name: :generated_file_hashes_project_path_idx
)
create table(:chat_conversations, primary_key: false) do
add :id, :string, primary_key: true
add :title, :string, null: false
add :model, :string
add :copilot_session_id, :string
add :created_at, :integer, null: false
add :updated_at, :integer, null: false
end
create table(:chat_messages) do
add :conversation_id,
references(:chat_conversations, column: :id, type: :string, on_delete: :delete_all),
null: false
add :role, :string, null: false
add :content, :text
add :tool_call_id, :string
add :tool_calls, :text
add :created_at, :integer, null: false
end
create table(:ai_providers, primary_key: false) do
add :id, :string, primary_key: true
add :name, :string, null: false
add :env, :string
add :package_ref, :string
add :api, :string
add :doc, :string
add :updated_at, :integer, null: false
end
create table(:ai_models, primary_key: false) do
add :provider, references(:ai_providers, type: :string, on_delete: :delete_all),
primary_key: true,
null: false
add :model_id, :string, primary_key: true
add :name, :string, null: false
add :family, :string
add :attachment, :boolean, null: false, default: false
add :reasoning, :boolean, null: false, default: false
add :tool_call, :boolean, null: false, default: false
add :structured_output, :boolean, null: false, default: false
add :temperature, :boolean, null: false, default: false
add :knowledge, :string
add :release_date, :string
add :last_updated_date, :string
add :open_weights, :boolean, null: false, default: false
add :input_price, :integer
add :output_price, :integer
add :cache_read_price, :integer
add :cache_write_price, :integer
add :context_window, :integer, null: false
add :max_input_tokens, :integer, null: false
add :max_output_tokens, :integer, null: false
add :interleaved, :string
add :status, :string
add :provider_package_ref, :string
add :updated_at, :integer, null: false
end
create table(:ai_model_modalities, primary_key: false) do
add :provider, references(:ai_providers, type: :string, on_delete: :delete_all),
primary_key: true,
null: false
add :model_id, :string, primary_key: true
add :direction, :string, primary_key: true
add :modality, :string, primary_key: true
end
create table(:ai_catalog_meta, primary_key: false) do
add :key, :string, primary_key: true
add :value, :string, null: false
end
create table(:embedding_keys, primary_key: false) do
add :label, :integer, primary_key: true
add :post_id, references(:posts, column: :id, type: :string, on_delete: :delete_all), null: false
add :project_id, references(:projects, type: :string, on_delete: :delete_all), null: false
add :content_hash, :string, null: false
add :vector, :text
end
create table(:dismissed_duplicate_pairs, primary_key: false) do
add :id, :string, primary_key: true
add :project_id, references(:projects, type: :string, on_delete: :delete_all), null: false
add :post_id_a, references(:posts, column: :id, type: :string, on_delete: :delete_all),
null: false
add :post_id_b, references(:posts, column: :id, type: :string, on_delete: :delete_all),
null: false
add :dismissed_at, :integer, null: false
end
create unique_index(:dismissed_duplicate_pairs, [:project_id, :post_id_a, :post_id_b],
name: :dismissed_pairs_idx
)
create table(:import_definitions, primary_key: false) do
add :id, :string, primary_key: true
add :project_id, references(:projects, type: :string, on_delete: :delete_all), null: false
add :name, :string, null: false
add :wxr_file_path, :string
add :uploads_folder_path, :string
add :last_analysis_result, :text
add :created_at, :integer, null: false
add :updated_at, :integer, null: false
end
create table(:db_notifications) do
add :entity_type, :string, null: false
add :entity_id, :string, null: false
add :action, :string, null: false
add :from_cli, :boolean, null: false, default: true
add :seen_at, :integer
add :created_at, :integer, null: false
end
execute(
"""
CREATE VIRTUAL TABLE posts_fts USING fts5(
post_id UNINDEXED,
title,
excerpt,
content,
tags,
categories
)
""",
"DROP TABLE IF EXISTS posts_fts"
)
execute(
"""
CREATE VIRTUAL TABLE media_fts USING fts5(
media_id UNINDEXED,
title,
alt,
caption,
original_name,
tags
)
""",
"DROP TABLE IF EXISTS media_fts"
)
end
end