Barazo AppView backend barazo.forum

feat(design): add header logo upload and showCommunityName (#131)

* feat(design): add header logo upload and showCommunityName setting

Add header logo upload endpoint (POST /api/admin/design/header-logo) with
fit-inside resize to 600x120 and two new community_settings columns:
header_logo_url and show_community_name. Update settings serialization,
public endpoint, PUT handler, and Zod validation schemas.

* fix(design): regenerate migration with drizzle-kit for proper snapshot

The manually written migration lacked a drizzle-kit snapshot file,
causing the CI Schema Drift Check to fail. Regenerated using
`pnpm db:generate` which produces both the SQL and snapshot.

* fix(design): resolve rebase conflicts and renumber migration to 0006

authored by

Guido X Jansen and committed by
GitHub
e6e99712 d87cb2d9

+4231
+2
drizzle/0006_add_header_logo.sql
··· 1 + ALTER TABLE "community_settings" ADD COLUMN "header_logo_url" text;--> statement-breakpoint 2 + ALTER TABLE "community_settings" ADD COLUMN "show_community_name" boolean DEFAULT true NOT NULL;
+3997
drizzle/meta/0006_snapshot.json
··· 1 + { 2 + "id": "ddab621d-79c2-450e-a5ea-c9ba69e2e35c", 3 + "prevId": "9015e774-1584-45d9-a654-9cf4437fa526", 4 + "version": "7", 5 + "dialect": "postgresql", 6 + "tables": { 7 + "public.users": { 8 + "name": "users", 9 + "schema": "", 10 + "columns": { 11 + "did": { 12 + "name": "did", 13 + "type": "text", 14 + "primaryKey": true, 15 + "notNull": true 16 + }, 17 + "handle": { 18 + "name": "handle", 19 + "type": "text", 20 + "primaryKey": false, 21 + "notNull": true 22 + }, 23 + "display_name": { 24 + "name": "display_name", 25 + "type": "text", 26 + "primaryKey": false, 27 + "notNull": false 28 + }, 29 + "avatar_url": { 30 + "name": "avatar_url", 31 + "type": "text", 32 + "primaryKey": false, 33 + "notNull": false 34 + }, 35 + "banner_url": { 36 + "name": "banner_url", 37 + "type": "text", 38 + "primaryKey": false, 39 + "notNull": false 40 + }, 41 + "bio": { 42 + "name": "bio", 43 + "type": "text", 44 + "primaryKey": false, 45 + "notNull": false 46 + }, 47 + "role": { 48 + "name": "role", 49 + "type": "text", 50 + "primaryKey": false, 51 + "notNull": true, 52 + "default": "'user'" 53 + }, 54 + "is_banned": { 55 + "name": "is_banned", 56 + "type": "boolean", 57 + "primaryKey": false, 58 + "notNull": true, 59 + "default": false 60 + }, 61 + "reputation_score": { 62 + "name": "reputation_score", 63 + "type": "integer", 64 + "primaryKey": false, 65 + "notNull": true, 66 + "default": 0 67 + }, 68 + "first_seen_at": { 69 + "name": "first_seen_at", 70 + "type": "timestamp with time zone", 71 + "primaryKey": false, 72 + "notNull": true, 73 + "default": "now()" 74 + }, 75 + "last_active_at": { 76 + "name": "last_active_at", 77 + "type": "timestamp with time zone", 78 + "primaryKey": false, 79 + "notNull": true, 80 + "default": "now()" 81 + }, 82 + "declared_age": { 83 + "name": "declared_age", 84 + "type": "integer", 85 + "primaryKey": false, 86 + "notNull": false 87 + }, 88 + "maturity_pref": { 89 + "name": "maturity_pref", 90 + "type": "text", 91 + "primaryKey": false, 92 + "notNull": true, 93 + "default": "'safe'" 94 + }, 95 + "account_created_at": { 96 + "name": "account_created_at", 97 + "type": "timestamp with time zone", 98 + "primaryKey": false, 99 + "notNull": false 100 + }, 101 + "followers_count": { 102 + "name": "followers_count", 103 + "type": "integer", 104 + "primaryKey": false, 105 + "notNull": true, 106 + "default": 0 107 + }, 108 + "follows_count": { 109 + "name": "follows_count", 110 + "type": "integer", 111 + "primaryKey": false, 112 + "notNull": true, 113 + "default": 0 114 + }, 115 + "atproto_posts_count": { 116 + "name": "atproto_posts_count", 117 + "type": "integer", 118 + "primaryKey": false, 119 + "notNull": true, 120 + "default": 0 121 + }, 122 + "has_bluesky_profile": { 123 + "name": "has_bluesky_profile", 124 + "type": "boolean", 125 + "primaryKey": false, 126 + "notNull": true, 127 + "default": false 128 + }, 129 + "atproto_labels": { 130 + "name": "atproto_labels", 131 + "type": "jsonb", 132 + "primaryKey": false, 133 + "notNull": true, 134 + "default": "'[]'::jsonb" 135 + } 136 + }, 137 + "indexes": { 138 + "users_role_elevated_idx": { 139 + "name": "users_role_elevated_idx", 140 + "columns": [ 141 + { 142 + "expression": "role", 143 + "isExpression": false, 144 + "asc": true, 145 + "nulls": "last" 146 + } 147 + ], 148 + "isUnique": false, 149 + "where": "role IN ('moderator', 'admin')", 150 + "concurrently": false, 151 + "method": "btree", 152 + "with": {} 153 + }, 154 + "users_handle_idx": { 155 + "name": "users_handle_idx", 156 + "columns": [ 157 + { 158 + "expression": "handle", 159 + "isExpression": false, 160 + "asc": true, 161 + "nulls": "last" 162 + } 163 + ], 164 + "isUnique": false, 165 + "concurrently": false, 166 + "method": "btree", 167 + "with": {} 168 + }, 169 + "users_account_created_at_idx": { 170 + "name": "users_account_created_at_idx", 171 + "columns": [ 172 + { 173 + "expression": "account_created_at", 174 + "isExpression": false, 175 + "asc": true, 176 + "nulls": "last" 177 + } 178 + ], 179 + "isUnique": false, 180 + "concurrently": false, 181 + "method": "btree", 182 + "with": {} 183 + } 184 + }, 185 + "foreignKeys": {}, 186 + "compositePrimaryKeys": {}, 187 + "uniqueConstraints": {}, 188 + "policies": {}, 189 + "checkConstraints": {}, 190 + "isRLSEnabled": false 191 + }, 192 + "public.firehose_cursor": { 193 + "name": "firehose_cursor", 194 + "schema": "", 195 + "columns": { 196 + "id": { 197 + "name": "id", 198 + "type": "text", 199 + "primaryKey": true, 200 + "notNull": true, 201 + "default": "'default'" 202 + }, 203 + "cursor": { 204 + "name": "cursor", 205 + "type": "bigint", 206 + "primaryKey": false, 207 + "notNull": false 208 + }, 209 + "updated_at": { 210 + "name": "updated_at", 211 + "type": "timestamp with time zone", 212 + "primaryKey": false, 213 + "notNull": true, 214 + "default": "now()" 215 + } 216 + }, 217 + "indexes": {}, 218 + "foreignKeys": {}, 219 + "compositePrimaryKeys": {}, 220 + "uniqueConstraints": {}, 221 + "policies": {}, 222 + "checkConstraints": {}, 223 + "isRLSEnabled": false 224 + }, 225 + "public.topics": { 226 + "name": "topics", 227 + "schema": "", 228 + "columns": { 229 + "uri": { 230 + "name": "uri", 231 + "type": "text", 232 + "primaryKey": true, 233 + "notNull": true 234 + }, 235 + "rkey": { 236 + "name": "rkey", 237 + "type": "text", 238 + "primaryKey": false, 239 + "notNull": true 240 + }, 241 + "author_did": { 242 + "name": "author_did", 243 + "type": "text", 244 + "primaryKey": false, 245 + "notNull": true 246 + }, 247 + "title": { 248 + "name": "title", 249 + "type": "text", 250 + "primaryKey": false, 251 + "notNull": true 252 + }, 253 + "content": { 254 + "name": "content", 255 + "type": "text", 256 + "primaryKey": false, 257 + "notNull": true 258 + }, 259 + "content_format": { 260 + "name": "content_format", 261 + "type": "text", 262 + "primaryKey": false, 263 + "notNull": false 264 + }, 265 + "category": { 266 + "name": "category", 267 + "type": "text", 268 + "primaryKey": false, 269 + "notNull": true 270 + }, 271 + "tags": { 272 + "name": "tags", 273 + "type": "jsonb", 274 + "primaryKey": false, 275 + "notNull": false 276 + }, 277 + "community_did": { 278 + "name": "community_did", 279 + "type": "text", 280 + "primaryKey": false, 281 + "notNull": true 282 + }, 283 + "cid": { 284 + "name": "cid", 285 + "type": "text", 286 + "primaryKey": false, 287 + "notNull": true 288 + }, 289 + "labels": { 290 + "name": "labels", 291 + "type": "jsonb", 292 + "primaryKey": false, 293 + "notNull": false 294 + }, 295 + "reply_count": { 296 + "name": "reply_count", 297 + "type": "integer", 298 + "primaryKey": false, 299 + "notNull": true, 300 + "default": 0 301 + }, 302 + "reaction_count": { 303 + "name": "reaction_count", 304 + "type": "integer", 305 + "primaryKey": false, 306 + "notNull": true, 307 + "default": 0 308 + }, 309 + "vote_count": { 310 + "name": "vote_count", 311 + "type": "integer", 312 + "primaryKey": false, 313 + "notNull": true, 314 + "default": 0 315 + }, 316 + "last_activity_at": { 317 + "name": "last_activity_at", 318 + "type": "timestamp with time zone", 319 + "primaryKey": false, 320 + "notNull": true, 321 + "default": "now()" 322 + }, 323 + "created_at": { 324 + "name": "created_at", 325 + "type": "timestamp with time zone", 326 + "primaryKey": false, 327 + "notNull": true 328 + }, 329 + "indexed_at": { 330 + "name": "indexed_at", 331 + "type": "timestamp with time zone", 332 + "primaryKey": false, 333 + "notNull": true, 334 + "default": "now()" 335 + }, 336 + "is_locked": { 337 + "name": "is_locked", 338 + "type": "boolean", 339 + "primaryKey": false, 340 + "notNull": true, 341 + "default": false 342 + }, 343 + "is_pinned": { 344 + "name": "is_pinned", 345 + "type": "boolean", 346 + "primaryKey": false, 347 + "notNull": true, 348 + "default": false 349 + }, 350 + "is_mod_deleted": { 351 + "name": "is_mod_deleted", 352 + "type": "boolean", 353 + "primaryKey": false, 354 + "notNull": true, 355 + "default": false 356 + }, 357 + "is_author_deleted": { 358 + "name": "is_author_deleted", 359 + "type": "boolean", 360 + "primaryKey": false, 361 + "notNull": true, 362 + "default": false 363 + }, 364 + "moderation_status": { 365 + "name": "moderation_status", 366 + "type": "text", 367 + "primaryKey": false, 368 + "notNull": true, 369 + "default": "'approved'" 370 + }, 371 + "trust_status": { 372 + "name": "trust_status", 373 + "type": "text", 374 + "primaryKey": false, 375 + "notNull": true, 376 + "default": "'trusted'" 377 + } 378 + }, 379 + "indexes": { 380 + "topics_author_did_idx": { 381 + "name": "topics_author_did_idx", 382 + "columns": [ 383 + { 384 + "expression": "author_did", 385 + "isExpression": false, 386 + "asc": true, 387 + "nulls": "last" 388 + } 389 + ], 390 + "isUnique": false, 391 + "concurrently": false, 392 + "method": "btree", 393 + "with": {} 394 + }, 395 + "topics_category_idx": { 396 + "name": "topics_category_idx", 397 + "columns": [ 398 + { 399 + "expression": "category", 400 + "isExpression": false, 401 + "asc": true, 402 + "nulls": "last" 403 + } 404 + ], 405 + "isUnique": false, 406 + "concurrently": false, 407 + "method": "btree", 408 + "with": {} 409 + }, 410 + "topics_created_at_idx": { 411 + "name": "topics_created_at_idx", 412 + "columns": [ 413 + { 414 + "expression": "created_at", 415 + "isExpression": false, 416 + "asc": true, 417 + "nulls": "last" 418 + } 419 + ], 420 + "isUnique": false, 421 + "concurrently": false, 422 + "method": "btree", 423 + "with": {} 424 + }, 425 + "topics_last_activity_at_idx": { 426 + "name": "topics_last_activity_at_idx", 427 + "columns": [ 428 + { 429 + "expression": "last_activity_at", 430 + "isExpression": false, 431 + "asc": true, 432 + "nulls": "last" 433 + } 434 + ], 435 + "isUnique": false, 436 + "concurrently": false, 437 + "method": "btree", 438 + "with": {} 439 + }, 440 + "topics_community_did_idx": { 441 + "name": "topics_community_did_idx", 442 + "columns": [ 443 + { 444 + "expression": "community_did", 445 + "isExpression": false, 446 + "asc": true, 447 + "nulls": "last" 448 + } 449 + ], 450 + "isUnique": false, 451 + "concurrently": false, 452 + "method": "btree", 453 + "with": {} 454 + }, 455 + "topics_moderation_status_idx": { 456 + "name": "topics_moderation_status_idx", 457 + "columns": [ 458 + { 459 + "expression": "moderation_status", 460 + "isExpression": false, 461 + "asc": true, 462 + "nulls": "last" 463 + } 464 + ], 465 + "isUnique": false, 466 + "concurrently": false, 467 + "method": "btree", 468 + "with": {} 469 + }, 470 + "topics_trust_status_idx": { 471 + "name": "topics_trust_status_idx", 472 + "columns": [ 473 + { 474 + "expression": "trust_status", 475 + "isExpression": false, 476 + "asc": true, 477 + "nulls": "last" 478 + } 479 + ], 480 + "isUnique": false, 481 + "concurrently": false, 482 + "method": "btree", 483 + "with": {} 484 + }, 485 + "topics_community_category_activity_idx": { 486 + "name": "topics_community_category_activity_idx", 487 + "columns": [ 488 + { 489 + "expression": "community_did", 490 + "isExpression": false, 491 + "asc": true, 492 + "nulls": "last" 493 + }, 494 + { 495 + "expression": "category", 496 + "isExpression": false, 497 + "asc": true, 498 + "nulls": "last" 499 + }, 500 + { 501 + "expression": "last_activity_at", 502 + "isExpression": false, 503 + "asc": true, 504 + "nulls": "last" 505 + } 506 + ], 507 + "isUnique": false, 508 + "concurrently": false, 509 + "method": "btree", 510 + "with": {} 511 + } 512 + }, 513 + "foreignKeys": {}, 514 + "compositePrimaryKeys": {}, 515 + "uniqueConstraints": {}, 516 + "policies": { 517 + "tenant_isolation": { 518 + "name": "tenant_isolation", 519 + "as": "PERMISSIVE", 520 + "for": "ALL", 521 + "to": ["barazo_app"], 522 + "using": "community_did = current_setting('app.current_community_did', true)", 523 + "withCheck": "community_did = current_setting('app.current_community_did', true)" 524 + } 525 + }, 526 + "checkConstraints": {}, 527 + "isRLSEnabled": true 528 + }, 529 + "public.replies": { 530 + "name": "replies", 531 + "schema": "", 532 + "columns": { 533 + "uri": { 534 + "name": "uri", 535 + "type": "text", 536 + "primaryKey": true, 537 + "notNull": true 538 + }, 539 + "rkey": { 540 + "name": "rkey", 541 + "type": "text", 542 + "primaryKey": false, 543 + "notNull": true 544 + }, 545 + "author_did": { 546 + "name": "author_did", 547 + "type": "text", 548 + "primaryKey": false, 549 + "notNull": true 550 + }, 551 + "content": { 552 + "name": "content", 553 + "type": "text", 554 + "primaryKey": false, 555 + "notNull": true 556 + }, 557 + "content_format": { 558 + "name": "content_format", 559 + "type": "text", 560 + "primaryKey": false, 561 + "notNull": false 562 + }, 563 + "root_uri": { 564 + "name": "root_uri", 565 + "type": "text", 566 + "primaryKey": false, 567 + "notNull": true 568 + }, 569 + "root_cid": { 570 + "name": "root_cid", 571 + "type": "text", 572 + "primaryKey": false, 573 + "notNull": true 574 + }, 575 + "parent_uri": { 576 + "name": "parent_uri", 577 + "type": "text", 578 + "primaryKey": false, 579 + "notNull": true 580 + }, 581 + "parent_cid": { 582 + "name": "parent_cid", 583 + "type": "text", 584 + "primaryKey": false, 585 + "notNull": true 586 + }, 587 + "community_did": { 588 + "name": "community_did", 589 + "type": "text", 590 + "primaryKey": false, 591 + "notNull": true 592 + }, 593 + "cid": { 594 + "name": "cid", 595 + "type": "text", 596 + "primaryKey": false, 597 + "notNull": true 598 + }, 599 + "labels": { 600 + "name": "labels", 601 + "type": "jsonb", 602 + "primaryKey": false, 603 + "notNull": false 604 + }, 605 + "reaction_count": { 606 + "name": "reaction_count", 607 + "type": "integer", 608 + "primaryKey": false, 609 + "notNull": true, 610 + "default": 0 611 + }, 612 + "vote_count": { 613 + "name": "vote_count", 614 + "type": "integer", 615 + "primaryKey": false, 616 + "notNull": true, 617 + "default": 0 618 + }, 619 + "depth": { 620 + "name": "depth", 621 + "type": "integer", 622 + "primaryKey": false, 623 + "notNull": true, 624 + "default": 1 625 + }, 626 + "created_at": { 627 + "name": "created_at", 628 + "type": "timestamp with time zone", 629 + "primaryKey": false, 630 + "notNull": true 631 + }, 632 + "indexed_at": { 633 + "name": "indexed_at", 634 + "type": "timestamp with time zone", 635 + "primaryKey": false, 636 + "notNull": true, 637 + "default": "now()" 638 + }, 639 + "is_author_deleted": { 640 + "name": "is_author_deleted", 641 + "type": "boolean", 642 + "primaryKey": false, 643 + "notNull": true, 644 + "default": false 645 + }, 646 + "is_mod_deleted": { 647 + "name": "is_mod_deleted", 648 + "type": "boolean", 649 + "primaryKey": false, 650 + "notNull": true, 651 + "default": false 652 + }, 653 + "moderation_status": { 654 + "name": "moderation_status", 655 + "type": "text", 656 + "primaryKey": false, 657 + "notNull": true, 658 + "default": "'approved'" 659 + }, 660 + "trust_status": { 661 + "name": "trust_status", 662 + "type": "text", 663 + "primaryKey": false, 664 + "notNull": true, 665 + "default": "'trusted'" 666 + } 667 + }, 668 + "indexes": { 669 + "replies_author_did_idx": { 670 + "name": "replies_author_did_idx", 671 + "columns": [ 672 + { 673 + "expression": "author_did", 674 + "isExpression": false, 675 + "asc": true, 676 + "nulls": "last" 677 + } 678 + ], 679 + "isUnique": false, 680 + "concurrently": false, 681 + "method": "btree", 682 + "with": {} 683 + }, 684 + "replies_root_uri_idx": { 685 + "name": "replies_root_uri_idx", 686 + "columns": [ 687 + { 688 + "expression": "root_uri", 689 + "isExpression": false, 690 + "asc": true, 691 + "nulls": "last" 692 + } 693 + ], 694 + "isUnique": false, 695 + "concurrently": false, 696 + "method": "btree", 697 + "with": {} 698 + }, 699 + "replies_parent_uri_idx": { 700 + "name": "replies_parent_uri_idx", 701 + "columns": [ 702 + { 703 + "expression": "parent_uri", 704 + "isExpression": false, 705 + "asc": true, 706 + "nulls": "last" 707 + } 708 + ], 709 + "isUnique": false, 710 + "concurrently": false, 711 + "method": "btree", 712 + "with": {} 713 + }, 714 + "replies_created_at_idx": { 715 + "name": "replies_created_at_idx", 716 + "columns": [ 717 + { 718 + "expression": "created_at", 719 + "isExpression": false, 720 + "asc": true, 721 + "nulls": "last" 722 + } 723 + ], 724 + "isUnique": false, 725 + "concurrently": false, 726 + "method": "btree", 727 + "with": {} 728 + }, 729 + "replies_community_did_idx": { 730 + "name": "replies_community_did_idx", 731 + "columns": [ 732 + { 733 + "expression": "community_did", 734 + "isExpression": false, 735 + "asc": true, 736 + "nulls": "last" 737 + } 738 + ], 739 + "isUnique": false, 740 + "concurrently": false, 741 + "method": "btree", 742 + "with": {} 743 + }, 744 + "replies_moderation_status_idx": { 745 + "name": "replies_moderation_status_idx", 746 + "columns": [ 747 + { 748 + "expression": "moderation_status", 749 + "isExpression": false, 750 + "asc": true, 751 + "nulls": "last" 752 + } 753 + ], 754 + "isUnique": false, 755 + "concurrently": false, 756 + "method": "btree", 757 + "with": {} 758 + }, 759 + "replies_trust_status_idx": { 760 + "name": "replies_trust_status_idx", 761 + "columns": [ 762 + { 763 + "expression": "trust_status", 764 + "isExpression": false, 765 + "asc": true, 766 + "nulls": "last" 767 + } 768 + ], 769 + "isUnique": false, 770 + "concurrently": false, 771 + "method": "btree", 772 + "with": {} 773 + }, 774 + "replies_root_uri_created_at_idx": { 775 + "name": "replies_root_uri_created_at_idx", 776 + "columns": [ 777 + { 778 + "expression": "root_uri", 779 + "isExpression": false, 780 + "asc": true, 781 + "nulls": "last" 782 + }, 783 + { 784 + "expression": "created_at", 785 + "isExpression": false, 786 + "asc": true, 787 + "nulls": "last" 788 + } 789 + ], 790 + "isUnique": false, 791 + "concurrently": false, 792 + "method": "btree", 793 + "with": {} 794 + }, 795 + "replies_root_uri_depth_idx": { 796 + "name": "replies_root_uri_depth_idx", 797 + "columns": [ 798 + { 799 + "expression": "root_uri", 800 + "isExpression": false, 801 + "asc": true, 802 + "nulls": "last" 803 + }, 804 + { 805 + "expression": "depth", 806 + "isExpression": false, 807 + "asc": true, 808 + "nulls": "last" 809 + } 810 + ], 811 + "isUnique": false, 812 + "concurrently": false, 813 + "method": "btree", 814 + "with": {} 815 + } 816 + }, 817 + "foreignKeys": {}, 818 + "compositePrimaryKeys": {}, 819 + "uniqueConstraints": {}, 820 + "policies": { 821 + "tenant_isolation": { 822 + "name": "tenant_isolation", 823 + "as": "PERMISSIVE", 824 + "for": "ALL", 825 + "to": ["barazo_app"], 826 + "using": "community_did = current_setting('app.current_community_did', true)", 827 + "withCheck": "community_did = current_setting('app.current_community_did', true)" 828 + } 829 + }, 830 + "checkConstraints": {}, 831 + "isRLSEnabled": true 832 + }, 833 + "public.reactions": { 834 + "name": "reactions", 835 + "schema": "", 836 + "columns": { 837 + "uri": { 838 + "name": "uri", 839 + "type": "text", 840 + "primaryKey": true, 841 + "notNull": true 842 + }, 843 + "rkey": { 844 + "name": "rkey", 845 + "type": "text", 846 + "primaryKey": false, 847 + "notNull": true 848 + }, 849 + "author_did": { 850 + "name": "author_did", 851 + "type": "text", 852 + "primaryKey": false, 853 + "notNull": true 854 + }, 855 + "subject_uri": { 856 + "name": "subject_uri", 857 + "type": "text", 858 + "primaryKey": false, 859 + "notNull": true 860 + }, 861 + "subject_cid": { 862 + "name": "subject_cid", 863 + "type": "text", 864 + "primaryKey": false, 865 + "notNull": true 866 + }, 867 + "type": { 868 + "name": "type", 869 + "type": "text", 870 + "primaryKey": false, 871 + "notNull": true 872 + }, 873 + "community_did": { 874 + "name": "community_did", 875 + "type": "text", 876 + "primaryKey": false, 877 + "notNull": true 878 + }, 879 + "cid": { 880 + "name": "cid", 881 + "type": "text", 882 + "primaryKey": false, 883 + "notNull": true 884 + }, 885 + "created_at": { 886 + "name": "created_at", 887 + "type": "timestamp with time zone", 888 + "primaryKey": false, 889 + "notNull": true 890 + }, 891 + "indexed_at": { 892 + "name": "indexed_at", 893 + "type": "timestamp with time zone", 894 + "primaryKey": false, 895 + "notNull": true, 896 + "default": "now()" 897 + } 898 + }, 899 + "indexes": { 900 + "reactions_author_did_idx": { 901 + "name": "reactions_author_did_idx", 902 + "columns": [ 903 + { 904 + "expression": "author_did", 905 + "isExpression": false, 906 + "asc": true, 907 + "nulls": "last" 908 + } 909 + ], 910 + "isUnique": false, 911 + "concurrently": false, 912 + "method": "btree", 913 + "with": {} 914 + }, 915 + "reactions_subject_uri_idx": { 916 + "name": "reactions_subject_uri_idx", 917 + "columns": [ 918 + { 919 + "expression": "subject_uri", 920 + "isExpression": false, 921 + "asc": true, 922 + "nulls": "last" 923 + } 924 + ], 925 + "isUnique": false, 926 + "concurrently": false, 927 + "method": "btree", 928 + "with": {} 929 + }, 930 + "reactions_community_did_idx": { 931 + "name": "reactions_community_did_idx", 932 + "columns": [ 933 + { 934 + "expression": "community_did", 935 + "isExpression": false, 936 + "asc": true, 937 + "nulls": "last" 938 + } 939 + ], 940 + "isUnique": false, 941 + "concurrently": false, 942 + "method": "btree", 943 + "with": {} 944 + }, 945 + "reactions_subject_uri_type_idx": { 946 + "name": "reactions_subject_uri_type_idx", 947 + "columns": [ 948 + { 949 + "expression": "subject_uri", 950 + "isExpression": false, 951 + "asc": true, 952 + "nulls": "last" 953 + }, 954 + { 955 + "expression": "type", 956 + "isExpression": false, 957 + "asc": true, 958 + "nulls": "last" 959 + } 960 + ], 961 + "isUnique": false, 962 + "concurrently": false, 963 + "method": "btree", 964 + "with": {} 965 + } 966 + }, 967 + "foreignKeys": {}, 968 + "compositePrimaryKeys": {}, 969 + "uniqueConstraints": { 970 + "reactions_author_subject_type_uniq": { 971 + "name": "reactions_author_subject_type_uniq", 972 + "nullsNotDistinct": false, 973 + "columns": ["author_did", "subject_uri", "type"] 974 + } 975 + }, 976 + "policies": { 977 + "tenant_isolation": { 978 + "name": "tenant_isolation", 979 + "as": "PERMISSIVE", 980 + "for": "ALL", 981 + "to": ["barazo_app"], 982 + "using": "community_did = current_setting('app.current_community_did', true)", 983 + "withCheck": "community_did = current_setting('app.current_community_did', true)" 984 + } 985 + }, 986 + "checkConstraints": {}, 987 + "isRLSEnabled": true 988 + }, 989 + "public.votes": { 990 + "name": "votes", 991 + "schema": "", 992 + "columns": { 993 + "uri": { 994 + "name": "uri", 995 + "type": "text", 996 + "primaryKey": true, 997 + "notNull": true 998 + }, 999 + "rkey": { 1000 + "name": "rkey", 1001 + "type": "text", 1002 + "primaryKey": false, 1003 + "notNull": true 1004 + }, 1005 + "author_did": { 1006 + "name": "author_did", 1007 + "type": "text", 1008 + "primaryKey": false, 1009 + "notNull": true 1010 + }, 1011 + "subject_uri": { 1012 + "name": "subject_uri", 1013 + "type": "text", 1014 + "primaryKey": false, 1015 + "notNull": true 1016 + }, 1017 + "subject_cid": { 1018 + "name": "subject_cid", 1019 + "type": "text", 1020 + "primaryKey": false, 1021 + "notNull": true 1022 + }, 1023 + "direction": { 1024 + "name": "direction", 1025 + "type": "text", 1026 + "primaryKey": false, 1027 + "notNull": true 1028 + }, 1029 + "community_did": { 1030 + "name": "community_did", 1031 + "type": "text", 1032 + "primaryKey": false, 1033 + "notNull": true 1034 + }, 1035 + "cid": { 1036 + "name": "cid", 1037 + "type": "text", 1038 + "primaryKey": false, 1039 + "notNull": true 1040 + }, 1041 + "created_at": { 1042 + "name": "created_at", 1043 + "type": "timestamp with time zone", 1044 + "primaryKey": false, 1045 + "notNull": true 1046 + }, 1047 + "indexed_at": { 1048 + "name": "indexed_at", 1049 + "type": "timestamp with time zone", 1050 + "primaryKey": false, 1051 + "notNull": true, 1052 + "default": "now()" 1053 + } 1054 + }, 1055 + "indexes": { 1056 + "votes_author_did_idx": { 1057 + "name": "votes_author_did_idx", 1058 + "columns": [ 1059 + { 1060 + "expression": "author_did", 1061 + "isExpression": false, 1062 + "asc": true, 1063 + "nulls": "last" 1064 + } 1065 + ], 1066 + "isUnique": false, 1067 + "concurrently": false, 1068 + "method": "btree", 1069 + "with": {} 1070 + }, 1071 + "votes_subject_uri_idx": { 1072 + "name": "votes_subject_uri_idx", 1073 + "columns": [ 1074 + { 1075 + "expression": "subject_uri", 1076 + "isExpression": false, 1077 + "asc": true, 1078 + "nulls": "last" 1079 + } 1080 + ], 1081 + "isUnique": false, 1082 + "concurrently": false, 1083 + "method": "btree", 1084 + "with": {} 1085 + }, 1086 + "votes_community_did_idx": { 1087 + "name": "votes_community_did_idx", 1088 + "columns": [ 1089 + { 1090 + "expression": "community_did", 1091 + "isExpression": false, 1092 + "asc": true, 1093 + "nulls": "last" 1094 + } 1095 + ], 1096 + "isUnique": false, 1097 + "concurrently": false, 1098 + "method": "btree", 1099 + "with": {} 1100 + } 1101 + }, 1102 + "foreignKeys": {}, 1103 + "compositePrimaryKeys": {}, 1104 + "uniqueConstraints": { 1105 + "votes_author_subject_uniq": { 1106 + "name": "votes_author_subject_uniq", 1107 + "nullsNotDistinct": false, 1108 + "columns": ["author_did", "subject_uri"] 1109 + } 1110 + }, 1111 + "policies": {}, 1112 + "checkConstraints": {}, 1113 + "isRLSEnabled": false 1114 + }, 1115 + "public.tracked_repos": { 1116 + "name": "tracked_repos", 1117 + "schema": "", 1118 + "columns": { 1119 + "did": { 1120 + "name": "did", 1121 + "type": "text", 1122 + "primaryKey": true, 1123 + "notNull": true 1124 + }, 1125 + "tracked_at": { 1126 + "name": "tracked_at", 1127 + "type": "timestamp with time zone", 1128 + "primaryKey": false, 1129 + "notNull": true, 1130 + "default": "now()" 1131 + } 1132 + }, 1133 + "indexes": {}, 1134 + "foreignKeys": {}, 1135 + "compositePrimaryKeys": {}, 1136 + "uniqueConstraints": {}, 1137 + "policies": {}, 1138 + "checkConstraints": {}, 1139 + "isRLSEnabled": false 1140 + }, 1141 + "public.community_settings": { 1142 + "name": "community_settings", 1143 + "schema": "", 1144 + "columns": { 1145 + "community_did": { 1146 + "name": "community_did", 1147 + "type": "text", 1148 + "primaryKey": true, 1149 + "notNull": true 1150 + }, 1151 + "domains": { 1152 + "name": "domains", 1153 + "type": "jsonb", 1154 + "primaryKey": false, 1155 + "notNull": true, 1156 + "default": "'[]'::jsonb" 1157 + }, 1158 + "initialized": { 1159 + "name": "initialized", 1160 + "type": "boolean", 1161 + "primaryKey": false, 1162 + "notNull": true, 1163 + "default": false 1164 + }, 1165 + "admin_did": { 1166 + "name": "admin_did", 1167 + "type": "text", 1168 + "primaryKey": false, 1169 + "notNull": false 1170 + }, 1171 + "community_name": { 1172 + "name": "community_name", 1173 + "type": "text", 1174 + "primaryKey": false, 1175 + "notNull": true, 1176 + "default": "'Barazo Community'" 1177 + }, 1178 + "maturity_rating": { 1179 + "name": "maturity_rating", 1180 + "type": "text", 1181 + "primaryKey": false, 1182 + "notNull": true, 1183 + "default": "'safe'" 1184 + }, 1185 + "reaction_set": { 1186 + "name": "reaction_set", 1187 + "type": "jsonb", 1188 + "primaryKey": false, 1189 + "notNull": true, 1190 + "default": "'[\"like\"]'::jsonb" 1191 + }, 1192 + "moderation_thresholds": { 1193 + "name": "moderation_thresholds", 1194 + "type": "jsonb", 1195 + "primaryKey": false, 1196 + "notNull": true, 1197 + "default": "'{\"autoBlockReportCount\":5,\"warnThreshold\":3,\"firstPostQueueCount\":3,\"newAccountDays\":7,\"newAccountWriteRatePerMin\":3,\"establishedWriteRatePerMin\":10,\"linkHoldEnabled\":true,\"topicCreationDelayEnabled\":true,\"burstPostCount\":5,\"burstWindowMinutes\":10,\"trustedPostThreshold\":10}'::jsonb" 1198 + }, 1199 + "word_filter": { 1200 + "name": "word_filter", 1201 + "type": "jsonb", 1202 + "primaryKey": false, 1203 + "notNull": true, 1204 + "default": "'[]'::jsonb" 1205 + }, 1206 + "jurisdiction_country": { 1207 + "name": "jurisdiction_country", 1208 + "type": "text", 1209 + "primaryKey": false, 1210 + "notNull": false 1211 + }, 1212 + "age_threshold": { 1213 + "name": "age_threshold", 1214 + "type": "integer", 1215 + "primaryKey": false, 1216 + "notNull": true, 1217 + "default": 16 1218 + }, 1219 + "max_reply_depth": { 1220 + "name": "max_reply_depth", 1221 + "type": "integer", 1222 + "primaryKey": false, 1223 + "notNull": true, 1224 + "default": 9999 1225 + }, 1226 + "require_login_for_mature": { 1227 + "name": "require_login_for_mature", 1228 + "type": "boolean", 1229 + "primaryKey": false, 1230 + "notNull": true, 1231 + "default": true 1232 + }, 1233 + "community_description": { 1234 + "name": "community_description", 1235 + "type": "text", 1236 + "primaryKey": false, 1237 + "notNull": false 1238 + }, 1239 + "handle": { 1240 + "name": "handle", 1241 + "type": "text", 1242 + "primaryKey": false, 1243 + "notNull": false 1244 + }, 1245 + "service_endpoint": { 1246 + "name": "service_endpoint", 1247 + "type": "text", 1248 + "primaryKey": false, 1249 + "notNull": false 1250 + }, 1251 + "signing_key": { 1252 + "name": "signing_key", 1253 + "type": "text", 1254 + "primaryKey": false, 1255 + "notNull": false 1256 + }, 1257 + "rotation_key": { 1258 + "name": "rotation_key", 1259 + "type": "text", 1260 + "primaryKey": false, 1261 + "notNull": false 1262 + }, 1263 + "community_logo_url": { 1264 + "name": "community_logo_url", 1265 + "type": "text", 1266 + "primaryKey": false, 1267 + "notNull": false 1268 + }, 1269 + "favicon_url": { 1270 + "name": "favicon_url", 1271 + "type": "text", 1272 + "primaryKey": false, 1273 + "notNull": false 1274 + }, 1275 + "header_logo_url": { 1276 + "name": "header_logo_url", 1277 + "type": "text", 1278 + "primaryKey": false, 1279 + "notNull": false 1280 + }, 1281 + "show_community_name": { 1282 + "name": "show_community_name", 1283 + "type": "boolean", 1284 + "primaryKey": false, 1285 + "notNull": true, 1286 + "default": true 1287 + }, 1288 + "primary_color": { 1289 + "name": "primary_color", 1290 + "type": "text", 1291 + "primaryKey": false, 1292 + "notNull": false 1293 + }, 1294 + "accent_color": { 1295 + "name": "accent_color", 1296 + "type": "text", 1297 + "primaryKey": false, 1298 + "notNull": false 1299 + }, 1300 + "created_at": { 1301 + "name": "created_at", 1302 + "type": "timestamp with time zone", 1303 + "primaryKey": false, 1304 + "notNull": true, 1305 + "default": "now()" 1306 + }, 1307 + "updated_at": { 1308 + "name": "updated_at", 1309 + "type": "timestamp with time zone", 1310 + "primaryKey": false, 1311 + "notNull": true, 1312 + "default": "now()" 1313 + } 1314 + }, 1315 + "indexes": {}, 1316 + "foreignKeys": {}, 1317 + "compositePrimaryKeys": {}, 1318 + "uniqueConstraints": {}, 1319 + "policies": { 1320 + "tenant_isolation": { 1321 + "name": "tenant_isolation", 1322 + "as": "PERMISSIVE", 1323 + "for": "ALL", 1324 + "to": ["barazo_app"], 1325 + "using": "community_did = current_setting('app.current_community_did', true)", 1326 + "withCheck": "community_did = current_setting('app.current_community_did', true)" 1327 + } 1328 + }, 1329 + "checkConstraints": {}, 1330 + "isRLSEnabled": true 1331 + }, 1332 + "public.categories": { 1333 + "name": "categories", 1334 + "schema": "", 1335 + "columns": { 1336 + "id": { 1337 + "name": "id", 1338 + "type": "text", 1339 + "primaryKey": true, 1340 + "notNull": true 1341 + }, 1342 + "slug": { 1343 + "name": "slug", 1344 + "type": "text", 1345 + "primaryKey": false, 1346 + "notNull": true 1347 + }, 1348 + "name": { 1349 + "name": "name", 1350 + "type": "text", 1351 + "primaryKey": false, 1352 + "notNull": true 1353 + }, 1354 + "description": { 1355 + "name": "description", 1356 + "type": "text", 1357 + "primaryKey": false, 1358 + "notNull": false 1359 + }, 1360 + "parent_id": { 1361 + "name": "parent_id", 1362 + "type": "text", 1363 + "primaryKey": false, 1364 + "notNull": false 1365 + }, 1366 + "sort_order": { 1367 + "name": "sort_order", 1368 + "type": "integer", 1369 + "primaryKey": false, 1370 + "notNull": true, 1371 + "default": 0 1372 + }, 1373 + "community_did": { 1374 + "name": "community_did", 1375 + "type": "text", 1376 + "primaryKey": false, 1377 + "notNull": true 1378 + }, 1379 + "maturity_rating": { 1380 + "name": "maturity_rating", 1381 + "type": "text", 1382 + "primaryKey": false, 1383 + "notNull": true, 1384 + "default": "'safe'" 1385 + }, 1386 + "created_at": { 1387 + "name": "created_at", 1388 + "type": "timestamp with time zone", 1389 + "primaryKey": false, 1390 + "notNull": true, 1391 + "default": "now()" 1392 + }, 1393 + "updated_at": { 1394 + "name": "updated_at", 1395 + "type": "timestamp with time zone", 1396 + "primaryKey": false, 1397 + "notNull": true, 1398 + "default": "now()" 1399 + } 1400 + }, 1401 + "indexes": { 1402 + "categories_slug_community_did_idx": { 1403 + "name": "categories_slug_community_did_idx", 1404 + "columns": [ 1405 + { 1406 + "expression": "slug", 1407 + "isExpression": false, 1408 + "asc": true, 1409 + "nulls": "last" 1410 + }, 1411 + { 1412 + "expression": "community_did", 1413 + "isExpression": false, 1414 + "asc": true, 1415 + "nulls": "last" 1416 + } 1417 + ], 1418 + "isUnique": true, 1419 + "concurrently": false, 1420 + "method": "btree", 1421 + "with": {} 1422 + }, 1423 + "categories_parent_id_idx": { 1424 + "name": "categories_parent_id_idx", 1425 + "columns": [ 1426 + { 1427 + "expression": "parent_id", 1428 + "isExpression": false, 1429 + "asc": true, 1430 + "nulls": "last" 1431 + } 1432 + ], 1433 + "isUnique": false, 1434 + "concurrently": false, 1435 + "method": "btree", 1436 + "with": {} 1437 + }, 1438 + "categories_community_did_idx": { 1439 + "name": "categories_community_did_idx", 1440 + "columns": [ 1441 + { 1442 + "expression": "community_did", 1443 + "isExpression": false, 1444 + "asc": true, 1445 + "nulls": "last" 1446 + } 1447 + ], 1448 + "isUnique": false, 1449 + "concurrently": false, 1450 + "method": "btree", 1451 + "with": {} 1452 + }, 1453 + "categories_maturity_rating_idx": { 1454 + "name": "categories_maturity_rating_idx", 1455 + "columns": [ 1456 + { 1457 + "expression": "maturity_rating", 1458 + "isExpression": false, 1459 + "asc": true, 1460 + "nulls": "last" 1461 + } 1462 + ], 1463 + "isUnique": false, 1464 + "concurrently": false, 1465 + "method": "btree", 1466 + "with": {} 1467 + } 1468 + }, 1469 + "foreignKeys": { 1470 + "categories_parent_id_fk": { 1471 + "name": "categories_parent_id_fk", 1472 + "tableFrom": "categories", 1473 + "tableTo": "categories", 1474 + "columnsFrom": ["parent_id"], 1475 + "columnsTo": ["id"], 1476 + "onDelete": "set null", 1477 + "onUpdate": "no action" 1478 + } 1479 + }, 1480 + "compositePrimaryKeys": {}, 1481 + "uniqueConstraints": {}, 1482 + "policies": { 1483 + "tenant_isolation": { 1484 + "name": "tenant_isolation", 1485 + "as": "PERMISSIVE", 1486 + "for": "ALL", 1487 + "to": ["barazo_app"], 1488 + "using": "community_did = current_setting('app.current_community_did', true)", 1489 + "withCheck": "community_did = current_setting('app.current_community_did', true)" 1490 + } 1491 + }, 1492 + "checkConstraints": {}, 1493 + "isRLSEnabled": true 1494 + }, 1495 + "public.moderation_actions": { 1496 + "name": "moderation_actions", 1497 + "schema": "", 1498 + "columns": { 1499 + "id": { 1500 + "name": "id", 1501 + "type": "serial", 1502 + "primaryKey": true, 1503 + "notNull": true 1504 + }, 1505 + "action": { 1506 + "name": "action", 1507 + "type": "text", 1508 + "primaryKey": false, 1509 + "notNull": true 1510 + }, 1511 + "target_uri": { 1512 + "name": "target_uri", 1513 + "type": "text", 1514 + "primaryKey": false, 1515 + "notNull": false 1516 + }, 1517 + "target_did": { 1518 + "name": "target_did", 1519 + "type": "text", 1520 + "primaryKey": false, 1521 + "notNull": false 1522 + }, 1523 + "moderator_did": { 1524 + "name": "moderator_did", 1525 + "type": "text", 1526 + "primaryKey": false, 1527 + "notNull": true 1528 + }, 1529 + "community_did": { 1530 + "name": "community_did", 1531 + "type": "text", 1532 + "primaryKey": false, 1533 + "notNull": true 1534 + }, 1535 + "reason": { 1536 + "name": "reason", 1537 + "type": "text", 1538 + "primaryKey": false, 1539 + "notNull": false 1540 + }, 1541 + "created_at": { 1542 + "name": "created_at", 1543 + "type": "timestamp with time zone", 1544 + "primaryKey": false, 1545 + "notNull": true, 1546 + "default": "now()" 1547 + } 1548 + }, 1549 + "indexes": { 1550 + "mod_actions_moderator_did_idx": { 1551 + "name": "mod_actions_moderator_did_idx", 1552 + "columns": [ 1553 + { 1554 + "expression": "moderator_did", 1555 + "isExpression": false, 1556 + "asc": true, 1557 + "nulls": "last" 1558 + } 1559 + ], 1560 + "isUnique": false, 1561 + "concurrently": false, 1562 + "method": "btree", 1563 + "with": {} 1564 + }, 1565 + "mod_actions_community_did_idx": { 1566 + "name": "mod_actions_community_did_idx", 1567 + "columns": [ 1568 + { 1569 + "expression": "community_did", 1570 + "isExpression": false, 1571 + "asc": true, 1572 + "nulls": "last" 1573 + } 1574 + ], 1575 + "isUnique": false, 1576 + "concurrently": false, 1577 + "method": "btree", 1578 + "with": {} 1579 + }, 1580 + "mod_actions_created_at_idx": { 1581 + "name": "mod_actions_created_at_idx", 1582 + "columns": [ 1583 + { 1584 + "expression": "created_at", 1585 + "isExpression": false, 1586 + "asc": true, 1587 + "nulls": "last" 1588 + } 1589 + ], 1590 + "isUnique": false, 1591 + "concurrently": false, 1592 + "method": "btree", 1593 + "with": {} 1594 + }, 1595 + "mod_actions_target_uri_idx": { 1596 + "name": "mod_actions_target_uri_idx", 1597 + "columns": [ 1598 + { 1599 + "expression": "target_uri", 1600 + "isExpression": false, 1601 + "asc": true, 1602 + "nulls": "last" 1603 + } 1604 + ], 1605 + "isUnique": false, 1606 + "concurrently": false, 1607 + "method": "btree", 1608 + "with": {} 1609 + }, 1610 + "mod_actions_target_did_idx": { 1611 + "name": "mod_actions_target_did_idx", 1612 + "columns": [ 1613 + { 1614 + "expression": "target_did", 1615 + "isExpression": false, 1616 + "asc": true, 1617 + "nulls": "last" 1618 + } 1619 + ], 1620 + "isUnique": false, 1621 + "concurrently": false, 1622 + "method": "btree", 1623 + "with": {} 1624 + } 1625 + }, 1626 + "foreignKeys": {}, 1627 + "compositePrimaryKeys": {}, 1628 + "uniqueConstraints": {}, 1629 + "policies": { 1630 + "tenant_isolation": { 1631 + "name": "tenant_isolation", 1632 + "as": "PERMISSIVE", 1633 + "for": "ALL", 1634 + "to": ["barazo_app"], 1635 + "using": "community_did = current_setting('app.current_community_did', true)", 1636 + "withCheck": "community_did = current_setting('app.current_community_did', true)" 1637 + } 1638 + }, 1639 + "checkConstraints": {}, 1640 + "isRLSEnabled": true 1641 + }, 1642 + "public.reports": { 1643 + "name": "reports", 1644 + "schema": "", 1645 + "columns": { 1646 + "id": { 1647 + "name": "id", 1648 + "type": "serial", 1649 + "primaryKey": true, 1650 + "notNull": true 1651 + }, 1652 + "reporter_did": { 1653 + "name": "reporter_did", 1654 + "type": "text", 1655 + "primaryKey": false, 1656 + "notNull": true 1657 + }, 1658 + "target_uri": { 1659 + "name": "target_uri", 1660 + "type": "text", 1661 + "primaryKey": false, 1662 + "notNull": true 1663 + }, 1664 + "target_did": { 1665 + "name": "target_did", 1666 + "type": "text", 1667 + "primaryKey": false, 1668 + "notNull": true 1669 + }, 1670 + "reason_type": { 1671 + "name": "reason_type", 1672 + "type": "text", 1673 + "primaryKey": false, 1674 + "notNull": true 1675 + }, 1676 + "description": { 1677 + "name": "description", 1678 + "type": "text", 1679 + "primaryKey": false, 1680 + "notNull": false 1681 + }, 1682 + "community_did": { 1683 + "name": "community_did", 1684 + "type": "text", 1685 + "primaryKey": false, 1686 + "notNull": true 1687 + }, 1688 + "status": { 1689 + "name": "status", 1690 + "type": "text", 1691 + "primaryKey": false, 1692 + "notNull": true, 1693 + "default": "'pending'" 1694 + }, 1695 + "resolution_type": { 1696 + "name": "resolution_type", 1697 + "type": "text", 1698 + "primaryKey": false, 1699 + "notNull": false 1700 + }, 1701 + "resolved_by": { 1702 + "name": "resolved_by", 1703 + "type": "text", 1704 + "primaryKey": false, 1705 + "notNull": false 1706 + }, 1707 + "resolved_at": { 1708 + "name": "resolved_at", 1709 + "type": "timestamp with time zone", 1710 + "primaryKey": false, 1711 + "notNull": false 1712 + }, 1713 + "appeal_reason": { 1714 + "name": "appeal_reason", 1715 + "type": "text", 1716 + "primaryKey": false, 1717 + "notNull": false 1718 + }, 1719 + "appealed_at": { 1720 + "name": "appealed_at", 1721 + "type": "timestamp with time zone", 1722 + "primaryKey": false, 1723 + "notNull": false 1724 + }, 1725 + "appeal_status": { 1726 + "name": "appeal_status", 1727 + "type": "text", 1728 + "primaryKey": false, 1729 + "notNull": true, 1730 + "default": "'none'" 1731 + }, 1732 + "created_at": { 1733 + "name": "created_at", 1734 + "type": "timestamp with time zone", 1735 + "primaryKey": false, 1736 + "notNull": true, 1737 + "default": "now()" 1738 + } 1739 + }, 1740 + "indexes": { 1741 + "reports_reporter_did_idx": { 1742 + "name": "reports_reporter_did_idx", 1743 + "columns": [ 1744 + { 1745 + "expression": "reporter_did", 1746 + "isExpression": false, 1747 + "asc": true, 1748 + "nulls": "last" 1749 + } 1750 + ], 1751 + "isUnique": false, 1752 + "concurrently": false, 1753 + "method": "btree", 1754 + "with": {} 1755 + }, 1756 + "reports_target_uri_idx": { 1757 + "name": "reports_target_uri_idx", 1758 + "columns": [ 1759 + { 1760 + "expression": "target_uri", 1761 + "isExpression": false, 1762 + "asc": true, 1763 + "nulls": "last" 1764 + } 1765 + ], 1766 + "isUnique": false, 1767 + "concurrently": false, 1768 + "method": "btree", 1769 + "with": {} 1770 + }, 1771 + "reports_target_did_idx": { 1772 + "name": "reports_target_did_idx", 1773 + "columns": [ 1774 + { 1775 + "expression": "target_did", 1776 + "isExpression": false, 1777 + "asc": true, 1778 + "nulls": "last" 1779 + } 1780 + ], 1781 + "isUnique": false, 1782 + "concurrently": false, 1783 + "method": "btree", 1784 + "with": {} 1785 + }, 1786 + "reports_community_did_idx": { 1787 + "name": "reports_community_did_idx", 1788 + "columns": [ 1789 + { 1790 + "expression": "community_did", 1791 + "isExpression": false, 1792 + "asc": true, 1793 + "nulls": "last" 1794 + } 1795 + ], 1796 + "isUnique": false, 1797 + "concurrently": false, 1798 + "method": "btree", 1799 + "with": {} 1800 + }, 1801 + "reports_status_idx": { 1802 + "name": "reports_status_idx", 1803 + "columns": [ 1804 + { 1805 + "expression": "status", 1806 + "isExpression": false, 1807 + "asc": true, 1808 + "nulls": "last" 1809 + } 1810 + ], 1811 + "isUnique": false, 1812 + "concurrently": false, 1813 + "method": "btree", 1814 + "with": {} 1815 + }, 1816 + "reports_created_at_idx": { 1817 + "name": "reports_created_at_idx", 1818 + "columns": [ 1819 + { 1820 + "expression": "created_at", 1821 + "isExpression": false, 1822 + "asc": true, 1823 + "nulls": "last" 1824 + } 1825 + ], 1826 + "isUnique": false, 1827 + "concurrently": false, 1828 + "method": "btree", 1829 + "with": {} 1830 + }, 1831 + "reports_unique_reporter_target_idx": { 1832 + "name": "reports_unique_reporter_target_idx", 1833 + "columns": [ 1834 + { 1835 + "expression": "reporter_did", 1836 + "isExpression": false, 1837 + "asc": true, 1838 + "nulls": "last" 1839 + }, 1840 + { 1841 + "expression": "target_uri", 1842 + "isExpression": false, 1843 + "asc": true, 1844 + "nulls": "last" 1845 + }, 1846 + { 1847 + "expression": "community_did", 1848 + "isExpression": false, 1849 + "asc": true, 1850 + "nulls": "last" 1851 + } 1852 + ], 1853 + "isUnique": true, 1854 + "concurrently": false, 1855 + "method": "btree", 1856 + "with": {} 1857 + } 1858 + }, 1859 + "foreignKeys": {}, 1860 + "compositePrimaryKeys": {}, 1861 + "uniqueConstraints": {}, 1862 + "policies": { 1863 + "tenant_isolation": { 1864 + "name": "tenant_isolation", 1865 + "as": "PERMISSIVE", 1866 + "for": "ALL", 1867 + "to": ["barazo_app"], 1868 + "using": "community_did = current_setting('app.current_community_did', true)", 1869 + "withCheck": "community_did = current_setting('app.current_community_did', true)" 1870 + } 1871 + }, 1872 + "checkConstraints": {}, 1873 + "isRLSEnabled": true 1874 + }, 1875 + "public.notifications": { 1876 + "name": "notifications", 1877 + "schema": "", 1878 + "columns": { 1879 + "id": { 1880 + "name": "id", 1881 + "type": "serial", 1882 + "primaryKey": true, 1883 + "notNull": true 1884 + }, 1885 + "recipient_did": { 1886 + "name": "recipient_did", 1887 + "type": "text", 1888 + "primaryKey": false, 1889 + "notNull": true 1890 + }, 1891 + "type": { 1892 + "name": "type", 1893 + "type": "text", 1894 + "primaryKey": false, 1895 + "notNull": true 1896 + }, 1897 + "subject_uri": { 1898 + "name": "subject_uri", 1899 + "type": "text", 1900 + "primaryKey": false, 1901 + "notNull": true 1902 + }, 1903 + "actor_did": { 1904 + "name": "actor_did", 1905 + "type": "text", 1906 + "primaryKey": false, 1907 + "notNull": true 1908 + }, 1909 + "community_did": { 1910 + "name": "community_did", 1911 + "type": "text", 1912 + "primaryKey": false, 1913 + "notNull": true 1914 + }, 1915 + "read": { 1916 + "name": "read", 1917 + "type": "boolean", 1918 + "primaryKey": false, 1919 + "notNull": true, 1920 + "default": false 1921 + }, 1922 + "created_at": { 1923 + "name": "created_at", 1924 + "type": "timestamp with time zone", 1925 + "primaryKey": false, 1926 + "notNull": true, 1927 + "default": "now()" 1928 + } 1929 + }, 1930 + "indexes": { 1931 + "notifications_recipient_did_idx": { 1932 + "name": "notifications_recipient_did_idx", 1933 + "columns": [ 1934 + { 1935 + "expression": "recipient_did", 1936 + "isExpression": false, 1937 + "asc": true, 1938 + "nulls": "last" 1939 + } 1940 + ], 1941 + "isUnique": false, 1942 + "concurrently": false, 1943 + "method": "btree", 1944 + "with": {} 1945 + }, 1946 + "notifications_recipient_read_idx": { 1947 + "name": "notifications_recipient_read_idx", 1948 + "columns": [ 1949 + { 1950 + "expression": "recipient_did", 1951 + "isExpression": false, 1952 + "asc": true, 1953 + "nulls": "last" 1954 + }, 1955 + { 1956 + "expression": "read", 1957 + "isExpression": false, 1958 + "asc": true, 1959 + "nulls": "last" 1960 + } 1961 + ], 1962 + "isUnique": false, 1963 + "concurrently": false, 1964 + "method": "btree", 1965 + "with": {} 1966 + }, 1967 + "notifications_created_at_idx": { 1968 + "name": "notifications_created_at_idx", 1969 + "columns": [ 1970 + { 1971 + "expression": "created_at", 1972 + "isExpression": false, 1973 + "asc": true, 1974 + "nulls": "last" 1975 + } 1976 + ], 1977 + "isUnique": false, 1978 + "concurrently": false, 1979 + "method": "btree", 1980 + "with": {} 1981 + } 1982 + }, 1983 + "foreignKeys": {}, 1984 + "compositePrimaryKeys": {}, 1985 + "uniqueConstraints": {}, 1986 + "policies": { 1987 + "tenant_isolation": { 1988 + "name": "tenant_isolation", 1989 + "as": "PERMISSIVE", 1990 + "for": "ALL", 1991 + "to": ["barazo_app"], 1992 + "using": "community_did = current_setting('app.current_community_did', true)", 1993 + "withCheck": "community_did = current_setting('app.current_community_did', true)" 1994 + } 1995 + }, 1996 + "checkConstraints": {}, 1997 + "isRLSEnabled": true 1998 + }, 1999 + "public.user_community_preferences": { 2000 + "name": "user_community_preferences", 2001 + "schema": "", 2002 + "columns": { 2003 + "did": { 2004 + "name": "did", 2005 + "type": "text", 2006 + "primaryKey": false, 2007 + "notNull": true 2008 + }, 2009 + "community_did": { 2010 + "name": "community_did", 2011 + "type": "text", 2012 + "primaryKey": false, 2013 + "notNull": true 2014 + }, 2015 + "maturity_override": { 2016 + "name": "maturity_override", 2017 + "type": "text", 2018 + "primaryKey": false, 2019 + "notNull": false 2020 + }, 2021 + "muted_words": { 2022 + "name": "muted_words", 2023 + "type": "jsonb", 2024 + "primaryKey": false, 2025 + "notNull": false 2026 + }, 2027 + "blocked_dids": { 2028 + "name": "blocked_dids", 2029 + "type": "jsonb", 2030 + "primaryKey": false, 2031 + "notNull": false 2032 + }, 2033 + "muted_dids": { 2034 + "name": "muted_dids", 2035 + "type": "jsonb", 2036 + "primaryKey": false, 2037 + "notNull": false 2038 + }, 2039 + "notification_prefs": { 2040 + "name": "notification_prefs", 2041 + "type": "jsonb", 2042 + "primaryKey": false, 2043 + "notNull": false 2044 + }, 2045 + "updated_at": { 2046 + "name": "updated_at", 2047 + "type": "timestamp with time zone", 2048 + "primaryKey": false, 2049 + "notNull": true, 2050 + "default": "now()" 2051 + } 2052 + }, 2053 + "indexes": { 2054 + "user_community_prefs_did_idx": { 2055 + "name": "user_community_prefs_did_idx", 2056 + "columns": [ 2057 + { 2058 + "expression": "did", 2059 + "isExpression": false, 2060 + "asc": true, 2061 + "nulls": "last" 2062 + } 2063 + ], 2064 + "isUnique": false, 2065 + "concurrently": false, 2066 + "method": "btree", 2067 + "with": {} 2068 + }, 2069 + "user_community_prefs_community_idx": { 2070 + "name": "user_community_prefs_community_idx", 2071 + "columns": [ 2072 + { 2073 + "expression": "community_did", 2074 + "isExpression": false, 2075 + "asc": true, 2076 + "nulls": "last" 2077 + } 2078 + ], 2079 + "isUnique": false, 2080 + "concurrently": false, 2081 + "method": "btree", 2082 + "with": {} 2083 + } 2084 + }, 2085 + "foreignKeys": {}, 2086 + "compositePrimaryKeys": { 2087 + "user_community_preferences_did_community_did_pk": { 2088 + "name": "user_community_preferences_did_community_did_pk", 2089 + "columns": ["did", "community_did"] 2090 + } 2091 + }, 2092 + "uniqueConstraints": {}, 2093 + "policies": { 2094 + "tenant_isolation": { 2095 + "name": "tenant_isolation", 2096 + "as": "PERMISSIVE", 2097 + "for": "ALL", 2098 + "to": ["barazo_app"], 2099 + "using": "community_did = current_setting('app.current_community_did', true)", 2100 + "withCheck": "community_did = current_setting('app.current_community_did', true)" 2101 + } 2102 + }, 2103 + "checkConstraints": {}, 2104 + "isRLSEnabled": true 2105 + }, 2106 + "public.user_preferences": { 2107 + "name": "user_preferences", 2108 + "schema": "", 2109 + "columns": { 2110 + "did": { 2111 + "name": "did", 2112 + "type": "text", 2113 + "primaryKey": true, 2114 + "notNull": true 2115 + }, 2116 + "maturity_level": { 2117 + "name": "maturity_level", 2118 + "type": "text", 2119 + "primaryKey": false, 2120 + "notNull": true, 2121 + "default": "'sfw'" 2122 + }, 2123 + "declared_age": { 2124 + "name": "declared_age", 2125 + "type": "integer", 2126 + "primaryKey": false, 2127 + "notNull": false 2128 + }, 2129 + "muted_words": { 2130 + "name": "muted_words", 2131 + "type": "jsonb", 2132 + "primaryKey": false, 2133 + "notNull": true, 2134 + "default": "'[]'::jsonb" 2135 + }, 2136 + "blocked_dids": { 2137 + "name": "blocked_dids", 2138 + "type": "jsonb", 2139 + "primaryKey": false, 2140 + "notNull": true, 2141 + "default": "'[]'::jsonb" 2142 + }, 2143 + "muted_dids": { 2144 + "name": "muted_dids", 2145 + "type": "jsonb", 2146 + "primaryKey": false, 2147 + "notNull": true, 2148 + "default": "'[]'::jsonb" 2149 + }, 2150 + "cross_post_bluesky": { 2151 + "name": "cross_post_bluesky", 2152 + "type": "boolean", 2153 + "primaryKey": false, 2154 + "notNull": true, 2155 + "default": false 2156 + }, 2157 + "cross_post_frontpage": { 2158 + "name": "cross_post_frontpage", 2159 + "type": "boolean", 2160 + "primaryKey": false, 2161 + "notNull": true, 2162 + "default": false 2163 + }, 2164 + "cross_post_scopes_granted": { 2165 + "name": "cross_post_scopes_granted", 2166 + "type": "boolean", 2167 + "primaryKey": false, 2168 + "notNull": true, 2169 + "default": false 2170 + }, 2171 + "updated_at": { 2172 + "name": "updated_at", 2173 + "type": "timestamp with time zone", 2174 + "primaryKey": false, 2175 + "notNull": true, 2176 + "default": "now()" 2177 + } 2178 + }, 2179 + "indexes": {}, 2180 + "foreignKeys": {}, 2181 + "compositePrimaryKeys": {}, 2182 + "uniqueConstraints": {}, 2183 + "policies": {}, 2184 + "checkConstraints": {}, 2185 + "isRLSEnabled": false 2186 + }, 2187 + "public.cross_posts": { 2188 + "name": "cross_posts", 2189 + "schema": "", 2190 + "columns": { 2191 + "id": { 2192 + "name": "id", 2193 + "type": "text", 2194 + "primaryKey": true, 2195 + "notNull": true 2196 + }, 2197 + "topic_uri": { 2198 + "name": "topic_uri", 2199 + "type": "text", 2200 + "primaryKey": false, 2201 + "notNull": true 2202 + }, 2203 + "service": { 2204 + "name": "service", 2205 + "type": "text", 2206 + "primaryKey": false, 2207 + "notNull": true 2208 + }, 2209 + "cross_post_uri": { 2210 + "name": "cross_post_uri", 2211 + "type": "text", 2212 + "primaryKey": false, 2213 + "notNull": true 2214 + }, 2215 + "cross_post_cid": { 2216 + "name": "cross_post_cid", 2217 + "type": "text", 2218 + "primaryKey": false, 2219 + "notNull": true 2220 + }, 2221 + "author_did": { 2222 + "name": "author_did", 2223 + "type": "text", 2224 + "primaryKey": false, 2225 + "notNull": true 2226 + }, 2227 + "created_at": { 2228 + "name": "created_at", 2229 + "type": "timestamp with time zone", 2230 + "primaryKey": false, 2231 + "notNull": true, 2232 + "default": "now()" 2233 + } 2234 + }, 2235 + "indexes": { 2236 + "cross_posts_topic_uri_idx": { 2237 + "name": "cross_posts_topic_uri_idx", 2238 + "columns": [ 2239 + { 2240 + "expression": "topic_uri", 2241 + "isExpression": false, 2242 + "asc": true, 2243 + "nulls": "last" 2244 + } 2245 + ], 2246 + "isUnique": false, 2247 + "concurrently": false, 2248 + "method": "btree", 2249 + "with": {} 2250 + }, 2251 + "cross_posts_author_did_idx": { 2252 + "name": "cross_posts_author_did_idx", 2253 + "columns": [ 2254 + { 2255 + "expression": "author_did", 2256 + "isExpression": false, 2257 + "asc": true, 2258 + "nulls": "last" 2259 + } 2260 + ], 2261 + "isUnique": false, 2262 + "concurrently": false, 2263 + "method": "btree", 2264 + "with": {} 2265 + } 2266 + }, 2267 + "foreignKeys": {}, 2268 + "compositePrimaryKeys": {}, 2269 + "uniqueConstraints": {}, 2270 + "policies": {}, 2271 + "checkConstraints": {}, 2272 + "isRLSEnabled": false 2273 + }, 2274 + "public.community_onboarding_fields": { 2275 + "name": "community_onboarding_fields", 2276 + "schema": "", 2277 + "columns": { 2278 + "id": { 2279 + "name": "id", 2280 + "type": "text", 2281 + "primaryKey": true, 2282 + "notNull": true 2283 + }, 2284 + "community_did": { 2285 + "name": "community_did", 2286 + "type": "text", 2287 + "primaryKey": false, 2288 + "notNull": true 2289 + }, 2290 + "field_type": { 2291 + "name": "field_type", 2292 + "type": "text", 2293 + "primaryKey": false, 2294 + "notNull": true 2295 + }, 2296 + "label": { 2297 + "name": "label", 2298 + "type": "text", 2299 + "primaryKey": false, 2300 + "notNull": true 2301 + }, 2302 + "description": { 2303 + "name": "description", 2304 + "type": "text", 2305 + "primaryKey": false, 2306 + "notNull": false 2307 + }, 2308 + "is_mandatory": { 2309 + "name": "is_mandatory", 2310 + "type": "boolean", 2311 + "primaryKey": false, 2312 + "notNull": true, 2313 + "default": true 2314 + }, 2315 + "sort_order": { 2316 + "name": "sort_order", 2317 + "type": "integer", 2318 + "primaryKey": false, 2319 + "notNull": true, 2320 + "default": 0 2321 + }, 2322 + "source": { 2323 + "name": "source", 2324 + "type": "text", 2325 + "primaryKey": false, 2326 + "notNull": true, 2327 + "default": "'admin'" 2328 + }, 2329 + "config": { 2330 + "name": "config", 2331 + "type": "jsonb", 2332 + "primaryKey": false, 2333 + "notNull": false 2334 + }, 2335 + "created_at": { 2336 + "name": "created_at", 2337 + "type": "timestamp with time zone", 2338 + "primaryKey": false, 2339 + "notNull": true, 2340 + "default": "now()" 2341 + }, 2342 + "updated_at": { 2343 + "name": "updated_at", 2344 + "type": "timestamp with time zone", 2345 + "primaryKey": false, 2346 + "notNull": true, 2347 + "default": "now()" 2348 + } 2349 + }, 2350 + "indexes": { 2351 + "onboarding_fields_community_idx": { 2352 + "name": "onboarding_fields_community_idx", 2353 + "columns": [ 2354 + { 2355 + "expression": "community_did", 2356 + "isExpression": false, 2357 + "asc": true, 2358 + "nulls": "last" 2359 + } 2360 + ], 2361 + "isUnique": false, 2362 + "concurrently": false, 2363 + "method": "btree", 2364 + "with": {} 2365 + } 2366 + }, 2367 + "foreignKeys": {}, 2368 + "compositePrimaryKeys": {}, 2369 + "uniqueConstraints": {}, 2370 + "policies": { 2371 + "tenant_isolation": { 2372 + "name": "tenant_isolation", 2373 + "as": "PERMISSIVE", 2374 + "for": "ALL", 2375 + "to": ["barazo_app"], 2376 + "using": "community_did = current_setting('app.current_community_did', true)", 2377 + "withCheck": "community_did = current_setting('app.current_community_did', true)" 2378 + } 2379 + }, 2380 + "checkConstraints": {}, 2381 + "isRLSEnabled": true 2382 + }, 2383 + "public.user_onboarding_responses": { 2384 + "name": "user_onboarding_responses", 2385 + "schema": "", 2386 + "columns": { 2387 + "did": { 2388 + "name": "did", 2389 + "type": "text", 2390 + "primaryKey": false, 2391 + "notNull": true 2392 + }, 2393 + "community_did": { 2394 + "name": "community_did", 2395 + "type": "text", 2396 + "primaryKey": false, 2397 + "notNull": true 2398 + }, 2399 + "field_id": { 2400 + "name": "field_id", 2401 + "type": "text", 2402 + "primaryKey": false, 2403 + "notNull": true 2404 + }, 2405 + "response": { 2406 + "name": "response", 2407 + "type": "jsonb", 2408 + "primaryKey": false, 2409 + "notNull": true 2410 + }, 2411 + "completed_at": { 2412 + "name": "completed_at", 2413 + "type": "timestamp with time zone", 2414 + "primaryKey": false, 2415 + "notNull": true, 2416 + "default": "now()" 2417 + } 2418 + }, 2419 + "indexes": { 2420 + "onboarding_responses_did_community_idx": { 2421 + "name": "onboarding_responses_did_community_idx", 2422 + "columns": [ 2423 + { 2424 + "expression": "did", 2425 + "isExpression": false, 2426 + "asc": true, 2427 + "nulls": "last" 2428 + }, 2429 + { 2430 + "expression": "community_did", 2431 + "isExpression": false, 2432 + "asc": true, 2433 + "nulls": "last" 2434 + } 2435 + ], 2436 + "isUnique": false, 2437 + "concurrently": false, 2438 + "method": "btree", 2439 + "with": {} 2440 + } 2441 + }, 2442 + "foreignKeys": {}, 2443 + "compositePrimaryKeys": { 2444 + "user_onboarding_responses_did_community_did_field_id_pk": { 2445 + "name": "user_onboarding_responses_did_community_did_field_id_pk", 2446 + "columns": ["did", "community_did", "field_id"] 2447 + } 2448 + }, 2449 + "uniqueConstraints": {}, 2450 + "policies": { 2451 + "tenant_isolation": { 2452 + "name": "tenant_isolation", 2453 + "as": "PERMISSIVE", 2454 + "for": "ALL", 2455 + "to": ["barazo_app"], 2456 + "using": "community_did = current_setting('app.current_community_did', true)", 2457 + "withCheck": "community_did = current_setting('app.current_community_did', true)" 2458 + } 2459 + }, 2460 + "checkConstraints": {}, 2461 + "isRLSEnabled": true 2462 + }, 2463 + "public.moderation_queue": { 2464 + "name": "moderation_queue", 2465 + "schema": "", 2466 + "columns": { 2467 + "id": { 2468 + "name": "id", 2469 + "type": "serial", 2470 + "primaryKey": true, 2471 + "notNull": true 2472 + }, 2473 + "content_uri": { 2474 + "name": "content_uri", 2475 + "type": "text", 2476 + "primaryKey": false, 2477 + "notNull": true 2478 + }, 2479 + "content_type": { 2480 + "name": "content_type", 2481 + "type": "text", 2482 + "primaryKey": false, 2483 + "notNull": true 2484 + }, 2485 + "author_did": { 2486 + "name": "author_did", 2487 + "type": "text", 2488 + "primaryKey": false, 2489 + "notNull": true 2490 + }, 2491 + "community_did": { 2492 + "name": "community_did", 2493 + "type": "text", 2494 + "primaryKey": false, 2495 + "notNull": true 2496 + }, 2497 + "queue_reason": { 2498 + "name": "queue_reason", 2499 + "type": "text", 2500 + "primaryKey": false, 2501 + "notNull": true 2502 + }, 2503 + "matched_words": { 2504 + "name": "matched_words", 2505 + "type": "jsonb", 2506 + "primaryKey": false, 2507 + "notNull": false 2508 + }, 2509 + "status": { 2510 + "name": "status", 2511 + "type": "text", 2512 + "primaryKey": false, 2513 + "notNull": true, 2514 + "default": "'pending'" 2515 + }, 2516 + "reviewed_by": { 2517 + "name": "reviewed_by", 2518 + "type": "text", 2519 + "primaryKey": false, 2520 + "notNull": false 2521 + }, 2522 + "created_at": { 2523 + "name": "created_at", 2524 + "type": "timestamp with time zone", 2525 + "primaryKey": false, 2526 + "notNull": true, 2527 + "default": "now()" 2528 + }, 2529 + "reviewed_at": { 2530 + "name": "reviewed_at", 2531 + "type": "timestamp with time zone", 2532 + "primaryKey": false, 2533 + "notNull": false 2534 + } 2535 + }, 2536 + "indexes": { 2537 + "mod_queue_author_did_idx": { 2538 + "name": "mod_queue_author_did_idx", 2539 + "columns": [ 2540 + { 2541 + "expression": "author_did", 2542 + "isExpression": false, 2543 + "asc": true, 2544 + "nulls": "last" 2545 + } 2546 + ], 2547 + "isUnique": false, 2548 + "concurrently": false, 2549 + "method": "btree", 2550 + "with": {} 2551 + }, 2552 + "mod_queue_community_did_idx": { 2553 + "name": "mod_queue_community_did_idx", 2554 + "columns": [ 2555 + { 2556 + "expression": "community_did", 2557 + "isExpression": false, 2558 + "asc": true, 2559 + "nulls": "last" 2560 + } 2561 + ], 2562 + "isUnique": false, 2563 + "concurrently": false, 2564 + "method": "btree", 2565 + "with": {} 2566 + }, 2567 + "mod_queue_status_idx": { 2568 + "name": "mod_queue_status_idx", 2569 + "columns": [ 2570 + { 2571 + "expression": "status", 2572 + "isExpression": false, 2573 + "asc": true, 2574 + "nulls": "last" 2575 + } 2576 + ], 2577 + "isUnique": false, 2578 + "concurrently": false, 2579 + "method": "btree", 2580 + "with": {} 2581 + }, 2582 + "mod_queue_created_at_idx": { 2583 + "name": "mod_queue_created_at_idx", 2584 + "columns": [ 2585 + { 2586 + "expression": "created_at", 2587 + "isExpression": false, 2588 + "asc": true, 2589 + "nulls": "last" 2590 + } 2591 + ], 2592 + "isUnique": false, 2593 + "concurrently": false, 2594 + "method": "btree", 2595 + "with": {} 2596 + }, 2597 + "mod_queue_content_uri_idx": { 2598 + "name": "mod_queue_content_uri_idx", 2599 + "columns": [ 2600 + { 2601 + "expression": "content_uri", 2602 + "isExpression": false, 2603 + "asc": true, 2604 + "nulls": "last" 2605 + } 2606 + ], 2607 + "isUnique": false, 2608 + "concurrently": false, 2609 + "method": "btree", 2610 + "with": {} 2611 + } 2612 + }, 2613 + "foreignKeys": {}, 2614 + "compositePrimaryKeys": {}, 2615 + "uniqueConstraints": {}, 2616 + "policies": { 2617 + "tenant_isolation": { 2618 + "name": "tenant_isolation", 2619 + "as": "PERMISSIVE", 2620 + "for": "ALL", 2621 + "to": ["barazo_app"], 2622 + "using": "community_did = current_setting('app.current_community_did', true)", 2623 + "withCheck": "community_did = current_setting('app.current_community_did', true)" 2624 + } 2625 + }, 2626 + "checkConstraints": {}, 2627 + "isRLSEnabled": true 2628 + }, 2629 + "public.account_trust": { 2630 + "name": "account_trust", 2631 + "schema": "", 2632 + "columns": { 2633 + "id": { 2634 + "name": "id", 2635 + "type": "serial", 2636 + "primaryKey": true, 2637 + "notNull": true 2638 + }, 2639 + "did": { 2640 + "name": "did", 2641 + "type": "text", 2642 + "primaryKey": false, 2643 + "notNull": true 2644 + }, 2645 + "community_did": { 2646 + "name": "community_did", 2647 + "type": "text", 2648 + "primaryKey": false, 2649 + "notNull": true 2650 + }, 2651 + "approved_post_count": { 2652 + "name": "approved_post_count", 2653 + "type": "integer", 2654 + "primaryKey": false, 2655 + "notNull": true, 2656 + "default": 0 2657 + }, 2658 + "is_trusted": { 2659 + "name": "is_trusted", 2660 + "type": "boolean", 2661 + "primaryKey": false, 2662 + "notNull": true, 2663 + "default": false 2664 + }, 2665 + "trusted_at": { 2666 + "name": "trusted_at", 2667 + "type": "timestamp with time zone", 2668 + "primaryKey": false, 2669 + "notNull": false 2670 + } 2671 + }, 2672 + "indexes": { 2673 + "account_trust_did_community_idx": { 2674 + "name": "account_trust_did_community_idx", 2675 + "columns": [ 2676 + { 2677 + "expression": "did", 2678 + "isExpression": false, 2679 + "asc": true, 2680 + "nulls": "last" 2681 + }, 2682 + { 2683 + "expression": "community_did", 2684 + "isExpression": false, 2685 + "asc": true, 2686 + "nulls": "last" 2687 + } 2688 + ], 2689 + "isUnique": true, 2690 + "concurrently": false, 2691 + "method": "btree", 2692 + "with": {} 2693 + }, 2694 + "account_trust_did_idx": { 2695 + "name": "account_trust_did_idx", 2696 + "columns": [ 2697 + { 2698 + "expression": "did", 2699 + "isExpression": false, 2700 + "asc": true, 2701 + "nulls": "last" 2702 + } 2703 + ], 2704 + "isUnique": false, 2705 + "concurrently": false, 2706 + "method": "btree", 2707 + "with": {} 2708 + } 2709 + }, 2710 + "foreignKeys": {}, 2711 + "compositePrimaryKeys": {}, 2712 + "uniqueConstraints": {}, 2713 + "policies": { 2714 + "tenant_isolation": { 2715 + "name": "tenant_isolation", 2716 + "as": "PERMISSIVE", 2717 + "for": "ALL", 2718 + "to": ["barazo_app"], 2719 + "using": "community_did = current_setting('app.current_community_did', true)", 2720 + "withCheck": "community_did = current_setting('app.current_community_did', true)" 2721 + } 2722 + }, 2723 + "checkConstraints": {}, 2724 + "isRLSEnabled": true 2725 + }, 2726 + "public.community_filters": { 2727 + "name": "community_filters", 2728 + "schema": "", 2729 + "columns": { 2730 + "community_did": { 2731 + "name": "community_did", 2732 + "type": "text", 2733 + "primaryKey": true, 2734 + "notNull": true 2735 + }, 2736 + "status": { 2737 + "name": "status", 2738 + "type": "text", 2739 + "primaryKey": false, 2740 + "notNull": true, 2741 + "default": "'active'" 2742 + }, 2743 + "admin_did": { 2744 + "name": "admin_did", 2745 + "type": "text", 2746 + "primaryKey": false, 2747 + "notNull": false 2748 + }, 2749 + "reason": { 2750 + "name": "reason", 2751 + "type": "text", 2752 + "primaryKey": false, 2753 + "notNull": false 2754 + }, 2755 + "report_count": { 2756 + "name": "report_count", 2757 + "type": "integer", 2758 + "primaryKey": false, 2759 + "notNull": true, 2760 + "default": 0 2761 + }, 2762 + "last_reviewed_at": { 2763 + "name": "last_reviewed_at", 2764 + "type": "timestamp with time zone", 2765 + "primaryKey": false, 2766 + "notNull": false 2767 + }, 2768 + "filtered_by": { 2769 + "name": "filtered_by", 2770 + "type": "text", 2771 + "primaryKey": false, 2772 + "notNull": false 2773 + }, 2774 + "created_at": { 2775 + "name": "created_at", 2776 + "type": "timestamp with time zone", 2777 + "primaryKey": false, 2778 + "notNull": true, 2779 + "default": "now()" 2780 + }, 2781 + "updated_at": { 2782 + "name": "updated_at", 2783 + "type": "timestamp with time zone", 2784 + "primaryKey": false, 2785 + "notNull": true, 2786 + "default": "now()" 2787 + } 2788 + }, 2789 + "indexes": { 2790 + "community_filters_status_idx": { 2791 + "name": "community_filters_status_idx", 2792 + "columns": [ 2793 + { 2794 + "expression": "status", 2795 + "isExpression": false, 2796 + "asc": true, 2797 + "nulls": "last" 2798 + } 2799 + ], 2800 + "isUnique": false, 2801 + "concurrently": false, 2802 + "method": "btree", 2803 + "with": {} 2804 + }, 2805 + "community_filters_admin_did_idx": { 2806 + "name": "community_filters_admin_did_idx", 2807 + "columns": [ 2808 + { 2809 + "expression": "admin_did", 2810 + "isExpression": false, 2811 + "asc": true, 2812 + "nulls": "last" 2813 + } 2814 + ], 2815 + "isUnique": false, 2816 + "concurrently": false, 2817 + "method": "btree", 2818 + "with": {} 2819 + }, 2820 + "community_filters_updated_at_idx": { 2821 + "name": "community_filters_updated_at_idx", 2822 + "columns": [ 2823 + { 2824 + "expression": "updated_at", 2825 + "isExpression": false, 2826 + "asc": true, 2827 + "nulls": "last" 2828 + } 2829 + ], 2830 + "isUnique": false, 2831 + "concurrently": false, 2832 + "method": "btree", 2833 + "with": {} 2834 + } 2835 + }, 2836 + "foreignKeys": {}, 2837 + "compositePrimaryKeys": {}, 2838 + "uniqueConstraints": {}, 2839 + "policies": { 2840 + "tenant_isolation": { 2841 + "name": "tenant_isolation", 2842 + "as": "PERMISSIVE", 2843 + "for": "ALL", 2844 + "to": ["barazo_app"], 2845 + "using": "community_did = current_setting('app.current_community_did', true)", 2846 + "withCheck": "community_did = current_setting('app.current_community_did', true)" 2847 + } 2848 + }, 2849 + "checkConstraints": {}, 2850 + "isRLSEnabled": true 2851 + }, 2852 + "public.account_filters": { 2853 + "name": "account_filters", 2854 + "schema": "", 2855 + "columns": { 2856 + "id": { 2857 + "name": "id", 2858 + "type": "serial", 2859 + "primaryKey": true, 2860 + "notNull": true 2861 + }, 2862 + "did": { 2863 + "name": "did", 2864 + "type": "text", 2865 + "primaryKey": false, 2866 + "notNull": true 2867 + }, 2868 + "community_did": { 2869 + "name": "community_did", 2870 + "type": "text", 2871 + "primaryKey": false, 2872 + "notNull": true 2873 + }, 2874 + "status": { 2875 + "name": "status", 2876 + "type": "text", 2877 + "primaryKey": false, 2878 + "notNull": true, 2879 + "default": "'active'" 2880 + }, 2881 + "reason": { 2882 + "name": "reason", 2883 + "type": "text", 2884 + "primaryKey": false, 2885 + "notNull": false 2886 + }, 2887 + "report_count": { 2888 + "name": "report_count", 2889 + "type": "integer", 2890 + "primaryKey": false, 2891 + "notNull": true, 2892 + "default": 0 2893 + }, 2894 + "ban_count": { 2895 + "name": "ban_count", 2896 + "type": "integer", 2897 + "primaryKey": false, 2898 + "notNull": true, 2899 + "default": 0 2900 + }, 2901 + "last_reviewed_at": { 2902 + "name": "last_reviewed_at", 2903 + "type": "timestamp with time zone", 2904 + "primaryKey": false, 2905 + "notNull": false 2906 + }, 2907 + "filtered_by": { 2908 + "name": "filtered_by", 2909 + "type": "text", 2910 + "primaryKey": false, 2911 + "notNull": false 2912 + }, 2913 + "created_at": { 2914 + "name": "created_at", 2915 + "type": "timestamp with time zone", 2916 + "primaryKey": false, 2917 + "notNull": true, 2918 + "default": "now()" 2919 + }, 2920 + "updated_at": { 2921 + "name": "updated_at", 2922 + "type": "timestamp with time zone", 2923 + "primaryKey": false, 2924 + "notNull": true, 2925 + "default": "now()" 2926 + } 2927 + }, 2928 + "indexes": { 2929 + "account_filters_did_community_idx": { 2930 + "name": "account_filters_did_community_idx", 2931 + "columns": [ 2932 + { 2933 + "expression": "did", 2934 + "isExpression": false, 2935 + "asc": true, 2936 + "nulls": "last" 2937 + }, 2938 + { 2939 + "expression": "community_did", 2940 + "isExpression": false, 2941 + "asc": true, 2942 + "nulls": "last" 2943 + } 2944 + ], 2945 + "isUnique": true, 2946 + "concurrently": false, 2947 + "method": "btree", 2948 + "with": {} 2949 + }, 2950 + "account_filters_did_idx": { 2951 + "name": "account_filters_did_idx", 2952 + "columns": [ 2953 + { 2954 + "expression": "did", 2955 + "isExpression": false, 2956 + "asc": true, 2957 + "nulls": "last" 2958 + } 2959 + ], 2960 + "isUnique": false, 2961 + "concurrently": false, 2962 + "method": "btree", 2963 + "with": {} 2964 + }, 2965 + "account_filters_community_did_idx": { 2966 + "name": "account_filters_community_did_idx", 2967 + "columns": [ 2968 + { 2969 + "expression": "community_did", 2970 + "isExpression": false, 2971 + "asc": true, 2972 + "nulls": "last" 2973 + } 2974 + ], 2975 + "isUnique": false, 2976 + "concurrently": false, 2977 + "method": "btree", 2978 + "with": {} 2979 + }, 2980 + "account_filters_status_idx": { 2981 + "name": "account_filters_status_idx", 2982 + "columns": [ 2983 + { 2984 + "expression": "status", 2985 + "isExpression": false, 2986 + "asc": true, 2987 + "nulls": "last" 2988 + } 2989 + ], 2990 + "isUnique": false, 2991 + "concurrently": false, 2992 + "method": "btree", 2993 + "with": {} 2994 + }, 2995 + "account_filters_updated_at_idx": { 2996 + "name": "account_filters_updated_at_idx", 2997 + "columns": [ 2998 + { 2999 + "expression": "updated_at", 3000 + "isExpression": false, 3001 + "asc": true, 3002 + "nulls": "last" 3003 + } 3004 + ], 3005 + "isUnique": false, 3006 + "concurrently": false, 3007 + "method": "btree", 3008 + "with": {} 3009 + } 3010 + }, 3011 + "foreignKeys": {}, 3012 + "compositePrimaryKeys": {}, 3013 + "uniqueConstraints": {}, 3014 + "policies": { 3015 + "tenant_isolation": { 3016 + "name": "tenant_isolation", 3017 + "as": "PERMISSIVE", 3018 + "for": "ALL", 3019 + "to": ["barazo_app"], 3020 + "using": "community_did = current_setting('app.current_community_did', true)", 3021 + "withCheck": "community_did = current_setting('app.current_community_did', true)" 3022 + } 3023 + }, 3024 + "checkConstraints": {}, 3025 + "isRLSEnabled": true 3026 + }, 3027 + "public.ozone_labels": { 3028 + "name": "ozone_labels", 3029 + "schema": "", 3030 + "columns": { 3031 + "id": { 3032 + "name": "id", 3033 + "type": "serial", 3034 + "primaryKey": true, 3035 + "notNull": true 3036 + }, 3037 + "src": { 3038 + "name": "src", 3039 + "type": "text", 3040 + "primaryKey": false, 3041 + "notNull": true 3042 + }, 3043 + "uri": { 3044 + "name": "uri", 3045 + "type": "text", 3046 + "primaryKey": false, 3047 + "notNull": true 3048 + }, 3049 + "val": { 3050 + "name": "val", 3051 + "type": "text", 3052 + "primaryKey": false, 3053 + "notNull": true 3054 + }, 3055 + "neg": { 3056 + "name": "neg", 3057 + "type": "boolean", 3058 + "primaryKey": false, 3059 + "notNull": true, 3060 + "default": false 3061 + }, 3062 + "cts": { 3063 + "name": "cts", 3064 + "type": "timestamp with time zone", 3065 + "primaryKey": false, 3066 + "notNull": true 3067 + }, 3068 + "exp": { 3069 + "name": "exp", 3070 + "type": "timestamp with time zone", 3071 + "primaryKey": false, 3072 + "notNull": false 3073 + }, 3074 + "indexed_at": { 3075 + "name": "indexed_at", 3076 + "type": "timestamp with time zone", 3077 + "primaryKey": false, 3078 + "notNull": true, 3079 + "default": "now()" 3080 + } 3081 + }, 3082 + "indexes": { 3083 + "ozone_labels_src_uri_val_idx": { 3084 + "name": "ozone_labels_src_uri_val_idx", 3085 + "columns": [ 3086 + { 3087 + "expression": "src", 3088 + "isExpression": false, 3089 + "asc": true, 3090 + "nulls": "last" 3091 + }, 3092 + { 3093 + "expression": "uri", 3094 + "isExpression": false, 3095 + "asc": true, 3096 + "nulls": "last" 3097 + }, 3098 + { 3099 + "expression": "val", 3100 + "isExpression": false, 3101 + "asc": true, 3102 + "nulls": "last" 3103 + } 3104 + ], 3105 + "isUnique": true, 3106 + "concurrently": false, 3107 + "method": "btree", 3108 + "with": {} 3109 + }, 3110 + "ozone_labels_uri_idx": { 3111 + "name": "ozone_labels_uri_idx", 3112 + "columns": [ 3113 + { 3114 + "expression": "uri", 3115 + "isExpression": false, 3116 + "asc": true, 3117 + "nulls": "last" 3118 + } 3119 + ], 3120 + "isUnique": false, 3121 + "concurrently": false, 3122 + "method": "btree", 3123 + "with": {} 3124 + }, 3125 + "ozone_labels_val_idx": { 3126 + "name": "ozone_labels_val_idx", 3127 + "columns": [ 3128 + { 3129 + "expression": "val", 3130 + "isExpression": false, 3131 + "asc": true, 3132 + "nulls": "last" 3133 + } 3134 + ], 3135 + "isUnique": false, 3136 + "concurrently": false, 3137 + "method": "btree", 3138 + "with": {} 3139 + }, 3140 + "ozone_labels_indexed_at_idx": { 3141 + "name": "ozone_labels_indexed_at_idx", 3142 + "columns": [ 3143 + { 3144 + "expression": "indexed_at", 3145 + "isExpression": false, 3146 + "asc": true, 3147 + "nulls": "last" 3148 + } 3149 + ], 3150 + "isUnique": false, 3151 + "concurrently": false, 3152 + "method": "btree", 3153 + "with": {} 3154 + } 3155 + }, 3156 + "foreignKeys": {}, 3157 + "compositePrimaryKeys": {}, 3158 + "uniqueConstraints": {}, 3159 + "policies": {}, 3160 + "checkConstraints": {}, 3161 + "isRLSEnabled": false 3162 + }, 3163 + "public.community_profiles": { 3164 + "name": "community_profiles", 3165 + "schema": "", 3166 + "columns": { 3167 + "did": { 3168 + "name": "did", 3169 + "type": "text", 3170 + "primaryKey": false, 3171 + "notNull": true 3172 + }, 3173 + "community_did": { 3174 + "name": "community_did", 3175 + "type": "text", 3176 + "primaryKey": false, 3177 + "notNull": true 3178 + }, 3179 + "display_name": { 3180 + "name": "display_name", 3181 + "type": "text", 3182 + "primaryKey": false, 3183 + "notNull": false 3184 + }, 3185 + "avatar_url": { 3186 + "name": "avatar_url", 3187 + "type": "text", 3188 + "primaryKey": false, 3189 + "notNull": false 3190 + }, 3191 + "banner_url": { 3192 + "name": "banner_url", 3193 + "type": "text", 3194 + "primaryKey": false, 3195 + "notNull": false 3196 + }, 3197 + "bio": { 3198 + "name": "bio", 3199 + "type": "text", 3200 + "primaryKey": false, 3201 + "notNull": false 3202 + }, 3203 + "updated_at": { 3204 + "name": "updated_at", 3205 + "type": "timestamp with time zone", 3206 + "primaryKey": false, 3207 + "notNull": true, 3208 + "default": "now()" 3209 + } 3210 + }, 3211 + "indexes": { 3212 + "community_profiles_did_idx": { 3213 + "name": "community_profiles_did_idx", 3214 + "columns": [ 3215 + { 3216 + "expression": "did", 3217 + "isExpression": false, 3218 + "asc": true, 3219 + "nulls": "last" 3220 + } 3221 + ], 3222 + "isUnique": false, 3223 + "concurrently": false, 3224 + "method": "btree", 3225 + "with": {} 3226 + }, 3227 + "community_profiles_community_idx": { 3228 + "name": "community_profiles_community_idx", 3229 + "columns": [ 3230 + { 3231 + "expression": "community_did", 3232 + "isExpression": false, 3233 + "asc": true, 3234 + "nulls": "last" 3235 + } 3236 + ], 3237 + "isUnique": false, 3238 + "concurrently": false, 3239 + "method": "btree", 3240 + "with": {} 3241 + } 3242 + }, 3243 + "foreignKeys": {}, 3244 + "compositePrimaryKeys": { 3245 + "community_profiles_did_community_did_pk": { 3246 + "name": "community_profiles_did_community_did_pk", 3247 + "columns": ["did", "community_did"] 3248 + } 3249 + }, 3250 + "uniqueConstraints": {}, 3251 + "policies": { 3252 + "tenant_isolation": { 3253 + "name": "tenant_isolation", 3254 + "as": "PERMISSIVE", 3255 + "for": "ALL", 3256 + "to": ["barazo_app"], 3257 + "using": "community_did = current_setting('app.current_community_did', true)", 3258 + "withCheck": "community_did = current_setting('app.current_community_did', true)" 3259 + } 3260 + }, 3261 + "checkConstraints": {}, 3262 + "isRLSEnabled": true 3263 + }, 3264 + "public.interaction_graph": { 3265 + "name": "interaction_graph", 3266 + "schema": "", 3267 + "columns": { 3268 + "source_did": { 3269 + "name": "source_did", 3270 + "type": "text", 3271 + "primaryKey": false, 3272 + "notNull": true 3273 + }, 3274 + "target_did": { 3275 + "name": "target_did", 3276 + "type": "text", 3277 + "primaryKey": false, 3278 + "notNull": true 3279 + }, 3280 + "community_id": { 3281 + "name": "community_id", 3282 + "type": "text", 3283 + "primaryKey": false, 3284 + "notNull": true 3285 + }, 3286 + "interaction_type": { 3287 + "name": "interaction_type", 3288 + "type": "text", 3289 + "primaryKey": false, 3290 + "notNull": true 3291 + }, 3292 + "weight": { 3293 + "name": "weight", 3294 + "type": "integer", 3295 + "primaryKey": false, 3296 + "notNull": true, 3297 + "default": 1 3298 + }, 3299 + "first_interaction_at": { 3300 + "name": "first_interaction_at", 3301 + "type": "timestamp with time zone", 3302 + "primaryKey": false, 3303 + "notNull": true, 3304 + "default": "now()" 3305 + }, 3306 + "last_interaction_at": { 3307 + "name": "last_interaction_at", 3308 + "type": "timestamp with time zone", 3309 + "primaryKey": false, 3310 + "notNull": true, 3311 + "default": "now()" 3312 + } 3313 + }, 3314 + "indexes": { 3315 + "interaction_graph_source_target_community_idx": { 3316 + "name": "interaction_graph_source_target_community_idx", 3317 + "columns": [ 3318 + { 3319 + "expression": "source_did", 3320 + "isExpression": false, 3321 + "asc": true, 3322 + "nulls": "last" 3323 + }, 3324 + { 3325 + "expression": "target_did", 3326 + "isExpression": false, 3327 + "asc": true, 3328 + "nulls": "last" 3329 + }, 3330 + { 3331 + "expression": "community_id", 3332 + "isExpression": false, 3333 + "asc": true, 3334 + "nulls": "last" 3335 + } 3336 + ], 3337 + "isUnique": false, 3338 + "concurrently": false, 3339 + "method": "btree", 3340 + "with": {} 3341 + } 3342 + }, 3343 + "foreignKeys": {}, 3344 + "compositePrimaryKeys": { 3345 + "interaction_graph_source_did_target_did_community_id_interaction_type_pk": { 3346 + "name": "interaction_graph_source_did_target_did_community_id_interaction_type_pk", 3347 + "columns": ["source_did", "target_did", "community_id", "interaction_type"] 3348 + } 3349 + }, 3350 + "uniqueConstraints": {}, 3351 + "policies": {}, 3352 + "checkConstraints": {}, 3353 + "isRLSEnabled": false 3354 + }, 3355 + "public.trust_seeds": { 3356 + "name": "trust_seeds", 3357 + "schema": "", 3358 + "columns": { 3359 + "id": { 3360 + "name": "id", 3361 + "type": "serial", 3362 + "primaryKey": true, 3363 + "notNull": true 3364 + }, 3365 + "did": { 3366 + "name": "did", 3367 + "type": "text", 3368 + "primaryKey": false, 3369 + "notNull": true 3370 + }, 3371 + "community_id": { 3372 + "name": "community_id", 3373 + "type": "text", 3374 + "primaryKey": false, 3375 + "notNull": true, 3376 + "default": "''" 3377 + }, 3378 + "added_by": { 3379 + "name": "added_by", 3380 + "type": "text", 3381 + "primaryKey": false, 3382 + "notNull": true 3383 + }, 3384 + "reason": { 3385 + "name": "reason", 3386 + "type": "text", 3387 + "primaryKey": false, 3388 + "notNull": false 3389 + }, 3390 + "created_at": { 3391 + "name": "created_at", 3392 + "type": "timestamp with time zone", 3393 + "primaryKey": false, 3394 + "notNull": true, 3395 + "default": "now()" 3396 + } 3397 + }, 3398 + "indexes": { 3399 + "trust_seeds_did_community_idx": { 3400 + "name": "trust_seeds_did_community_idx", 3401 + "columns": [ 3402 + { 3403 + "expression": "did", 3404 + "isExpression": false, 3405 + "asc": true, 3406 + "nulls": "last" 3407 + }, 3408 + { 3409 + "expression": "community_id", 3410 + "isExpression": false, 3411 + "asc": true, 3412 + "nulls": "last" 3413 + } 3414 + ], 3415 + "isUnique": true, 3416 + "concurrently": false, 3417 + "method": "btree", 3418 + "with": {} 3419 + } 3420 + }, 3421 + "foreignKeys": {}, 3422 + "compositePrimaryKeys": {}, 3423 + "uniqueConstraints": {}, 3424 + "policies": {}, 3425 + "checkConstraints": {}, 3426 + "isRLSEnabled": false 3427 + }, 3428 + "public.trust_scores": { 3429 + "name": "trust_scores", 3430 + "schema": "", 3431 + "columns": { 3432 + "did": { 3433 + "name": "did", 3434 + "type": "text", 3435 + "primaryKey": false, 3436 + "notNull": true 3437 + }, 3438 + "community_id": { 3439 + "name": "community_id", 3440 + "type": "text", 3441 + "primaryKey": false, 3442 + "notNull": true, 3443 + "default": "''" 3444 + }, 3445 + "score": { 3446 + "name": "score", 3447 + "type": "real", 3448 + "primaryKey": false, 3449 + "notNull": true 3450 + }, 3451 + "computed_at": { 3452 + "name": "computed_at", 3453 + "type": "timestamp with time zone", 3454 + "primaryKey": false, 3455 + "notNull": true, 3456 + "default": "now()" 3457 + } 3458 + }, 3459 + "indexes": { 3460 + "trust_scores_did_community_idx": { 3461 + "name": "trust_scores_did_community_idx", 3462 + "columns": [ 3463 + { 3464 + "expression": "did", 3465 + "isExpression": false, 3466 + "asc": true, 3467 + "nulls": "last" 3468 + }, 3469 + { 3470 + "expression": "community_id", 3471 + "isExpression": false, 3472 + "asc": true, 3473 + "nulls": "last" 3474 + } 3475 + ], 3476 + "isUnique": false, 3477 + "concurrently": false, 3478 + "method": "btree", 3479 + "with": {} 3480 + } 3481 + }, 3482 + "foreignKeys": {}, 3483 + "compositePrimaryKeys": { 3484 + "trust_scores_did_community_id_pk": { 3485 + "name": "trust_scores_did_community_id_pk", 3486 + "columns": ["did", "community_id"] 3487 + } 3488 + }, 3489 + "uniqueConstraints": {}, 3490 + "policies": {}, 3491 + "checkConstraints": {}, 3492 + "isRLSEnabled": false 3493 + }, 3494 + "public.sybil_clusters": { 3495 + "name": "sybil_clusters", 3496 + "schema": "", 3497 + "columns": { 3498 + "id": { 3499 + "name": "id", 3500 + "type": "serial", 3501 + "primaryKey": true, 3502 + "notNull": true 3503 + }, 3504 + "cluster_hash": { 3505 + "name": "cluster_hash", 3506 + "type": "text", 3507 + "primaryKey": false, 3508 + "notNull": true 3509 + }, 3510 + "internal_edge_count": { 3511 + "name": "internal_edge_count", 3512 + "type": "integer", 3513 + "primaryKey": false, 3514 + "notNull": true 3515 + }, 3516 + "external_edge_count": { 3517 + "name": "external_edge_count", 3518 + "type": "integer", 3519 + "primaryKey": false, 3520 + "notNull": true 3521 + }, 3522 + "member_count": { 3523 + "name": "member_count", 3524 + "type": "integer", 3525 + "primaryKey": false, 3526 + "notNull": true 3527 + }, 3528 + "status": { 3529 + "name": "status", 3530 + "type": "text", 3531 + "primaryKey": false, 3532 + "notNull": true, 3533 + "default": "'flagged'" 3534 + }, 3535 + "reviewed_by": { 3536 + "name": "reviewed_by", 3537 + "type": "text", 3538 + "primaryKey": false, 3539 + "notNull": false 3540 + }, 3541 + "reviewed_at": { 3542 + "name": "reviewed_at", 3543 + "type": "timestamp with time zone", 3544 + "primaryKey": false, 3545 + "notNull": false 3546 + }, 3547 + "detected_at": { 3548 + "name": "detected_at", 3549 + "type": "timestamp with time zone", 3550 + "primaryKey": false, 3551 + "notNull": true, 3552 + "default": "now()" 3553 + }, 3554 + "updated_at": { 3555 + "name": "updated_at", 3556 + "type": "timestamp with time zone", 3557 + "primaryKey": false, 3558 + "notNull": true, 3559 + "default": "now()" 3560 + } 3561 + }, 3562 + "indexes": { 3563 + "sybil_clusters_hash_idx": { 3564 + "name": "sybil_clusters_hash_idx", 3565 + "columns": [ 3566 + { 3567 + "expression": "cluster_hash", 3568 + "isExpression": false, 3569 + "asc": true, 3570 + "nulls": "last" 3571 + } 3572 + ], 3573 + "isUnique": true, 3574 + "concurrently": false, 3575 + "method": "btree", 3576 + "with": {} 3577 + } 3578 + }, 3579 + "foreignKeys": {}, 3580 + "compositePrimaryKeys": {}, 3581 + "uniqueConstraints": {}, 3582 + "policies": {}, 3583 + "checkConstraints": {}, 3584 + "isRLSEnabled": false 3585 + }, 3586 + "public.sybil_cluster_members": { 3587 + "name": "sybil_cluster_members", 3588 + "schema": "", 3589 + "columns": { 3590 + "cluster_id": { 3591 + "name": "cluster_id", 3592 + "type": "integer", 3593 + "primaryKey": false, 3594 + "notNull": true 3595 + }, 3596 + "did": { 3597 + "name": "did", 3598 + "type": "text", 3599 + "primaryKey": false, 3600 + "notNull": true 3601 + }, 3602 + "role_in_cluster": { 3603 + "name": "role_in_cluster", 3604 + "type": "text", 3605 + "primaryKey": false, 3606 + "notNull": true 3607 + }, 3608 + "joined_at": { 3609 + "name": "joined_at", 3610 + "type": "timestamp with time zone", 3611 + "primaryKey": false, 3612 + "notNull": true, 3613 + "default": "now()" 3614 + } 3615 + }, 3616 + "indexes": {}, 3617 + "foreignKeys": { 3618 + "sybil_cluster_members_cluster_id_sybil_clusters_id_fk": { 3619 + "name": "sybil_cluster_members_cluster_id_sybil_clusters_id_fk", 3620 + "tableFrom": "sybil_cluster_members", 3621 + "tableTo": "sybil_clusters", 3622 + "columnsFrom": ["cluster_id"], 3623 + "columnsTo": ["id"], 3624 + "onDelete": "no action", 3625 + "onUpdate": "no action" 3626 + } 3627 + }, 3628 + "compositePrimaryKeys": { 3629 + "sybil_cluster_members_cluster_id_did_pk": { 3630 + "name": "sybil_cluster_members_cluster_id_did_pk", 3631 + "columns": ["cluster_id", "did"] 3632 + } 3633 + }, 3634 + "uniqueConstraints": {}, 3635 + "policies": {}, 3636 + "checkConstraints": {}, 3637 + "isRLSEnabled": false 3638 + }, 3639 + "public.behavioral_flags": { 3640 + "name": "behavioral_flags", 3641 + "schema": "", 3642 + "columns": { 3643 + "id": { 3644 + "name": "id", 3645 + "type": "serial", 3646 + "primaryKey": true, 3647 + "notNull": true 3648 + }, 3649 + "flag_type": { 3650 + "name": "flag_type", 3651 + "type": "text", 3652 + "primaryKey": false, 3653 + "notNull": true 3654 + }, 3655 + "affected_dids": { 3656 + "name": "affected_dids", 3657 + "type": "jsonb", 3658 + "primaryKey": false, 3659 + "notNull": true 3660 + }, 3661 + "details": { 3662 + "name": "details", 3663 + "type": "text", 3664 + "primaryKey": false, 3665 + "notNull": true 3666 + }, 3667 + "community_did": { 3668 + "name": "community_did", 3669 + "type": "text", 3670 + "primaryKey": false, 3671 + "notNull": false 3672 + }, 3673 + "status": { 3674 + "name": "status", 3675 + "type": "text", 3676 + "primaryKey": false, 3677 + "notNull": true, 3678 + "default": "'pending'" 3679 + }, 3680 + "detected_at": { 3681 + "name": "detected_at", 3682 + "type": "timestamp with time zone", 3683 + "primaryKey": false, 3684 + "notNull": true, 3685 + "default": "now()" 3686 + } 3687 + }, 3688 + "indexes": { 3689 + "behavioral_flags_flag_type_idx": { 3690 + "name": "behavioral_flags_flag_type_idx", 3691 + "columns": [ 3692 + { 3693 + "expression": "flag_type", 3694 + "isExpression": false, 3695 + "asc": true, 3696 + "nulls": "last" 3697 + } 3698 + ], 3699 + "isUnique": false, 3700 + "concurrently": false, 3701 + "method": "btree", 3702 + "with": {} 3703 + }, 3704 + "behavioral_flags_status_idx": { 3705 + "name": "behavioral_flags_status_idx", 3706 + "columns": [ 3707 + { 3708 + "expression": "status", 3709 + "isExpression": false, 3710 + "asc": true, 3711 + "nulls": "last" 3712 + } 3713 + ], 3714 + "isUnique": false, 3715 + "concurrently": false, 3716 + "method": "btree", 3717 + "with": {} 3718 + }, 3719 + "behavioral_flags_detected_at_idx": { 3720 + "name": "behavioral_flags_detected_at_idx", 3721 + "columns": [ 3722 + { 3723 + "expression": "detected_at", 3724 + "isExpression": false, 3725 + "asc": true, 3726 + "nulls": "last" 3727 + } 3728 + ], 3729 + "isUnique": false, 3730 + "concurrently": false, 3731 + "method": "btree", 3732 + "with": {} 3733 + } 3734 + }, 3735 + "foreignKeys": {}, 3736 + "compositePrimaryKeys": {}, 3737 + "uniqueConstraints": {}, 3738 + "policies": {}, 3739 + "checkConstraints": {}, 3740 + "isRLSEnabled": false 3741 + }, 3742 + "public.pds_trust_factors": { 3743 + "name": "pds_trust_factors", 3744 + "schema": "", 3745 + "columns": { 3746 + "id": { 3747 + "name": "id", 3748 + "type": "serial", 3749 + "primaryKey": true, 3750 + "notNull": true 3751 + }, 3752 + "pds_host": { 3753 + "name": "pds_host", 3754 + "type": "text", 3755 + "primaryKey": false, 3756 + "notNull": true 3757 + }, 3758 + "trust_factor": { 3759 + "name": "trust_factor", 3760 + "type": "real", 3761 + "primaryKey": false, 3762 + "notNull": true 3763 + }, 3764 + "is_default": { 3765 + "name": "is_default", 3766 + "type": "boolean", 3767 + "primaryKey": false, 3768 + "notNull": true, 3769 + "default": false 3770 + }, 3771 + "updated_at": { 3772 + "name": "updated_at", 3773 + "type": "timestamp with time zone", 3774 + "primaryKey": false, 3775 + "notNull": true, 3776 + "default": "now()" 3777 + } 3778 + }, 3779 + "indexes": { 3780 + "pds_trust_factors_pds_host_idx": { 3781 + "name": "pds_trust_factors_pds_host_idx", 3782 + "columns": [ 3783 + { 3784 + "expression": "pds_host", 3785 + "isExpression": false, 3786 + "asc": true, 3787 + "nulls": "last" 3788 + } 3789 + ], 3790 + "isUnique": true, 3791 + "concurrently": false, 3792 + "method": "btree", 3793 + "with": {} 3794 + } 3795 + }, 3796 + "foreignKeys": {}, 3797 + "compositePrimaryKeys": {}, 3798 + "uniqueConstraints": {}, 3799 + "policies": {}, 3800 + "checkConstraints": {}, 3801 + "isRLSEnabled": false 3802 + }, 3803 + "public.pages": { 3804 + "name": "pages", 3805 + "schema": "", 3806 + "columns": { 3807 + "id": { 3808 + "name": "id", 3809 + "type": "text", 3810 + "primaryKey": true, 3811 + "notNull": true 3812 + }, 3813 + "slug": { 3814 + "name": "slug", 3815 + "type": "text", 3816 + "primaryKey": false, 3817 + "notNull": true 3818 + }, 3819 + "title": { 3820 + "name": "title", 3821 + "type": "text", 3822 + "primaryKey": false, 3823 + "notNull": true 3824 + }, 3825 + "content": { 3826 + "name": "content", 3827 + "type": "text", 3828 + "primaryKey": false, 3829 + "notNull": true 3830 + }, 3831 + "status": { 3832 + "name": "status", 3833 + "type": "text", 3834 + "primaryKey": false, 3835 + "notNull": true, 3836 + "default": "'draft'" 3837 + }, 3838 + "meta_description": { 3839 + "name": "meta_description", 3840 + "type": "text", 3841 + "primaryKey": false, 3842 + "notNull": false 3843 + }, 3844 + "parent_id": { 3845 + "name": "parent_id", 3846 + "type": "text", 3847 + "primaryKey": false, 3848 + "notNull": false 3849 + }, 3850 + "sort_order": { 3851 + "name": "sort_order", 3852 + "type": "integer", 3853 + "primaryKey": false, 3854 + "notNull": true, 3855 + "default": 0 3856 + }, 3857 + "community_did": { 3858 + "name": "community_did", 3859 + "type": "text", 3860 + "primaryKey": false, 3861 + "notNull": true 3862 + }, 3863 + "created_at": { 3864 + "name": "created_at", 3865 + "type": "timestamp with time zone", 3866 + "primaryKey": false, 3867 + "notNull": true, 3868 + "default": "now()" 3869 + }, 3870 + "updated_at": { 3871 + "name": "updated_at", 3872 + "type": "timestamp with time zone", 3873 + "primaryKey": false, 3874 + "notNull": true, 3875 + "default": "now()" 3876 + } 3877 + }, 3878 + "indexes": { 3879 + "pages_slug_community_did_idx": { 3880 + "name": "pages_slug_community_did_idx", 3881 + "columns": [ 3882 + { 3883 + "expression": "slug", 3884 + "isExpression": false, 3885 + "asc": true, 3886 + "nulls": "last" 3887 + }, 3888 + { 3889 + "expression": "community_did", 3890 + "isExpression": false, 3891 + "asc": true, 3892 + "nulls": "last" 3893 + } 3894 + ], 3895 + "isUnique": true, 3896 + "concurrently": false, 3897 + "method": "btree", 3898 + "with": {} 3899 + }, 3900 + "pages_community_did_idx": { 3901 + "name": "pages_community_did_idx", 3902 + "columns": [ 3903 + { 3904 + "expression": "community_did", 3905 + "isExpression": false, 3906 + "asc": true, 3907 + "nulls": "last" 3908 + } 3909 + ], 3910 + "isUnique": false, 3911 + "concurrently": false, 3912 + "method": "btree", 3913 + "with": {} 3914 + }, 3915 + "pages_parent_id_idx": { 3916 + "name": "pages_parent_id_idx", 3917 + "columns": [ 3918 + { 3919 + "expression": "parent_id", 3920 + "isExpression": false, 3921 + "asc": true, 3922 + "nulls": "last" 3923 + } 3924 + ], 3925 + "isUnique": false, 3926 + "concurrently": false, 3927 + "method": "btree", 3928 + "with": {} 3929 + }, 3930 + "pages_status_community_did_idx": { 3931 + "name": "pages_status_community_did_idx", 3932 + "columns": [ 3933 + { 3934 + "expression": "status", 3935 + "isExpression": false, 3936 + "asc": true, 3937 + "nulls": "last" 3938 + }, 3939 + { 3940 + "expression": "community_did", 3941 + "isExpression": false, 3942 + "asc": true, 3943 + "nulls": "last" 3944 + } 3945 + ], 3946 + "isUnique": false, 3947 + "concurrently": false, 3948 + "method": "btree", 3949 + "with": {} 3950 + } 3951 + }, 3952 + "foreignKeys": { 3953 + "pages_parent_id_fk": { 3954 + "name": "pages_parent_id_fk", 3955 + "tableFrom": "pages", 3956 + "tableTo": "pages", 3957 + "columnsFrom": ["parent_id"], 3958 + "columnsTo": ["id"], 3959 + "onDelete": "set null", 3960 + "onUpdate": "no action" 3961 + } 3962 + }, 3963 + "compositePrimaryKeys": {}, 3964 + "uniqueConstraints": {}, 3965 + "policies": { 3966 + "tenant_isolation": { 3967 + "name": "tenant_isolation", 3968 + "as": "PERMISSIVE", 3969 + "for": "ALL", 3970 + "to": ["barazo_app"], 3971 + "using": "community_did = current_setting('app.current_community_did', true)", 3972 + "withCheck": "community_did = current_setting('app.current_community_did', true)" 3973 + } 3974 + }, 3975 + "checkConstraints": {}, 3976 + "isRLSEnabled": true 3977 + } 3978 + }, 3979 + "enums": {}, 3980 + "schemas": {}, 3981 + "sequences": {}, 3982 + "roles": { 3983 + "barazo_app": { 3984 + "name": "barazo_app", 3985 + "createDb": false, 3986 + "createRole": false, 3987 + "inherit": true 3988 + } 3989 + }, 3990 + "policies": {}, 3991 + "views": {}, 3992 + "_meta": { 3993 + "columns": {}, 3994 + "schemas": {}, 3995 + "tables": {} 3996 + } 3997 + }
+7
drizzle/meta/_journal.json
··· 43 43 "when": 1772623579346, 44 44 "tag": "0005_threading-schema", 45 45 "breakpoints": true 46 + }, 47 + { 48 + "idx": 6, 49 + "version": "7", 50 + "when": 1772624609912, 51 + "tag": "0006_add_header_logo", 52 + "breakpoints": true 46 53 } 47 54 ] 48 55 }
+2
src/db/schema/community-settings.ts
··· 56 56 rotationKey: text('rotation_key'), 57 57 communityLogoUrl: text('community_logo_url'), 58 58 faviconUrl: text('favicon_url'), 59 + headerLogoUrl: text('header_logo_url'), 60 + showCommunityName: boolean('show_community_name').notNull().default(true), 59 61 primaryColor: text('primary_color'), 60 62 accentColor: text('accent_color'), 61 63 createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
+55
src/routes/admin-design.ts
··· 9 9 10 10 const LOGO_SIZE = { width: 512, height: 512 } 11 11 const FAVICON_SIZE = { width: 256, height: 256 } 12 + const HEADER_LOGO_MAX = { width: 600, height: 120 } 12 13 13 14 // --------------------------------------------------------------------------- 14 15 // OpenAPI JSON Schema definitions ··· 133 134 await db 134 135 .update(communitySettings) 135 136 .set({ faviconUrl: url, updatedAt: new Date() }) 137 + .where(eq(communitySettings.communityDid, communityDid)) 138 + 139 + return reply.status(200).send({ url }) 140 + } 141 + ) 142 + 143 + // ----------------------------------------------------------------- 144 + // POST /api/admin/design/header-logo 145 + // ----------------------------------------------------------------- 146 + 147 + app.post( 148 + '/api/admin/design/header-logo', 149 + { 150 + preHandler: [requireAdmin], 151 + schema: { 152 + tags: ['Admin', 'Design'], 153 + summary: 'Upload community header logo', 154 + security: [{ bearerAuth: [] }], 155 + consumes: ['multipart/form-data'], 156 + response: { 157 + 200: uploadResponseJsonSchema, 158 + 400: errorResponseSchema, 159 + 401: errorResponseSchema, 160 + 403: errorResponseSchema, 161 + }, 162 + }, 163 + }, 164 + async (request, reply) => { 165 + const communityDid = requireCommunityDid(request) 166 + 167 + const file = await request.file() 168 + if (!file) throw badRequest('No file uploaded') 169 + if (!ALLOWED_MIMES.has(file.mimetype)) { 170 + throw badRequest('File must be JPEG, PNG, WebP, or GIF') 171 + } 172 + 173 + const buffer = await file.toBuffer() 174 + if (buffer.length > maxSize) { 175 + throw badRequest(`File too large (max ${String(Math.round(maxSize / 1024 / 1024))}MB)`) 176 + } 177 + 178 + const processed = await sharp(buffer) 179 + .resize(HEADER_LOGO_MAX.width, HEADER_LOGO_MAX.height, { 180 + fit: 'inside', 181 + withoutEnlargement: true, 182 + }) 183 + .webp({ quality: 85 }) 184 + .toBuffer() 185 + 186 + const url = await storage.store(processed, 'image/webp', 'header-logos') 187 + 188 + await db 189 + .update(communitySettings) 190 + .set({ headerLogoUrl: url, updatedAt: new Date() }) 136 191 .where(eq(communitySettings.communityDid, communityDid)) 137 192 138 193 return reply.status(200).send({ url })
+18
src/routes/admin-settings.ts
··· 23 23 communityDescription: { type: ['string', 'null'] as const }, 24 24 communityLogoUrl: { type: ['string', 'null'] as const }, 25 25 faviconUrl: { type: ['string', 'null'] as const }, 26 + headerLogoUrl: { type: ['string', 'null'] as const }, 27 + showCommunityName: { type: 'boolean' as const }, 26 28 primaryColor: { type: ['string', 'null'] as const }, 27 29 accentColor: { type: ['string', 'null'] as const }, 28 30 jurisdictionCountry: { type: ['string', 'null'] as const }, ··· 89 91 communityDescription: row.communityDescription ?? null, 90 92 communityLogoUrl: row.communityLogoUrl ?? null, 91 93 faviconUrl: row.faviconUrl ?? null, 94 + headerLogoUrl: row.headerLogoUrl ?? null, 95 + showCommunityName: row.showCommunityName, 92 96 primaryColor: row.primaryColor ?? null, 93 97 accentColor: row.accentColor ?? null, 94 98 jurisdictionCountry: row.jurisdictionCountry ?? null, ··· 136 140 communityDescription: { type: ['string', 'null'] as const }, 137 141 communityLogoUrl: { type: ['string', 'null'] as const }, 138 142 faviconUrl: { type: ['string', 'null'] as const }, 143 + headerLogoUrl: { type: ['string', 'null'] as const }, 144 + showCommunityName: { type: 'boolean' as const }, 139 145 maxReplyDepth: { type: 'integer' as const }, 140 146 }, 141 147 }, ··· 162 168 communityDescription: row.communityDescription ?? null, 163 169 communityLogoUrl: row.communityLogoUrl ?? null, 164 170 faviconUrl: row.faviconUrl ?? null, 171 + headerLogoUrl: row.headerLogoUrl ?? null, 172 + showCommunityName: row.showCommunityName, 165 173 maxReplyDepth: row.maxReplyDepth, 166 174 }) 167 175 } ··· 228 236 communityDescription: { type: ['string', 'null'], maxLength: 500 }, 229 237 communityLogoUrl: { type: ['string', 'null'], format: 'uri' }, 230 238 faviconUrl: { type: ['string', 'null'], format: 'uri' }, 239 + headerLogoUrl: { type: ['string', 'null'], format: 'uri' }, 240 + showCommunityName: { type: 'boolean' }, 231 241 primaryColor: { 232 242 type: ['string', 'null'], 233 243 pattern: '^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$', ··· 269 279 updates.communityDescription === undefined && 270 280 updates.communityLogoUrl === undefined && 271 281 updates.faviconUrl === undefined && 282 + updates.headerLogoUrl === undefined && 283 + updates.showCommunityName === undefined && 272 284 updates.primaryColor === undefined && 273 285 updates.accentColor === undefined && 274 286 updates.jurisdictionCountry === undefined && ··· 352 364 } 353 365 if (updates.faviconUrl !== undefined) { 354 366 dbUpdates.faviconUrl = updates.faviconUrl 367 + } 368 + if (updates.headerLogoUrl !== undefined) { 369 + dbUpdates.headerLogoUrl = updates.headerLogoUrl 370 + } 371 + if (updates.showCommunityName !== undefined) { 372 + dbUpdates.showCommunityName = updates.showCommunityName 355 373 } 356 374 if (updates.primaryColor !== undefined) { 357 375 dbUpdates.primaryColor = updates.primaryColor
+4
src/validation/admin-settings.ts
··· 27 27 .optional(), 28 28 communityLogoUrl: z.url('Community logo must be a valid URL').nullable().optional(), 29 29 faviconUrl: z.url('Favicon must be a valid URL').nullable().optional(), 30 + headerLogoUrl: z.url('Header logo must be a valid URL').nullable().optional(), 31 + showCommunityName: z.boolean().optional(), 30 32 primaryColor: z 31 33 .string() 32 34 .regex(hexColorPattern, 'Primary color must be a valid hex color (e.g., #ff0000)') ··· 76 78 communityDescription: z.string().nullable(), 77 79 communityLogoUrl: z.string().nullable(), 78 80 faviconUrl: z.string().nullable(), 81 + headerLogoUrl: z.string().nullable(), 82 + showCommunityName: z.boolean(), 79 83 primaryColor: z.string().nullable(), 80 84 accentColor: z.string().nullable(), 81 85 jurisdictionCountry: z.string().nullable(),
+2
tests/integration/tenant-isolation.test.ts
··· 43 43 rotation_key TEXT, 44 44 community_logo_url TEXT, 45 45 favicon_url TEXT, 46 + header_logo_url TEXT, 47 + show_community_name BOOLEAN NOT NULL DEFAULT true, 46 48 primary_color TEXT, 47 49 accent_color TEXT, 48 50 created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
+144
tests/unit/routes/admin-design.test.ts
··· 468 468 expect(response.statusCode).toBe(400) 469 469 }) 470 470 }) 471 + 472 + // ========================================================================= 473 + // POST /api/admin/design/header-logo 474 + // ========================================================================= 475 + 476 + describe('POST /api/admin/design/header-logo', () => { 477 + let app: FastifyInstance 478 + let mockStorage: StorageService 479 + 480 + beforeAll(async () => { 481 + mockStorage = createMockStorage() 482 + ;(mockStorage.store as ReturnType<typeof vi.fn>).mockResolvedValue( 483 + 'http://localhost:3000/uploads/header-logos/test.webp' 484 + ) 485 + app = await buildTestApp(testUser(), mockStorage) 486 + }) 487 + 488 + afterAll(async () => { 489 + await app.close() 490 + }) 491 + 492 + beforeEach(() => { 493 + vi.clearAllMocks() 494 + resetAllDbMocks() 495 + ;(mockStorage.store as ReturnType<typeof vi.fn>).mockResolvedValue( 496 + 'http://localhost:3000/uploads/header-logos/test.webp' 497 + ) 498 + }) 499 + 500 + it('uploads header logo and returns URL', async () => { 501 + const imageData = Buffer.from('fake-png-data') 502 + const { body, contentType } = createMultipartPayload('header.png', 'image/png', imageData) 503 + 504 + const response = await app.inject({ 505 + method: 'POST', 506 + url: '/api/admin/design/header-logo', 507 + headers: { 508 + authorization: 'Bearer test-token', 509 + 'content-type': contentType, 510 + }, 511 + body, 512 + }) 513 + 514 + expect(response.statusCode).toBe(200) 515 + const result = response.json<{ url: string }>() 516 + expect(result.url).toBe('http://localhost:3000/uploads/header-logos/test.webp') 517 + // eslint-disable-next-line @typescript-eslint/unbound-method 518 + expect(mockStorage.store).toHaveBeenCalledOnce() 519 + expect(mockDb.update).toHaveBeenCalledOnce() 520 + }) 521 + 522 + it('resizes header logo to 600x120 with fit inside', async () => { 523 + const imageData = Buffer.from('fake-png-data') 524 + const { body, contentType } = createMultipartPayload('header.png', 'image/png', imageData) 525 + 526 + await app.inject({ 527 + method: 'POST', 528 + url: '/api/admin/design/header-logo', 529 + headers: { 530 + authorization: 'Bearer test-token', 531 + 'content-type': contentType, 532 + }, 533 + body, 534 + }) 535 + 536 + expect(mockSharpInstance.resize).toHaveBeenCalledWith(600, 120, { 537 + fit: 'inside', 538 + withoutEnlargement: true, 539 + }) 540 + expect(mockSharpInstance.webp).toHaveBeenCalledWith({ quality: 85 }) 541 + }) 542 + 543 + it('stores with header-logos prefix', async () => { 544 + const imageData = Buffer.from('fake-png-data') 545 + const { body, contentType } = createMultipartPayload('header.png', 'image/png', imageData) 546 + 547 + await app.inject({ 548 + method: 'POST', 549 + url: '/api/admin/design/header-logo', 550 + headers: { 551 + authorization: 'Bearer test-token', 552 + 'content-type': contentType, 553 + }, 554 + body, 555 + }) 556 + 557 + // eslint-disable-next-line @typescript-eslint/unbound-method 558 + expect(mockStorage.store).toHaveBeenCalledWith( 559 + expect.any(Buffer), 560 + 'image/webp', 561 + 'header-logos' 562 + ) 563 + }) 564 + 565 + it('returns 401 when not authenticated', async () => { 566 + const noAuthApp = await buildTestApp(undefined) 567 + const imageData = Buffer.from('fake-png-data') 568 + const { body, contentType } = createMultipartPayload('header.png', 'image/png', imageData) 569 + 570 + const response = await noAuthApp.inject({ 571 + method: 'POST', 572 + url: '/api/admin/design/header-logo', 573 + headers: { 'content-type': contentType }, 574 + body, 575 + }) 576 + 577 + expect(response.statusCode).toBe(401) 578 + await noAuthApp.close() 579 + }) 580 + 581 + it('returns 400 when no file is uploaded', async () => { 582 + const response = await app.inject({ 583 + method: 'POST', 584 + url: '/api/admin/design/header-logo', 585 + headers: { 586 + authorization: 'Bearer test-token', 587 + 'content-type': 'multipart/form-data; boundary=----EmptyBoundary', 588 + }, 589 + body: '------EmptyBoundary--\r\n', 590 + }) 591 + 592 + expect(response.statusCode).toBe(400) 593 + }) 594 + 595 + it('returns 400 for invalid MIME type', async () => { 596 + const { body, contentType } = createMultipartPayload( 597 + 'doc.txt', 598 + 'text/plain', 599 + Buffer.from('not-an-image') 600 + ) 601 + 602 + const response = await app.inject({ 603 + method: 'POST', 604 + url: '/api/admin/design/header-logo', 605 + headers: { 606 + authorization: 'Bearer test-token', 607 + 'content-type': contentType, 608 + }, 609 + body, 610 + }) 611 + 612 + expect(response.statusCode).toBe(400) 613 + }) 614 + }) 471 615 })