gabriel / musehub public
0001_consolidated_schema.py python
1035 lines 54.7 KB
c0f0b481 release: merge dev → main (#5) Gabriel Cardona <cgcardona@gmail.com> 5d ago
1 """Consolidated schema — all tables, single migration.
2
3 Revision ID: 0001
4 Revises:
5 Create Date: 2026-02-27 00:00:00.000000
6
7 THIS IS THE ONLY MIGRATION. All new tables are folded in here during
8 development. Do NOT create new migration files — add tables directly to
9 upgrade() and their drops (in reverse order) to the top of downgrade().
10
11 Creates:
12
13 Auth
14 - muse_users, muse_access_tokens
15
16 Muse CLI — filesystem commit history
17 - muse_objects, muse_snapshots, muse_commits
18 (includes parent2_commit_id for merge commits; metadata JSON blob for
19 commit-level annotations e.g. tempo_bpm set via ``muse tempo --set``)
20 - muse_tags (music-semantic tags attached to commits)
21
22 MuseHub — remote collaboration backend
23 - musehub_repos, musehub_branches, musehub_commits, musehub_issues
24 - musehub_issue_milestones (many-to-many join: issues ↔ milestones)
25 - musehub_pull_requests (PR workflow; merged_at records exact merge timestamp)
26 - musehub_pr_comments (inline review comments on musical diffs within PRs)
27 - musehub_objects (content-addressed binary artifact storage)
28 - musehub_stars (per-user repo starring for the explore/discover page)
29 - musehub_profiles (public user profile pages — bio, avatar, pinned repos)
30 - musehub_sessions (recording session metadata — participants, intent, commits)
31 - musehub_releases (published version releases with download packages)
32 - musehub_release_assets (downloadable file attachments per release with download counts)
33 - musehub_webhooks (registered event-driven webhook subscriptions)
34 - musehub_webhook_deliveries (delivery log per dispatch attempt; payload column stores JSON body for retry)
35 - musehub_render_jobs (async audio render pipeline)
36 - musehub_comments, musehub_reactions, musehub_follows, musehub_watches
37 - musehub_notifications, musehub_forks, musehub_view_events, musehub_download_events
38 - musehub_events (activity event stream)
39 - musehub_labels, musehub_issue_labels, musehub_pr_labels (label tagging)
40 - musehub_collaborators (repo access control beyond owner)
41 - musehub_stash, musehub_stash_entries (git-stash-style temporary shelving)
42 - musehub_pr_reviews (reviewer assignment and approval tracking per PR)
43 - musehub_repos.settings (nullable JSON column for feature-flag settings)
44
45 Fresh install:
46 docker compose exec musehub alembic upgrade head
47 """
48 from __future__ import annotations
49
50 import sqlalchemy as sa
51 from alembic import op
52 from sqlalchemy.dialects import postgresql
53
54 revision = "0001"
55 down_revision = None
56 branch_labels = None
57 depends_on = None
58
59
60 def upgrade() -> None:
61 # ── Users & auth ──────────────────────────────────────────────────────
62 op.create_table(
63 "muse_users",
64 sa.Column("id", sa.String(36), nullable=False),
65 sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("CURRENT_TIMESTAMP")),
66 sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("CURRENT_TIMESTAMP")),
67 sa.PrimaryKeyConstraint("id"),
68 )
69
70 op.create_table(
71 "muse_access_tokens",
72 sa.Column("id", sa.String(36), nullable=False),
73 sa.Column("user_id", sa.String(36), nullable=False),
74 sa.Column("token_hash", sa.String(64), nullable=False),
75 sa.Column("expires_at", sa.DateTime(timezone=True), nullable=False),
76 sa.Column("revoked", sa.Boolean(), nullable=False, server_default="false"),
77 sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("CURRENT_TIMESTAMP")),
78 sa.ForeignKeyConstraint(["user_id"], ["muse_users.id"], ondelete="CASCADE"),
79 sa.PrimaryKeyConstraint("id"),
80 )
81 op.create_index("ix_muse_access_tokens_user_id", "muse_access_tokens", ["user_id"])
82 op.create_index("ix_muse_access_tokens_token_hash", "muse_access_tokens", ["token_hash"], unique=True)
83
84 # ── Muse CLI — filesystem commit history ──────────────────────────────
85 op.create_table(
86 "muse_objects",
87 sa.Column("object_id", sa.String(64), nullable=False),
88 sa.Column("size_bytes", sa.Integer(), nullable=False),
89 sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
90 sa.PrimaryKeyConstraint("object_id"),
91 )
92
93 op.create_table(
94 "muse_snapshots",
95 sa.Column("snapshot_id", sa.String(64), nullable=False),
96 sa.Column("manifest", sa.JSON(), nullable=False),
97 sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
98 sa.PrimaryKeyConstraint("snapshot_id"),
99 )
100
101 op.create_table(
102 "muse_commits",
103 sa.Column("commit_id", sa.String(64), nullable=False),
104 sa.Column("repo_id", sa.String(36), nullable=False),
105 sa.Column("branch", sa.String(255), nullable=False),
106 sa.Column("parent_commit_id", sa.String(64), nullable=True),
107 sa.Column("parent2_commit_id", sa.String(64), nullable=True),
108 sa.Column("snapshot_id", sa.String(64), nullable=False),
109 sa.Column("message", sa.Text(), nullable=False),
110 sa.Column("author", sa.String(255), nullable=False),
111 sa.Column("committed_at", sa.DateTime(timezone=True), nullable=False),
112 sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
113 sa.Column("metadata", sa.JSON(), nullable=True),
114 sa.ForeignKeyConstraint(["snapshot_id"], ["muse_snapshots.snapshot_id"], ondelete="RESTRICT"),
115 sa.PrimaryKeyConstraint("commit_id"),
116 )
117 op.create_index("ix_muse_commits_repo_id", "muse_commits", ["repo_id"])
118 op.create_index("ix_muse_commits_parent_commit_id", "muse_commits", ["parent_commit_id"])
119 op.create_index("ix_muse_commits_parent2_commit_id", "muse_commits", ["parent2_commit_id"])
120
121 op.create_table(
122 "muse_tags",
123 sa.Column("tag_id", sa.String(36), nullable=False),
124 sa.Column("repo_id", sa.String(36), nullable=False),
125 sa.Column("commit_id", sa.String(64), nullable=False),
126 sa.Column("tag", sa.Text(), nullable=False),
127 sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
128 sa.ForeignKeyConstraint(["commit_id"], ["muse_commits.commit_id"], ondelete="CASCADE"),
129 sa.PrimaryKeyConstraint("tag_id"),
130 )
131 op.create_index("ix_muse_tags_repo_id", "muse_tags", ["repo_id"])
132 op.create_index("ix_muse_tags_commit_id", "muse_tags", ["commit_id"])
133 op.create_index("ix_muse_tags_tag", "muse_tags", ["tag"])
134
135 # ── MuseHub — remote collaboration backend ───────────────────────────
136 op.create_table(
137 "musehub_repos",
138 sa.Column("repo_id", sa.String(36), nullable=False),
139 sa.Column("name", sa.String(255), nullable=False),
140 # URL-visible owner username (e.g. "gabriel") — forms the /{owner}/{slug} path
141 sa.Column("owner", sa.String(64), nullable=False),
142 # URL-safe slug auto-generated from name (e.g. "neo-soul-experiment")
143 sa.Column("slug", sa.String(64), nullable=False),
144 sa.Column("visibility", sa.String(20), nullable=False, server_default="private"),
145 sa.Column("owner_user_id", sa.String(36), nullable=False),
146 sa.Column("description", sa.Text(), nullable=False, server_default=""),
147 sa.Column("tags", sa.JSON(), nullable=False, server_default="[]"),
148 sa.Column("key_signature", sa.String(50), nullable=True),
149 sa.Column("tempo_bpm", sa.Integer(), nullable=True),
150 sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("CURRENT_TIMESTAMP")),
151 # Soft-delete timestamp; non-null means the repo is logically deleted
152 sa.Column("deleted_at", sa.DateTime(timezone=True), nullable=True),
153 sa.Column("settings", sa.JSON(), nullable=True),
154 sa.PrimaryKeyConstraint("repo_id"),
155 sa.UniqueConstraint("owner", "slug", name="uq_musehub_repos_owner_slug"),
156 )
157 op.create_index("ix_musehub_repos_owner", "musehub_repos", ["owner"])
158 op.create_index("ix_musehub_repos_slug", "musehub_repos", ["slug"])
159 op.create_index("ix_musehub_repos_owner_user_id", "musehub_repos", ["owner_user_id"])
160
161 op.create_table(
162 "musehub_branches",
163 sa.Column("branch_id", sa.String(36), nullable=False),
164 sa.Column("repo_id", sa.String(36), nullable=False),
165 sa.Column("name", sa.String(255), nullable=False),
166 sa.Column("head_commit_id", sa.String(64), nullable=True),
167 sa.ForeignKeyConstraint(["repo_id"], ["musehub_repos.repo_id"], ondelete="CASCADE"),
168 sa.PrimaryKeyConstraint("branch_id"),
169 )
170 op.create_index("ix_musehub_branches_repo_id", "musehub_branches", ["repo_id"])
171
172 op.create_table(
173 "musehub_commits",
174 sa.Column("commit_id", sa.String(64), nullable=False),
175 sa.Column("repo_id", sa.String(36), nullable=False),
176 sa.Column("branch", sa.String(255), nullable=False),
177 sa.Column("parent_ids", sa.JSON(), nullable=False, server_default="[]"),
178 sa.Column("message", sa.Text(), nullable=False),
179 sa.Column("author", sa.String(255), nullable=False),
180 sa.Column("timestamp", sa.DateTime(timezone=True), nullable=False),
181 sa.Column("snapshot_id", sa.String(64), nullable=True),
182 sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("CURRENT_TIMESTAMP")),
183 sa.ForeignKeyConstraint(["repo_id"], ["musehub_repos.repo_id"], ondelete="CASCADE"),
184 sa.PrimaryKeyConstraint("commit_id"),
185 )
186 op.create_index("ix_musehub_commits_repo_id", "musehub_commits", ["repo_id"])
187 op.create_index("ix_musehub_commits_branch", "musehub_commits", ["branch"])
188 op.create_index("ix_musehub_commits_timestamp", "musehub_commits", ["timestamp"])
189
190 # ── MuseHub — milestones ─────────────────────────────────────────────
191 op.create_table(
192 "musehub_milestones",
193 sa.Column("milestone_id", sa.String(36), nullable=False),
194 sa.Column("repo_id", sa.String(36), nullable=False),
195 sa.Column("number", sa.Integer(), nullable=False),
196 sa.Column("title", sa.String(255), nullable=False),
197 sa.Column("description", sa.Text(), nullable=False, server_default=""),
198 sa.Column("state", sa.String(20), nullable=False, server_default="open"),
199 sa.Column("author", sa.String(255), nullable=False, server_default=""),
200 sa.Column("due_on", sa.DateTime(timezone=True), nullable=True),
201 sa.Column(
202 "created_at",
203 sa.DateTime(timezone=True),
204 nullable=False,
205 server_default=sa.text("CURRENT_TIMESTAMP"),
206 ),
207 sa.Column(
208 "updated_at",
209 sa.DateTime(timezone=True),
210 nullable=False,
211 server_default=sa.text("CURRENT_TIMESTAMP"),
212 ),
213 sa.ForeignKeyConstraint(["repo_id"], ["musehub_repos.repo_id"], ondelete="CASCADE"),
214 sa.PrimaryKeyConstraint("milestone_id"),
215 )
216 op.create_index("ix_musehub_milestones_repo_id", "musehub_milestones", ["repo_id"])
217 op.create_index("ix_musehub_milestones_number", "musehub_milestones", ["number"])
218 op.create_index("ix_musehub_milestones_state", "musehub_milestones", ["state"])
219
220 # ── MuseHub — issue tracking ─────────────────────────────────────────
221 op.create_table(
222 "musehub_issues",
223 sa.Column("issue_id", sa.String(36), nullable=False),
224 sa.Column("repo_id", sa.String(36), nullable=False),
225 sa.Column("number", sa.Integer(), nullable=False),
226 sa.Column("title", sa.String(500), nullable=False),
227 sa.Column("body", sa.Text(), nullable=False, server_default=""),
228 sa.Column("state", sa.String(20), nullable=False, server_default="open"),
229 sa.Column("labels", sa.JSON(), nullable=False, server_default="[]"),
230 sa.Column("author", sa.String(255), nullable=False, server_default=""),
231 sa.Column("assignee", sa.String(255), nullable=True),
232 sa.Column("milestone_id", sa.String(36), nullable=True),
233 sa.Column(
234 "created_at",
235 sa.DateTime(timezone=True),
236 nullable=False,
237 server_default=sa.text("CURRENT_TIMESTAMP"),
238 ),
239 sa.Column(
240 "updated_at",
241 sa.DateTime(timezone=True),
242 nullable=False,
243 server_default=sa.text("CURRENT_TIMESTAMP"),
244 ),
245 sa.ForeignKeyConstraint(["repo_id"], ["musehub_repos.repo_id"], ondelete="CASCADE"),
246 sa.ForeignKeyConstraint(
247 ["milestone_id"], ["musehub_milestones.milestone_id"], ondelete="SET NULL"
248 ),
249 sa.PrimaryKeyConstraint("issue_id"),
250 )
251 op.create_index("ix_musehub_issues_repo_id", "musehub_issues", ["repo_id"])
252 op.create_index("ix_musehub_issues_number", "musehub_issues", ["number"])
253 op.create_index("ix_musehub_issues_state", "musehub_issues", ["state"])
254 op.create_index("ix_musehub_issues_milestone_id", "musehub_issues", ["milestone_id"])
255
256 # ── MuseHub — issue comments ─────────────────────────────────────────
257 op.create_table(
258 "musehub_issue_comments",
259 sa.Column("comment_id", sa.String(36), nullable=False),
260 sa.Column("issue_id", sa.String(36), nullable=False),
261 sa.Column("repo_id", sa.String(36), nullable=False),
262 sa.Column("author", sa.String(255), nullable=False, server_default=""),
263 sa.Column("body", sa.Text(), nullable=False),
264 sa.Column("parent_id", sa.String(36), nullable=True),
265 sa.Column("musical_refs", sa.JSON(), nullable=False, server_default="[]"),
266 sa.Column("is_deleted", sa.Boolean(), nullable=False, server_default="false"),
267 sa.Column(
268 "created_at",
269 sa.DateTime(timezone=True),
270 nullable=False,
271 server_default=sa.text("CURRENT_TIMESTAMP"),
272 ),
273 sa.Column(
274 "updated_at",
275 sa.DateTime(timezone=True),
276 nullable=False,
277 server_default=sa.text("CURRENT_TIMESTAMP"),
278 ),
279 sa.ForeignKeyConstraint(["issue_id"], ["musehub_issues.issue_id"], ondelete="CASCADE"),
280 sa.ForeignKeyConstraint(["repo_id"], ["musehub_repos.repo_id"], ondelete="CASCADE"),
281 sa.PrimaryKeyConstraint("comment_id"),
282 )
283 op.create_index("ix_musehub_issue_comments_issue_id", "musehub_issue_comments", ["issue_id"])
284 op.create_index("ix_musehub_issue_comments_repo_id", "musehub_issue_comments", ["repo_id"])
285 op.create_index("ix_musehub_issue_comments_parent_id", "musehub_issue_comments", ["parent_id"])
286 op.create_index("ix_musehub_issue_comments_created_at", "musehub_issue_comments", ["created_at"])
287
288 # ── MuseHub — issue-milestone join table ─────────────────────────────
289 op.create_table(
290 "musehub_issue_milestones",
291 sa.Column("issue_id", sa.String(36), nullable=False),
292 sa.Column("milestone_id", sa.String(36), nullable=False),
293 sa.ForeignKeyConstraint(
294 ["issue_id"],
295 ["musehub_issues.issue_id"],
296 ondelete="CASCADE",
297 ),
298 sa.ForeignKeyConstraint(
299 ["milestone_id"],
300 ["musehub_milestones.milestone_id"],
301 ondelete="CASCADE",
302 ),
303 sa.PrimaryKeyConstraint("issue_id", "milestone_id"),
304 )
305 op.create_index(
306 "ix_musehub_issue_milestones_milestone_id",
307 "musehub_issue_milestones",
308 ["milestone_id"],
309 )
310
311 # ── MuseHub — pull requests ──────────────────────────────────────────
312 op.create_table(
313 "musehub_pull_requests",
314 sa.Column("pr_id", sa.String(36), nullable=False),
315 sa.Column("repo_id", sa.String(36), nullable=False),
316 sa.Column("title", sa.String(500), nullable=False),
317 sa.Column("body", sa.Text(), nullable=False, server_default=""),
318 sa.Column("state", sa.String(20), nullable=False, server_default="open"),
319 sa.Column("from_branch", sa.String(255), nullable=False),
320 sa.Column("to_branch", sa.String(255), nullable=False),
321 sa.Column("merge_commit_id", sa.String(64), nullable=True),
322 sa.Column("author", sa.String(255), nullable=False, server_default=""),
323 sa.Column(
324 "created_at",
325 sa.DateTime(timezone=True),
326 nullable=False,
327 server_default=sa.text("CURRENT_TIMESTAMP"),
328 ),
329 # Set by merge_pr() at the exact moment of merge; NULL for open/unmerged PRs.
330 sa.Column("merged_at", sa.DateTime(timezone=True), nullable=True),
331 sa.ForeignKeyConstraint(["repo_id"], ["musehub_repos.repo_id"], ondelete="CASCADE"),
332 sa.PrimaryKeyConstraint("pr_id"),
333 )
334 op.create_index("ix_musehub_pull_requests_repo_id", "musehub_pull_requests", ["repo_id"])
335 op.create_index("ix_musehub_pull_requests_state", "musehub_pull_requests", ["state"])
336
337 # ── MuseHub — PR review comments ────────────────────────────────────
338 op.create_table(
339 "musehub_pr_comments",
340 sa.Column("comment_id", sa.String(36), nullable=False),
341 sa.Column("pr_id", sa.String(36), nullable=False),
342 sa.Column("repo_id", sa.String(36), nullable=False),
343 sa.Column("author", sa.String(255), nullable=False),
344 sa.Column("body", sa.Text(), nullable=False),
345 sa.Column("target_type", sa.String(20), nullable=False, server_default="general"),
346 sa.Column("target_track", sa.String(255), nullable=True),
347 sa.Column("target_beat_start", sa.Float(), nullable=True),
348 sa.Column("target_beat_end", sa.Float(), nullable=True),
349 sa.Column("target_note_pitch", sa.Integer(), nullable=True),
350 sa.Column("parent_comment_id", sa.String(36), nullable=True),
351 sa.Column(
352 "created_at",
353 sa.DateTime(timezone=True),
354 nullable=False,
355 server_default=sa.text("CURRENT_TIMESTAMP"),
356 ),
357 sa.ForeignKeyConstraint(["pr_id"], ["musehub_pull_requests.pr_id"], ondelete="CASCADE"),
358 sa.PrimaryKeyConstraint("comment_id"),
359 )
360 op.create_index("ix_musehub_pr_comments_pr_id", "musehub_pr_comments", ["pr_id"])
361 op.create_index("ix_musehub_pr_comments_repo_id", "musehub_pr_comments", ["repo_id"])
362 op.create_index("ix_musehub_pr_comments_parent_comment_id", "musehub_pr_comments", ["parent_comment_id"])
363 op.create_index("ix_musehub_pr_comments_created_at", "musehub_pr_comments", ["created_at"])
364
365 # ── MuseHub — binary artifact storage ───────────────────────────────
366 op.create_table(
367 "musehub_objects",
368 sa.Column("object_id", sa.String(128), nullable=False),
369 sa.Column("repo_id", sa.String(36), nullable=False),
370 sa.Column("path", sa.String(1024), nullable=False),
371 sa.Column("size_bytes", sa.Integer(), nullable=False, server_default="0"),
372 sa.Column("disk_path", sa.String(2048), nullable=False),
373 sa.Column(
374 "created_at",
375 sa.DateTime(timezone=True),
376 nullable=False,
377 server_default=sa.text("CURRENT_TIMESTAMP"),
378 ),
379 sa.ForeignKeyConstraint(["repo_id"], ["musehub_repos.repo_id"], ondelete="CASCADE"),
380 sa.PrimaryKeyConstraint("object_id"),
381 )
382 op.create_index("ix_musehub_objects_repo_id", "musehub_objects", ["repo_id"])
383
384 # ── MuseHub — repo starring (explore/discover page) ─────────────────
385 op.create_table(
386 "musehub_stars",
387 sa.Column("star_id", sa.String(36), nullable=False),
388 sa.Column("repo_id", sa.String(36), nullable=False),
389 sa.Column("user_id", sa.String(36), nullable=False),
390 sa.Column(
391 "created_at",
392 sa.DateTime(timezone=True),
393 nullable=False,
394 server_default=sa.text("CURRENT_TIMESTAMP"),
395 ),
396 sa.ForeignKeyConstraint(["repo_id"], ["musehub_repos.repo_id"], ondelete="CASCADE"),
397 sa.PrimaryKeyConstraint("star_id"),
398 sa.UniqueConstraint("repo_id", "user_id", name="uq_musehub_stars_repo_user"),
399 )
400 op.create_index("ix_musehub_stars_repo_id", "musehub_stars", ["repo_id"])
401 op.create_index("ix_musehub_stars_user_id", "musehub_stars", ["user_id"])
402
403 # ── MuseHub — recording sessions ─────────────────────────────────────
404 op.create_table(
405 "musehub_sessions",
406 sa.Column("session_id", sa.String(36), nullable=False),
407 sa.Column("repo_id", sa.String(36), nullable=False),
408 sa.Column("schema_version", sa.String(10), nullable=False, server_default="1"),
409 sa.Column("started_at", sa.DateTime(timezone=True), nullable=False),
410 sa.Column("ended_at", sa.DateTime(timezone=True), nullable=True),
411 sa.Column("participants", sa.JSON(), nullable=False, server_default="[]"),
412 sa.Column("location", sa.String(500), nullable=False, server_default=""),
413 sa.Column("intent", sa.Text(), nullable=False, server_default=""),
414 sa.Column("commits", sa.JSON(), nullable=False, server_default="[]"),
415 sa.Column("notes", sa.Text(), nullable=False, server_default=""),
416 # True while the session is still active; False after muse session end / stop
417 sa.Column("is_active", sa.Boolean(), nullable=False, server_default="false"),
418 sa.Column(
419 "created_at",
420 sa.DateTime(timezone=True),
421 nullable=False,
422 server_default=sa.text("CURRENT_TIMESTAMP"),
423 ),
424 sa.ForeignKeyConstraint(["repo_id"], ["musehub_repos.repo_id"], ondelete="CASCADE"),
425 sa.PrimaryKeyConstraint("session_id"),
426 )
427 op.create_index("ix_musehub_sessions_repo_id", "musehub_sessions", ["repo_id"])
428 op.create_index("ix_musehub_sessions_started_at", "musehub_sessions", ["started_at"])
429 op.create_index("ix_musehub_sessions_is_active", "musehub_sessions", ["is_active"])
430
431 # ── MuseHub — public user profiles ───────────────────────────────────
432 op.create_table(
433 "musehub_profiles",
434 # PK is the JWT sub claim — same value used in musehub_repos.owner_user_id
435 sa.Column("user_id", sa.String(36), nullable=False),
436 # URL-friendly handle, e.g. "gabriel" → /musehub/ui/users/gabriel
437 sa.Column("username", sa.String(64), nullable=False),
438 # Human-readable display name shown in profile header
439 sa.Column("display_name", sa.String(255), nullable=True),
440 sa.Column("bio", sa.Text(), nullable=True),
441 sa.Column("avatar_url", sa.String(2048), nullable=True),
442 sa.Column("location", sa.String(255), nullable=True),
443 sa.Column("website_url", sa.String(2048), nullable=True),
444 sa.Column("twitter_handle", sa.String(64), nullable=True),
445 sa.Column("is_verified", sa.Boolean(), nullable=False, server_default="false"),
446 # CC attribution string, e.g. "Public Domain", "CC BY 4.0"; null = all rights reserved
447 sa.Column("cc_license", sa.String(50), nullable=True),
448 # JSON list of repo_ids (up to 6) pinned by the user on their profile page
449 sa.Column("pinned_repo_ids", sa.JSON(), nullable=False, server_default="[]"),
450 sa.Column(
451 "created_at",
452 sa.DateTime(timezone=True),
453 nullable=False,
454 server_default=sa.text("CURRENT_TIMESTAMP"),
455 ),
456 sa.Column(
457 "updated_at",
458 sa.DateTime(timezone=True),
459 nullable=False,
460 server_default=sa.text("CURRENT_TIMESTAMP"),
461 ),
462 sa.PrimaryKeyConstraint("user_id"),
463 sa.UniqueConstraint("username", name="uq_musehub_profiles_username"),
464 )
465 op.create_index("ix_musehub_profiles_username", "musehub_profiles", ["username"])
466 op.create_index("ix_musehub_profiles_is_verified", "musehub_profiles", ["is_verified"])
467
468 # ── MuseHub — webhook subscriptions ─────────────────────────────────
469 op.create_table(
470 "musehub_webhooks",
471 sa.Column("webhook_id", sa.String(36), nullable=False),
472 sa.Column("repo_id", sa.String(36), nullable=False),
473 sa.Column("url", sa.String(2048), nullable=False),
474 sa.Column("events", sa.JSON(), nullable=False, server_default="[]"),
475 sa.Column("secret", sa.Text(), nullable=False, server_default=""),
476 sa.Column("active", sa.Boolean(), nullable=False, server_default="true"),
477 sa.Column(
478 "created_at",
479 sa.DateTime(timezone=True),
480 nullable=False,
481 server_default=sa.text("CURRENT_TIMESTAMP"),
482 ),
483 sa.ForeignKeyConstraint(["repo_id"], ["musehub_repos.repo_id"], ondelete="CASCADE"),
484 sa.PrimaryKeyConstraint("webhook_id"),
485 )
486 op.create_index("ix_musehub_webhooks_repo_id", "musehub_webhooks", ["repo_id"])
487
488 op.create_table(
489 "musehub_webhook_deliveries",
490 sa.Column("delivery_id", sa.String(36), nullable=False),
491 sa.Column("webhook_id", sa.String(36), nullable=False),
492 sa.Column("event_type", sa.String(64), nullable=False),
493 sa.Column("attempt", sa.Integer(), nullable=False, server_default="1"),
494 sa.Column("success", sa.Boolean(), nullable=False, server_default="false"),
495 sa.Column("response_status", sa.Integer(), nullable=False, server_default="0"),
496 sa.Column("response_body", sa.Text(), nullable=False, server_default=""),
497 # JSON-encoded payload stored so failed deliveries can be retried via redeliver endpoint
498 sa.Column("payload", sa.Text(), nullable=False, server_default=""),
499 sa.Column(
500 "delivered_at",
501 sa.DateTime(timezone=True),
502 nullable=False,
503 server_default=sa.text("CURRENT_TIMESTAMP"),
504 ),
505 sa.ForeignKeyConstraint(
506 ["webhook_id"], ["musehub_webhooks.webhook_id"], ondelete="CASCADE"
507 ),
508 sa.PrimaryKeyConstraint("delivery_id"),
509 )
510 op.create_index(
511 "ix_musehub_webhook_deliveries_webhook_id",
512 "musehub_webhook_deliveries",
513 ["webhook_id"],
514 )
515 op.create_index(
516 "ix_musehub_webhook_deliveries_event_type",
517 "musehub_webhook_deliveries",
518 ["event_type"],
519 )
520
521 # ── MuseHub — releases ───────────────────────────────────────────────
522 op.create_table(
523 "musehub_releases",
524 sa.Column("release_id", sa.String(36), nullable=False),
525 sa.Column("repo_id", sa.String(36), nullable=False),
526 sa.Column("tag", sa.String(100), nullable=False),
527 sa.Column("title", sa.String(500), nullable=False),
528 sa.Column("body", sa.Text(), nullable=False, server_default=""),
529 sa.Column("commit_id", sa.String(64), nullable=True),
530 sa.Column("download_urls", sa.JSON(), nullable=False, server_default="{}"),
531 sa.Column("author", sa.String(255), nullable=False, server_default=""),
532 sa.Column("is_prerelease", sa.Boolean(), nullable=False, server_default="false"),
533 sa.Column("is_draft", sa.Boolean(), nullable=False, server_default="false"),
534 sa.Column("gpg_signature", sa.Text(), nullable=True),
535 sa.Column(
536 "created_at",
537 sa.DateTime(timezone=True),
538 nullable=False,
539 server_default=sa.text("CURRENT_TIMESTAMP"),
540 ),
541 sa.ForeignKeyConstraint(["repo_id"], ["musehub_repos.repo_id"], ondelete="CASCADE"),
542 sa.PrimaryKeyConstraint("release_id"),
543 sa.UniqueConstraint("repo_id", "tag", name="uq_musehub_releases_repo_tag"),
544 )
545 op.create_index("ix_musehub_releases_repo_id", "musehub_releases", ["repo_id"])
546 op.create_index("ix_musehub_releases_tag", "musehub_releases", ["tag"])
547
548 # ── MuseHub — release assets ─────────────────────────────────────────
549 op.create_table(
550 "musehub_release_assets",
551 sa.Column("asset_id", sa.String(36), nullable=False),
552 sa.Column("release_id", sa.String(36), nullable=False),
553 sa.Column("repo_id", sa.String(36), nullable=False),
554 sa.Column("name", sa.String(500), nullable=False),
555 sa.Column("label", sa.String(255), nullable=False, server_default=""),
556 sa.Column("content_type", sa.String(128), nullable=False, server_default=""),
557 sa.Column("size", sa.Integer(), nullable=False, server_default="0"),
558 sa.Column("download_url", sa.String(2048), nullable=False),
559 sa.Column("download_count", sa.Integer(), nullable=False, server_default="0"),
560 sa.Column(
561 "created_at",
562 sa.DateTime(timezone=True),
563 nullable=False,
564 server_default=sa.text("CURRENT_TIMESTAMP"),
565 ),
566 sa.ForeignKeyConstraint(
567 ["release_id"], ["musehub_releases.release_id"], ondelete="CASCADE"
568 ),
569 sa.PrimaryKeyConstraint("asset_id"),
570 )
571 op.create_index(
572 "ix_musehub_release_assets_release_id", "musehub_release_assets", ["release_id"]
573 )
574 op.create_index(
575 "ix_musehub_release_assets_repo_id", "musehub_release_assets", ["repo_id"]
576 )
577
578 # ── MuseHub — social layer ────────────────────────────────────────────
579 op.create_table(
580 "musehub_comments",
581 sa.Column("comment_id", sa.String(36), nullable=False),
582 sa.Column("repo_id", sa.String(36), nullable=False),
583 sa.Column("target_type", sa.String(20), nullable=False),
584 sa.Column("target_id", sa.String(255), nullable=False),
585 sa.Column("author", sa.String(255), nullable=False),
586 sa.Column("body", sa.Text(), nullable=False),
587 sa.Column("parent_id", sa.String(36), nullable=True),
588 sa.Column("is_deleted", sa.Boolean(), nullable=False, server_default="false"),
589 sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("CURRENT_TIMESTAMP")),
590 sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("CURRENT_TIMESTAMP")),
591 sa.ForeignKeyConstraint(["repo_id"], ["musehub_repos.repo_id"], ondelete="CASCADE"),
592 sa.PrimaryKeyConstraint("comment_id"),
593 )
594 op.create_index("ix_musehub_comments_repo_id", "musehub_comments", ["repo_id"])
595 op.create_index("ix_musehub_comments_author", "musehub_comments", ["author"])
596 op.create_index("ix_musehub_comments_created_at", "musehub_comments", ["created_at"])
597 op.create_index("ix_musehub_comments_target_type", "musehub_comments", ["target_type"])
598 op.create_index("ix_musehub_comments_target_id", "musehub_comments", ["target_id"])
599
600 op.create_table(
601 "musehub_reactions",
602 sa.Column("reaction_id", sa.String(36), nullable=False),
603 sa.Column("repo_id", sa.String(36), nullable=False),
604 sa.Column("target_type", sa.String(20), nullable=False),
605 sa.Column("target_id", sa.String(255), nullable=False),
606 sa.Column("user_id", sa.String(255), nullable=False),
607 sa.Column("emoji", sa.String(10), nullable=False),
608 sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("CURRENT_TIMESTAMP")),
609 sa.PrimaryKeyConstraint("reaction_id"),
610 sa.UniqueConstraint("user_id", "target_type", "target_id", "emoji", name="uq_musehub_reactions"),
611 )
612 op.create_index("ix_musehub_reactions_repo_id", "musehub_reactions", ["repo_id"])
613 op.create_index("ix_musehub_reactions_target_type", "musehub_reactions", ["target_type"])
614 op.create_index("ix_musehub_reactions_target_id", "musehub_reactions", ["target_id"])
615 op.create_index("ix_musehub_reactions_user_id", "musehub_reactions", ["user_id"])
616
617 op.create_table(
618 "musehub_follows",
619 sa.Column("follow_id", sa.String(36), nullable=False),
620 sa.Column("follower_id", sa.String(255), nullable=False),
621 sa.Column("followee_id", sa.String(255), nullable=False),
622 sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("CURRENT_TIMESTAMP")),
623 sa.PrimaryKeyConstraint("follow_id"),
624 sa.UniqueConstraint("follower_id", "followee_id", name="uq_musehub_follows"),
625 )
626 op.create_index("ix_musehub_follows_follower_id", "musehub_follows", ["follower_id"])
627 op.create_index("ix_musehub_follows_followee_id", "musehub_follows", ["followee_id"])
628
629 op.create_table(
630 "musehub_watches",
631 sa.Column("watch_id", sa.String(36), nullable=False),
632 sa.Column("user_id", sa.String(255), nullable=False),
633 sa.Column("repo_id", sa.String(36), nullable=False),
634 sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("CURRENT_TIMESTAMP")),
635 sa.ForeignKeyConstraint(["repo_id"], ["musehub_repos.repo_id"], ondelete="CASCADE"),
636 sa.PrimaryKeyConstraint("watch_id"),
637 sa.UniqueConstraint("user_id", "repo_id", name="uq_musehub_watches"),
638 )
639 op.create_index("ix_musehub_watches_user_id", "musehub_watches", ["user_id"])
640 op.create_index("ix_musehub_watches_repo_id", "musehub_watches", ["repo_id"])
641
642 op.create_table(
643 "musehub_notifications",
644 sa.Column("notif_id", sa.String(36), nullable=False),
645 sa.Column("recipient_id", sa.String(255), nullable=False),
646 sa.Column("event_type", sa.String(40), nullable=False),
647 sa.Column("repo_id", sa.String(36), nullable=True),
648 sa.Column("actor", sa.String(255), nullable=False),
649 sa.Column("payload", sa.JSON(), nullable=False, server_default="{}"),
650 sa.Column("is_read", sa.Boolean(), nullable=False, server_default="false"),
651 sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("CURRENT_TIMESTAMP")),
652 sa.PrimaryKeyConstraint("notif_id"),
653 )
654 op.create_index("ix_musehub_notifications_recipient_id", "musehub_notifications", ["recipient_id"])
655 op.create_index("ix_musehub_notifications_is_read", "musehub_notifications", ["is_read"])
656 op.create_index("ix_musehub_notifications_created_at", "musehub_notifications", ["created_at"])
657
658 op.create_table(
659 "musehub_forks",
660 sa.Column("fork_id", sa.String(36), nullable=False),
661 sa.Column("source_repo_id", sa.String(36), nullable=False),
662 sa.Column("fork_repo_id", sa.String(36), nullable=False),
663 sa.Column("forked_by", sa.String(255), nullable=False),
664 sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("CURRENT_TIMESTAMP")),
665 sa.ForeignKeyConstraint(["source_repo_id"], ["musehub_repos.repo_id"], ondelete="CASCADE"),
666 sa.ForeignKeyConstraint(["fork_repo_id"], ["musehub_repos.repo_id"], ondelete="CASCADE"),
667 sa.PrimaryKeyConstraint("fork_id"),
668 sa.UniqueConstraint("source_repo_id", "fork_repo_id", name="uq_musehub_forks"),
669 )
670 op.create_index("ix_musehub_forks_source_repo_id", "musehub_forks", ["source_repo_id"])
671 op.create_index("ix_musehub_forks_fork_repo_id", "musehub_forks", ["fork_repo_id"])
672
673 op.create_table(
674 "musehub_view_events",
675 sa.Column("view_id", sa.String(36), nullable=False),
676 sa.Column("repo_id", sa.String(36), nullable=False),
677 sa.Column("viewer_fingerprint", sa.String(64), nullable=False),
678 sa.Column("event_date", sa.String(10), nullable=False),
679 sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("CURRENT_TIMESTAMP")),
680 sa.ForeignKeyConstraint(["repo_id"], ["musehub_repos.repo_id"], ondelete="CASCADE"),
681 sa.PrimaryKeyConstraint("view_id"),
682 sa.UniqueConstraint("repo_id", "viewer_fingerprint", "event_date", name="uq_musehub_view_events"),
683 )
684 op.create_index("ix_musehub_view_events_repo_id", "musehub_view_events", ["repo_id"])
685
686 op.create_table(
687 "musehub_download_events",
688 sa.Column("dl_id", sa.String(36), nullable=False),
689 sa.Column("repo_id", sa.String(36), nullable=False),
690 sa.Column("ref", sa.String(255), nullable=False),
691 sa.Column("downloader_id", sa.String(255), nullable=True),
692 sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("CURRENT_TIMESTAMP")),
693 sa.ForeignKeyConstraint(["repo_id"], ["musehub_repos.repo_id"], ondelete="CASCADE"),
694 sa.PrimaryKeyConstraint("dl_id"),
695 )
696 op.create_index("ix_musehub_download_events_repo_id", "musehub_download_events", ["repo_id"])
697 op.create_index("ix_musehub_download_events_created_at", "musehub_download_events", ["created_at"])
698
699 # ── MuseHub — render pipeline ─────────────────────────────────────────
700 op.create_table(
701 "musehub_render_jobs",
702 sa.Column("render_job_id", sa.String(36), nullable=False),
703 sa.Column("repo_id", sa.String(36), nullable=False),
704 sa.Column("commit_id", sa.String(64), nullable=False),
705 sa.Column("status", sa.String(20), nullable=False, server_default="pending"),
706 sa.Column("error_message", sa.Text(), nullable=True),
707 sa.Column("midi_count", sa.Integer(), nullable=False, server_default="0"),
708 sa.Column("mp3_object_ids", sa.JSON(), nullable=False, server_default="[]"),
709 sa.Column("image_object_ids", sa.JSON(), nullable=False, server_default="[]"),
710 sa.Column(
711 "created_at",
712 sa.DateTime(timezone=True),
713 nullable=False,
714 server_default=sa.text("CURRENT_TIMESTAMP"),
715 ),
716 sa.Column(
717 "updated_at",
718 sa.DateTime(timezone=True),
719 nullable=False,
720 server_default=sa.text("CURRENT_TIMESTAMP"),
721 ),
722 sa.ForeignKeyConstraint(["repo_id"], ["musehub_repos.repo_id"], ondelete="CASCADE"),
723 sa.PrimaryKeyConstraint("render_job_id"),
724 sa.UniqueConstraint("repo_id", "commit_id", name="uq_musehub_render_jobs_repo_commit"),
725 )
726 op.create_index("ix_musehub_render_jobs_repo_id", "musehub_render_jobs", ["repo_id"])
727 op.create_index("ix_musehub_render_jobs_commit_id", "musehub_render_jobs", ["commit_id"])
728 op.create_index("ix_musehub_render_jobs_status", "musehub_render_jobs", ["status"])
729
730 # ── MuseHub — activity event stream ──────────────────────────────────
731 op.create_table(
732 "musehub_events",
733 sa.Column("event_id", sa.String(36), nullable=False),
734 sa.Column("repo_id", sa.String(36), nullable=False),
735 sa.Column("event_type", sa.String(40), nullable=False),
736 sa.Column("actor", sa.String(255), nullable=False),
737 sa.Column("description", sa.Text(), nullable=False, server_default=""),
738 sa.Column("event_metadata", sa.JSON(), nullable=False, server_default="{}"),
739 sa.Column(
740 "created_at",
741 sa.DateTime(timezone=True),
742 nullable=False,
743 server_default=sa.text("CURRENT_TIMESTAMP"),
744 ),
745 sa.ForeignKeyConstraint(["repo_id"], ["musehub_repos.repo_id"], ondelete="CASCADE"),
746 sa.PrimaryKeyConstraint("event_id"),
747 )
748 op.create_index("ix_musehub_events_repo_id", "musehub_events", ["repo_id"])
749 op.create_index("ix_musehub_events_event_type", "musehub_events", ["event_type"])
750 op.create_index("ix_musehub_events_created_at", "musehub_events", ["created_at"])
751
752 # ── MuseHub — labels ─────────────────────────────────────────────────
753 op.create_table(
754 "musehub_labels",
755 sa.Column("id", sa.String(36), nullable=False),
756 sa.Column("repo_id", sa.String(36), nullable=False),
757 sa.Column("name", sa.String(50), nullable=False),
758 sa.Column("color", sa.String(7), nullable=False),
759 sa.Column("description", sa.String(200), nullable=True),
760 sa.Column(
761 "created_at",
762 sa.DateTime(timezone=True),
763 nullable=False,
764 server_default=sa.text("CURRENT_TIMESTAMP"),
765 ),
766 sa.ForeignKeyConstraint(["repo_id"], ["musehub_repos.repo_id"], ondelete="CASCADE"),
767 sa.PrimaryKeyConstraint("id"),
768 sa.UniqueConstraint("repo_id", "name", name="uq_musehub_labels_repo_name"),
769 )
770 op.create_index("ix_musehub_labels_repo_id", "musehub_labels", ["repo_id"])
771
772 op.create_table(
773 "musehub_issue_labels",
774 sa.Column("issue_id", sa.String(36), nullable=False),
775 sa.Column("label_id", sa.String(36), nullable=False),
776 sa.ForeignKeyConstraint(["issue_id"], ["musehub_issues.issue_id"], ondelete="CASCADE"),
777 sa.ForeignKeyConstraint(["label_id"], ["musehub_labels.id"], ondelete="CASCADE"),
778 sa.PrimaryKeyConstraint("issue_id", "label_id"),
779 )
780 op.create_index("ix_musehub_issue_labels_label_id", "musehub_issue_labels", ["label_id"])
781
782 op.create_table(
783 "musehub_pr_labels",
784 sa.Column("pr_id", sa.String(36), nullable=False),
785 sa.Column("label_id", sa.String(36), nullable=False),
786 sa.ForeignKeyConstraint(["pr_id"], ["musehub_pull_requests.pr_id"], ondelete="CASCADE"),
787 sa.ForeignKeyConstraint(["label_id"], ["musehub_labels.id"], ondelete="CASCADE"),
788 sa.PrimaryKeyConstraint("pr_id", "label_id"),
789 )
790 op.create_index("ix_musehub_pr_labels_label_id", "musehub_pr_labels", ["label_id"])
791
792 # ── MuseHub — collaborators ──────────────────────────────────────────
793 op.create_table(
794 "musehub_collaborators",
795 sa.Column("id", sa.String(36), nullable=False),
796 sa.Column("repo_id", sa.String(36), nullable=False),
797 sa.Column("user_id", sa.String(36), nullable=False),
798 sa.Column("permission", sa.String(20), nullable=False, server_default="write"),
799 sa.Column("invited_by", sa.String(36), nullable=True),
800 sa.Column(
801 "invited_at",
802 sa.DateTime(timezone=True),
803 nullable=False,
804 server_default=sa.text("CURRENT_TIMESTAMP"),
805 ),
806 sa.Column("accepted_at", sa.DateTime(timezone=True), nullable=True),
807 sa.ForeignKeyConstraint(["repo_id"], ["musehub_repos.repo_id"], ondelete="CASCADE"),
808 sa.ForeignKeyConstraint(["user_id"], ["muse_users.id"], ondelete="CASCADE"),
809 sa.ForeignKeyConstraint(["invited_by"], ["muse_users.id"], ondelete="SET NULL"),
810 sa.PrimaryKeyConstraint("id"),
811 sa.UniqueConstraint("repo_id", "user_id", name="uq_musehub_collaborators_repo_user"),
812 )
813 op.create_index("ix_musehub_collaborators_repo_id", "musehub_collaborators", ["repo_id"])
814 op.create_index("ix_musehub_collaborators_user_id", "musehub_collaborators", ["user_id"])
815
816 # ── MuseHub — stash ──────────────────────────────────────────────────
817 op.create_table(
818 "musehub_stash",
819 sa.Column("id", sa.String(36), nullable=False),
820 sa.Column("repo_id", sa.String(36), nullable=False),
821 sa.Column("user_id", sa.String(36), nullable=False),
822 sa.Column("branch", sa.String(255), nullable=False),
823 sa.Column("message", sa.String(500), nullable=True),
824 sa.Column("is_applied", sa.Boolean(), nullable=False, server_default=sa.false()),
825 sa.Column(
826 "created_at",
827 sa.DateTime(timezone=True),
828 nullable=False,
829 server_default=sa.text("CURRENT_TIMESTAMP"),
830 ),
831 sa.Column("applied_at", sa.DateTime(timezone=True), nullable=True),
832 sa.ForeignKeyConstraint(["repo_id"], ["musehub_repos.repo_id"], ondelete="CASCADE"),
833 sa.ForeignKeyConstraint(["user_id"], ["muse_users.id"], ondelete="CASCADE"),
834 sa.PrimaryKeyConstraint("id"),
835 )
836 op.create_index("ix_musehub_stash_repo_id", "musehub_stash", ["repo_id"])
837 op.create_index("ix_musehub_stash_user_id", "musehub_stash", ["user_id"])
838
839 op.create_table(
840 "musehub_stash_entries",
841 sa.Column("id", sa.String(36), nullable=False),
842 sa.Column("stash_id", sa.String(36), nullable=False),
843 sa.Column("path", sa.String(1024), nullable=False),
844 sa.Column("object_id", sa.String(128), nullable=False),
845 sa.Column("position", sa.Integer(), nullable=False),
846 sa.ForeignKeyConstraint(["stash_id"], ["musehub_stash.id"], ondelete="CASCADE"),
847 sa.PrimaryKeyConstraint("id"),
848 )
849 op.create_index("ix_musehub_stash_entries_stash_id", "musehub_stash_entries", ["stash_id"])
850
851 # ── MuseHub — PR reviews ─────────────────────────────────────────────
852 op.create_table(
853 "musehub_pr_reviews",
854 sa.Column("id", sa.String(36), nullable=False),
855 sa.Column("pr_id", sa.String(36), nullable=False),
856 sa.Column("reviewer_username", sa.String(255), nullable=False),
857 sa.Column("state", sa.String(30), nullable=False, server_default="pending"),
858 sa.Column("body", sa.Text(), nullable=True),
859 sa.Column("submitted_at", sa.DateTime(timezone=True), nullable=True),
860 sa.Column(
861 "created_at",
862 sa.DateTime(timezone=True),
863 nullable=False,
864 server_default=sa.text("CURRENT_TIMESTAMP"),
865 ),
866 sa.ForeignKeyConstraint(
867 ["pr_id"],
868 ["musehub_pull_requests.pr_id"],
869 ondelete="CASCADE",
870 ),
871 sa.PrimaryKeyConstraint("id"),
872 )
873 op.create_index("ix_musehub_pr_reviews_pr_id", "musehub_pr_reviews", ["pr_id"])
874 op.create_index(
875 "ix_musehub_pr_reviews_reviewer_username",
876 "musehub_pr_reviews",
877 ["reviewer_username"],
878 )
879 op.create_index("ix_musehub_pr_reviews_state", "musehub_pr_reviews", ["state"])
880
881
882 def downgrade() -> None:
883 # Drop in reverse creation order, respecting foreign-key dependencies.
884
885 op.drop_index("ix_musehub_pr_reviews_state", table_name="musehub_pr_reviews")
886 op.drop_index("ix_musehub_pr_reviews_reviewer_username", table_name="musehub_pr_reviews")
887 op.drop_index("ix_musehub_pr_reviews_pr_id", table_name="musehub_pr_reviews")
888 op.drop_table("musehub_pr_reviews")
889
890 op.drop_index("ix_musehub_stash_entries_stash_id", table_name="musehub_stash_entries")
891 op.drop_table("musehub_stash_entries")
892 op.drop_index("ix_musehub_stash_user_id", table_name="musehub_stash")
893 op.drop_index("ix_musehub_stash_repo_id", table_name="musehub_stash")
894 op.drop_table("musehub_stash")
895
896 op.drop_index("ix_musehub_collaborators_user_id", table_name="musehub_collaborators")
897 op.drop_index("ix_musehub_collaborators_repo_id", table_name="musehub_collaborators")
898 op.drop_table("musehub_collaborators")
899
900 op.drop_index("ix_musehub_pr_labels_label_id", table_name="musehub_pr_labels")
901 op.drop_table("musehub_pr_labels")
902 op.drop_index("ix_musehub_issue_labels_label_id", table_name="musehub_issue_labels")
903 op.drop_table("musehub_issue_labels")
904 op.drop_index("ix_musehub_labels_repo_id", table_name="musehub_labels")
905 op.drop_table("musehub_labels")
906
907 op.drop_index("ix_musehub_events_created_at", table_name="musehub_events")
908 op.drop_index("ix_musehub_events_event_type", table_name="musehub_events")
909 op.drop_index("ix_musehub_events_repo_id", table_name="musehub_events")
910 op.drop_table("musehub_events")
911
912 op.drop_index("ix_musehub_render_jobs_status", table_name="musehub_render_jobs")
913 op.drop_index("ix_musehub_render_jobs_commit_id", table_name="musehub_render_jobs")
914 op.drop_index("ix_musehub_render_jobs_repo_id", table_name="musehub_render_jobs")
915 op.drop_table("musehub_render_jobs")
916
917 op.drop_index("ix_musehub_download_events_created_at", table_name="musehub_download_events")
918 op.drop_index("ix_musehub_download_events_repo_id", table_name="musehub_download_events")
919 op.drop_table("musehub_download_events")
920 op.drop_index("ix_musehub_view_events_repo_id", table_name="musehub_view_events")
921 op.drop_table("musehub_view_events")
922 op.drop_index("ix_musehub_forks_fork_repo_id", table_name="musehub_forks")
923 op.drop_index("ix_musehub_forks_source_repo_id", table_name="musehub_forks")
924 op.drop_table("musehub_forks")
925 op.drop_index("ix_musehub_notifications_created_at", table_name="musehub_notifications")
926 op.drop_index("ix_musehub_notifications_is_read", table_name="musehub_notifications")
927 op.drop_index("ix_musehub_notifications_recipient_id", table_name="musehub_notifications")
928 op.drop_table("musehub_notifications")
929 op.drop_index("ix_musehub_watches_repo_id", table_name="musehub_watches")
930 op.drop_index("ix_musehub_watches_user_id", table_name="musehub_watches")
931 op.drop_table("musehub_watches")
932 op.drop_index("ix_musehub_follows_followee_id", table_name="musehub_follows")
933 op.drop_index("ix_musehub_follows_follower_id", table_name="musehub_follows")
934 op.drop_table("musehub_follows")
935 op.drop_index("ix_musehub_reactions_user_id", table_name="musehub_reactions")
936 op.drop_index("ix_musehub_reactions_target_id", table_name="musehub_reactions")
937 op.drop_index("ix_musehub_reactions_target_type", table_name="musehub_reactions")
938 op.drop_index("ix_musehub_reactions_repo_id", table_name="musehub_reactions")
939 op.drop_table("musehub_reactions")
940 op.drop_index("ix_musehub_comments_target_id", table_name="musehub_comments")
941 op.drop_index("ix_musehub_comments_target_type", table_name="musehub_comments")
942 op.drop_index("ix_musehub_comments_created_at", table_name="musehub_comments")
943 op.drop_index("ix_musehub_comments_author", table_name="musehub_comments")
944 op.drop_index("ix_musehub_comments_repo_id", table_name="musehub_comments")
945 op.drop_table("musehub_comments")
946
947 op.drop_index("ix_musehub_profiles_is_verified", table_name="musehub_profiles")
948 op.drop_index("ix_musehub_profiles_username", table_name="musehub_profiles")
949 op.drop_table("musehub_profiles")
950
951 op.drop_index("ix_musehub_webhook_deliveries_event_type", table_name="musehub_webhook_deliveries")
952 op.drop_index("ix_musehub_webhook_deliveries_webhook_id", table_name="musehub_webhook_deliveries")
953 op.drop_table("musehub_webhook_deliveries")
954 op.drop_index("ix_musehub_webhooks_repo_id", table_name="musehub_webhooks")
955 op.drop_table("musehub_webhooks")
956
957 op.drop_index("ix_musehub_release_assets_repo_id", table_name="musehub_release_assets")
958 op.drop_index("ix_musehub_release_assets_release_id", table_name="musehub_release_assets")
959 op.drop_table("musehub_release_assets")
960 op.drop_index("ix_musehub_releases_tag", table_name="musehub_releases")
961 op.drop_index("ix_musehub_releases_repo_id", table_name="musehub_releases")
962 op.drop_table("musehub_releases")
963
964 op.drop_index("ix_musehub_sessions_is_active", table_name="musehub_sessions")
965 op.drop_index("ix_musehub_sessions_started_at", table_name="musehub_sessions")
966 op.drop_index("ix_musehub_sessions_repo_id", table_name="musehub_sessions")
967 op.drop_table("musehub_sessions")
968
969 op.drop_index("ix_musehub_stars_user_id", table_name="musehub_stars")
970 op.drop_index("ix_musehub_stars_repo_id", table_name="musehub_stars")
971 op.drop_table("musehub_stars")
972
973 op.drop_index("ix_musehub_objects_repo_id", table_name="musehub_objects")
974 op.drop_table("musehub_objects")
975
976 op.drop_index("ix_musehub_pr_comments_created_at", table_name="musehub_pr_comments")
977 op.drop_index("ix_musehub_pr_comments_parent_comment_id", table_name="musehub_pr_comments")
978 op.drop_index("ix_musehub_pr_comments_repo_id", table_name="musehub_pr_comments")
979 op.drop_index("ix_musehub_pr_comments_pr_id", table_name="musehub_pr_comments")
980 op.drop_table("musehub_pr_comments")
981
982 op.drop_index("ix_musehub_pull_requests_state", table_name="musehub_pull_requests")
983 op.drop_index("ix_musehub_pull_requests_repo_id", table_name="musehub_pull_requests")
984 op.drop_table("musehub_pull_requests")
985
986 op.drop_index("ix_musehub_issue_comments_created_at", table_name="musehub_issue_comments")
987 op.drop_index("ix_musehub_issue_comments_parent_id", table_name="musehub_issue_comments")
988 op.drop_index("ix_musehub_issue_comments_repo_id", table_name="musehub_issue_comments")
989 op.drop_index("ix_musehub_issue_comments_issue_id", table_name="musehub_issue_comments")
990 op.drop_table("musehub_issue_comments")
991
992 op.drop_index("ix_musehub_issue_milestones_milestone_id", table_name="musehub_issue_milestones")
993 op.drop_table("musehub_issue_milestones")
994
995 op.drop_index("ix_musehub_issues_milestone_id", table_name="musehub_issues")
996 op.drop_index("ix_musehub_issues_state", table_name="musehub_issues")
997 op.drop_index("ix_musehub_issues_number", table_name="musehub_issues")
998 op.drop_index("ix_musehub_issues_repo_id", table_name="musehub_issues")
999 op.drop_table("musehub_issues")
1000
1001 op.drop_index("ix_musehub_milestones_state", table_name="musehub_milestones")
1002 op.drop_index("ix_musehub_milestones_number", table_name="musehub_milestones")
1003 op.drop_index("ix_musehub_milestones_repo_id", table_name="musehub_milestones")
1004 op.drop_table("musehub_milestones")
1005
1006 op.drop_index("ix_musehub_commits_timestamp", table_name="musehub_commits")
1007 op.drop_index("ix_musehub_commits_branch", table_name="musehub_commits")
1008 op.drop_index("ix_musehub_commits_repo_id", table_name="musehub_commits")
1009 op.drop_table("musehub_commits")
1010
1011 op.drop_index("ix_musehub_branches_repo_id", table_name="musehub_branches")
1012 op.drop_table("musehub_branches")
1013
1014 op.drop_index("ix_musehub_repos_owner_user_id", table_name="musehub_repos")
1015 op.drop_index("ix_musehub_repos_slug", table_name="musehub_repos")
1016 op.drop_index("ix_musehub_repos_owner", table_name="musehub_repos")
1017 op.drop_table("musehub_repos")
1018
1019 op.drop_index("ix_muse_tags_tag", table_name="muse_tags")
1020 op.drop_index("ix_muse_tags_commit_id", table_name="muse_tags")
1021 op.drop_index("ix_muse_tags_repo_id", table_name="muse_tags")
1022 op.drop_table("muse_tags")
1023
1024 op.drop_index("ix_muse_commits_parent2_commit_id", table_name="muse_commits")
1025 op.drop_index("ix_muse_commits_parent_commit_id", table_name="muse_commits")
1026 op.drop_index("ix_muse_commits_repo_id", table_name="muse_commits")
1027 op.drop_table("muse_commits")
1028
1029 op.drop_table("muse_snapshots")
1030 op.drop_table("muse_objects")
1031
1032 op.drop_index("ix_muse_access_tokens_token_hash", table_name="muse_access_tokens")
1033 op.drop_index("ix_muse_access_tokens_user_id", table_name="muse_access_tokens")
1034 op.drop_table("muse_access_tokens")
1035 op.drop_table("muse_users")