Exosphere is a set of small, modular, self-hostable community tools built on the AT Protocol. app.exosphere.site
6
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor: remove categories

Hugo 206bad36 ed980b47

+1552 -172
+2 -3
TODO.md
··· 30 30 31 31 ## Feature Requests Module 32 32 33 - - [x] Submit feature requests (title, description, category) 33 + - [x] Submit feature requests (title, description) 34 34 - [ ] Handle feature request edition 35 35 - [ ] Should we have the ability to do it? 36 36 - [ ] How do we show to users that a feature request was indeed edited ··· 40 40 - [x] Admin ability to update status 41 41 - [ ] Post official/pinned responses 42 42 - [x] Sort by top voted, newest 43 - - [ ] Filter by status by category 43 + - [ ] Filter by status 44 44 - [ ] Comments on requests 45 45 - [x] Simple comments 46 46 - [ ] Comments threads on requests 47 47 - [x] Merge duplicate requests 48 - - [ ] Request categories management 49 48 50 49 ## Feeds Module 51 50
+2
drizzle/0006_melodic_menace.sql
··· 1 + DROP INDEX `idx_feature_requests_category`;--> statement-breakpoint 2 + ALTER TABLE `feature_requests` DROP COLUMN `category`;
+1523
drizzle/meta/0006_snapshot.json
··· 1 + { 2 + "version": "6", 3 + "dialect": "sqlite", 4 + "id": "eec14d3f-541d-45c5-844c-4b45eb164b0c", 5 + "prevId": "f024260b-c00f-40d3-981d-89f2c8962fe8", 6 + "tables": { 7 + "oauth_sessions": { 8 + "name": "oauth_sessions", 9 + "columns": { 10 + "key": { 11 + "name": "key", 12 + "type": "text", 13 + "primaryKey": true, 14 + "notNull": true, 15 + "autoincrement": false 16 + }, 17 + "session": { 18 + "name": "session", 19 + "type": "text", 20 + "primaryKey": false, 21 + "notNull": true, 22 + "autoincrement": false 23 + }, 24 + "created_at": { 25 + "name": "created_at", 26 + "type": "text", 27 + "primaryKey": false, 28 + "notNull": true, 29 + "autoincrement": false, 30 + "default": "(datetime('now'))" 31 + }, 32 + "updated_at": { 33 + "name": "updated_at", 34 + "type": "text", 35 + "primaryKey": false, 36 + "notNull": true, 37 + "autoincrement": false, 38 + "default": "(datetime('now'))" 39 + } 40 + }, 41 + "indexes": {}, 42 + "foreignKeys": {}, 43 + "compositePrimaryKeys": {}, 44 + "uniqueConstraints": {}, 45 + "checkConstraints": {} 46 + }, 47 + "oauth_states": { 48 + "name": "oauth_states", 49 + "columns": { 50 + "key": { 51 + "name": "key", 52 + "type": "text", 53 + "primaryKey": true, 54 + "notNull": true, 55 + "autoincrement": false 56 + }, 57 + "state": { 58 + "name": "state", 59 + "type": "text", 60 + "primaryKey": false, 61 + "notNull": true, 62 + "autoincrement": false 63 + }, 64 + "created_at": { 65 + "name": "created_at", 66 + "type": "text", 67 + "primaryKey": false, 68 + "notNull": true, 69 + "autoincrement": false, 70 + "default": "(datetime('now'))" 71 + } 72 + }, 73 + "indexes": {}, 74 + "foreignKeys": {}, 75 + "compositePrimaryKeys": {}, 76 + "uniqueConstraints": {}, 77 + "checkConstraints": {} 78 + }, 79 + "indexer_cursor": { 80 + "name": "indexer_cursor", 81 + "columns": { 82 + "id": { 83 + "name": "id", 84 + "type": "text", 85 + "primaryKey": true, 86 + "notNull": true, 87 + "autoincrement": false, 88 + "default": "'jetstream'" 89 + }, 90 + "cursor": { 91 + "name": "cursor", 92 + "type": "integer", 93 + "primaryKey": false, 94 + "notNull": true, 95 + "autoincrement": false 96 + }, 97 + "updated_at": { 98 + "name": "updated_at", 99 + "type": "text", 100 + "primaryKey": false, 101 + "notNull": true, 102 + "autoincrement": false, 103 + "default": "(datetime('now'))" 104 + } 105 + }, 106 + "indexes": {}, 107 + "foreignKeys": {}, 108 + "compositePrimaryKeys": {}, 109 + "uniqueConstraints": {}, 110 + "checkConstraints": {} 111 + }, 112 + "sphere_entry_counter": { 113 + "name": "sphere_entry_counter", 114 + "columns": { 115 + "sphere_id": { 116 + "name": "sphere_id", 117 + "type": "text", 118 + "primaryKey": true, 119 + "notNull": true, 120 + "autoincrement": false 121 + }, 122 + "last_number": { 123 + "name": "last_number", 124 + "type": "integer", 125 + "primaryKey": false, 126 + "notNull": true, 127 + "autoincrement": false, 128 + "default": 0 129 + } 130 + }, 131 + "indexes": {}, 132 + "foreignKeys": { 133 + "sphere_entry_counter_sphere_id_spheres_id_fk": { 134 + "name": "sphere_entry_counter_sphere_id_spheres_id_fk", 135 + "tableFrom": "sphere_entry_counter", 136 + "tableTo": "spheres", 137 + "columnsFrom": [ 138 + "sphere_id" 139 + ], 140 + "columnsTo": [ 141 + "id" 142 + ], 143 + "onDelete": "no action", 144 + "onUpdate": "no action" 145 + } 146 + }, 147 + "compositePrimaryKeys": {}, 148 + "uniqueConstraints": {}, 149 + "checkConstraints": {} 150 + }, 151 + "entity_labels": { 152 + "name": "entity_labels", 153 + "columns": { 154 + "label_id": { 155 + "name": "label_id", 156 + "type": "text", 157 + "primaryKey": false, 158 + "notNull": true, 159 + "autoincrement": false 160 + }, 161 + "entity_id": { 162 + "name": "entity_id", 163 + "type": "text", 164 + "primaryKey": false, 165 + "notNull": true, 166 + "autoincrement": false 167 + }, 168 + "entity_type": { 169 + "name": "entity_type", 170 + "type": "text", 171 + "primaryKey": false, 172 + "notNull": true, 173 + "autoincrement": false 174 + } 175 + }, 176 + "indexes": { 177 + "idx_entity_labels_entity": { 178 + "name": "idx_entity_labels_entity", 179 + "columns": [ 180 + "entity_id", 181 + "entity_type" 182 + ], 183 + "isUnique": false 184 + } 185 + }, 186 + "foreignKeys": { 187 + "entity_labels_label_id_sphere_labels_id_fk": { 188 + "name": "entity_labels_label_id_sphere_labels_id_fk", 189 + "tableFrom": "entity_labels", 190 + "tableTo": "sphere_labels", 191 + "columnsFrom": [ 192 + "label_id" 193 + ], 194 + "columnsTo": [ 195 + "id" 196 + ], 197 + "onDelete": "cascade", 198 + "onUpdate": "no action" 199 + } 200 + }, 201 + "compositePrimaryKeys": { 202 + "entity_labels_label_id_entity_id_pk": { 203 + "columns": [ 204 + "label_id", 205 + "entity_id" 206 + ], 207 + "name": "entity_labels_label_id_entity_id_pk" 208 + } 209 + }, 210 + "uniqueConstraints": {}, 211 + "checkConstraints": {} 212 + }, 213 + "sphere_labels": { 214 + "name": "sphere_labels", 215 + "columns": { 216 + "id": { 217 + "name": "id", 218 + "type": "text", 219 + "primaryKey": true, 220 + "notNull": true, 221 + "autoincrement": false 222 + }, 223 + "sphere_id": { 224 + "name": "sphere_id", 225 + "type": "text", 226 + "primaryKey": false, 227 + "notNull": true, 228 + "autoincrement": false 229 + }, 230 + "name": { 231 + "name": "name", 232 + "type": "text", 233 + "primaryKey": false, 234 + "notNull": true, 235 + "autoincrement": false 236 + }, 237 + "description": { 238 + "name": "description", 239 + "type": "text", 240 + "primaryKey": false, 241 + "notNull": false, 242 + "autoincrement": false 243 + }, 244 + "color": { 245 + "name": "color", 246 + "type": "text", 247 + "primaryKey": false, 248 + "notNull": true, 249 + "autoincrement": false 250 + }, 251 + "position": { 252 + "name": "position", 253 + "type": "integer", 254 + "primaryKey": false, 255 + "notNull": true, 256 + "autoincrement": false, 257 + "default": 0 258 + }, 259 + "created_at": { 260 + "name": "created_at", 261 + "type": "text", 262 + "primaryKey": false, 263 + "notNull": true, 264 + "autoincrement": false, 265 + "default": "(datetime('now'))" 266 + } 267 + }, 268 + "indexes": { 269 + "idx_sphere_labels_sphere_name": { 270 + "name": "idx_sphere_labels_sphere_name", 271 + "columns": [ 272 + "sphere_id", 273 + "name" 274 + ], 275 + "isUnique": true 276 + }, 277 + "idx_sphere_labels_sphere_position": { 278 + "name": "idx_sphere_labels_sphere_position", 279 + "columns": [ 280 + "sphere_id", 281 + "position" 282 + ], 283 + "isUnique": false 284 + } 285 + }, 286 + "foreignKeys": { 287 + "sphere_labels_sphere_id_spheres_id_fk": { 288 + "name": "sphere_labels_sphere_id_spheres_id_fk", 289 + "tableFrom": "sphere_labels", 290 + "tableTo": "spheres", 291 + "columnsFrom": [ 292 + "sphere_id" 293 + ], 294 + "columnsTo": [ 295 + "id" 296 + ], 297 + "onDelete": "no action", 298 + "onUpdate": "no action" 299 + } 300 + }, 301 + "compositePrimaryKeys": {}, 302 + "uniqueConstraints": {}, 303 + "checkConstraints": {} 304 + }, 305 + "sphere_members": { 306 + "name": "sphere_members", 307 + "columns": { 308 + "sphere_id": { 309 + "name": "sphere_id", 310 + "type": "text", 311 + "primaryKey": false, 312 + "notNull": true, 313 + "autoincrement": false 314 + }, 315 + "did": { 316 + "name": "did", 317 + "type": "text", 318 + "primaryKey": false, 319 + "notNull": true, 320 + "autoincrement": false 321 + }, 322 + "role": { 323 + "name": "role", 324 + "type": "text", 325 + "primaryKey": false, 326 + "notNull": true, 327 + "autoincrement": false, 328 + "default": "'member'" 329 + }, 330 + "status": { 331 + "name": "status", 332 + "type": "text", 333 + "primaryKey": false, 334 + "notNull": true, 335 + "autoincrement": false, 336 + "default": "'invited'" 337 + }, 338 + "invited_by": { 339 + "name": "invited_by", 340 + "type": "text", 341 + "primaryKey": false, 342 + "notNull": false, 343 + "autoincrement": false 344 + }, 345 + "pds_uri": { 346 + "name": "pds_uri", 347 + "type": "text", 348 + "primaryKey": false, 349 + "notNull": false, 350 + "autoincrement": false 351 + }, 352 + "approval_pds_uri": { 353 + "name": "approval_pds_uri", 354 + "type": "text", 355 + "primaryKey": false, 356 + "notNull": false, 357 + "autoincrement": false 358 + }, 359 + "created_at": { 360 + "name": "created_at", 361 + "type": "text", 362 + "primaryKey": false, 363 + "notNull": true, 364 + "autoincrement": false, 365 + "default": "(datetime('now'))" 366 + } 367 + }, 368 + "indexes": { 369 + "idx_sphere_members_did": { 370 + "name": "idx_sphere_members_did", 371 + "columns": [ 372 + "did" 373 + ], 374 + "isUnique": false 375 + } 376 + }, 377 + "foreignKeys": { 378 + "sphere_members_sphere_id_spheres_id_fk": { 379 + "name": "sphere_members_sphere_id_spheres_id_fk", 380 + "tableFrom": "sphere_members", 381 + "tableTo": "spheres", 382 + "columnsFrom": [ 383 + "sphere_id" 384 + ], 385 + "columnsTo": [ 386 + "id" 387 + ], 388 + "onDelete": "no action", 389 + "onUpdate": "no action" 390 + } 391 + }, 392 + "compositePrimaryKeys": { 393 + "sphere_members_sphere_id_did_pk": { 394 + "columns": [ 395 + "sphere_id", 396 + "did" 397 + ], 398 + "name": "sphere_members_sphere_id_did_pk" 399 + } 400 + }, 401 + "uniqueConstraints": {}, 402 + "checkConstraints": {} 403 + }, 404 + "sphere_modules": { 405 + "name": "sphere_modules", 406 + "columns": { 407 + "sphere_id": { 408 + "name": "sphere_id", 409 + "type": "text", 410 + "primaryKey": false, 411 + "notNull": true, 412 + "autoincrement": false 413 + }, 414 + "module_name": { 415 + "name": "module_name", 416 + "type": "text", 417 + "primaryKey": false, 418 + "notNull": true, 419 + "autoincrement": false 420 + }, 421 + "enabled_at": { 422 + "name": "enabled_at", 423 + "type": "text", 424 + "primaryKey": false, 425 + "notNull": true, 426 + "autoincrement": false, 427 + "default": "(datetime('now'))" 428 + } 429 + }, 430 + "indexes": {}, 431 + "foreignKeys": { 432 + "sphere_modules_sphere_id_spheres_id_fk": { 433 + "name": "sphere_modules_sphere_id_spheres_id_fk", 434 + "tableFrom": "sphere_modules", 435 + "tableTo": "spheres", 436 + "columnsFrom": [ 437 + "sphere_id" 438 + ], 439 + "columnsTo": [ 440 + "id" 441 + ], 442 + "onDelete": "no action", 443 + "onUpdate": "no action" 444 + } 445 + }, 446 + "compositePrimaryKeys": { 447 + "sphere_modules_sphere_id_module_name_pk": { 448 + "columns": [ 449 + "sphere_id", 450 + "module_name" 451 + ], 452 + "name": "sphere_modules_sphere_id_module_name_pk" 453 + } 454 + }, 455 + "uniqueConstraints": {}, 456 + "checkConstraints": {} 457 + }, 458 + "sphere_permissions": { 459 + "name": "sphere_permissions", 460 + "columns": { 461 + "sphere_id": { 462 + "name": "sphere_id", 463 + "type": "text", 464 + "primaryKey": false, 465 + "notNull": true, 466 + "autoincrement": false 467 + }, 468 + "action_key": { 469 + "name": "action_key", 470 + "type": "text", 471 + "primaryKey": false, 472 + "notNull": true, 473 + "autoincrement": false 474 + }, 475 + "min_role": { 476 + "name": "min_role", 477 + "type": "text", 478 + "primaryKey": false, 479 + "notNull": true, 480 + "autoincrement": false 481 + }, 482 + "updated_at": { 483 + "name": "updated_at", 484 + "type": "text", 485 + "primaryKey": false, 486 + "notNull": true, 487 + "autoincrement": false, 488 + "default": "(datetime('now'))" 489 + } 490 + }, 491 + "indexes": {}, 492 + "foreignKeys": { 493 + "sphere_permissions_sphere_id_spheres_id_fk": { 494 + "name": "sphere_permissions_sphere_id_spheres_id_fk", 495 + "tableFrom": "sphere_permissions", 496 + "tableTo": "spheres", 497 + "columnsFrom": [ 498 + "sphere_id" 499 + ], 500 + "columnsTo": [ 501 + "id" 502 + ], 503 + "onDelete": "no action", 504 + "onUpdate": "no action" 505 + } 506 + }, 507 + "compositePrimaryKeys": { 508 + "sphere_permissions_sphere_id_action_key_pk": { 509 + "columns": [ 510 + "sphere_id", 511 + "action_key" 512 + ], 513 + "name": "sphere_permissions_sphere_id_action_key_pk" 514 + } 515 + }, 516 + "uniqueConstraints": {}, 517 + "checkConstraints": {} 518 + }, 519 + "spheres": { 520 + "name": "spheres", 521 + "columns": { 522 + "id": { 523 + "name": "id", 524 + "type": "text", 525 + "primaryKey": true, 526 + "notNull": true, 527 + "autoincrement": false 528 + }, 529 + "handle": { 530 + "name": "handle", 531 + "type": "text", 532 + "primaryKey": false, 533 + "notNull": true, 534 + "autoincrement": false 535 + }, 536 + "name": { 537 + "name": "name", 538 + "type": "text", 539 + "primaryKey": false, 540 + "notNull": true, 541 + "autoincrement": false 542 + }, 543 + "description": { 544 + "name": "description", 545 + "type": "text", 546 + "primaryKey": false, 547 + "notNull": false, 548 + "autoincrement": false 549 + }, 550 + "visibility": { 551 + "name": "visibility", 552 + "type": "text", 553 + "primaryKey": false, 554 + "notNull": true, 555 + "autoincrement": false, 556 + "default": "'public'" 557 + }, 558 + "owner_did": { 559 + "name": "owner_did", 560 + "type": "text", 561 + "primaryKey": false, 562 + "notNull": true, 563 + "autoincrement": false 564 + }, 565 + "pds_uri": { 566 + "name": "pds_uri", 567 + "type": "text", 568 + "primaryKey": false, 569 + "notNull": false, 570 + "autoincrement": false 571 + }, 572 + "created_at": { 573 + "name": "created_at", 574 + "type": "text", 575 + "primaryKey": false, 576 + "notNull": true, 577 + "autoincrement": false, 578 + "default": "(datetime('now'))" 579 + }, 580 + "updated_at": { 581 + "name": "updated_at", 582 + "type": "text", 583 + "primaryKey": false, 584 + "notNull": true, 585 + "autoincrement": false, 586 + "default": "(datetime('now'))" 587 + } 588 + }, 589 + "indexes": { 590 + "spheres_handle_unique": { 591 + "name": "spheres_handle_unique", 592 + "columns": [ 593 + "handle" 594 + ], 595 + "isUnique": true 596 + } 597 + }, 598 + "foreignKeys": {}, 599 + "compositePrimaryKeys": {}, 600 + "uniqueConstraints": {}, 601 + "checkConstraints": {} 602 + }, 603 + "feature_request_comment_votes": { 604 + "name": "feature_request_comment_votes", 605 + "columns": { 606 + "comment_id": { 607 + "name": "comment_id", 608 + "type": "text", 609 + "primaryKey": false, 610 + "notNull": true, 611 + "autoincrement": false 612 + }, 613 + "author_did": { 614 + "name": "author_did", 615 + "type": "text", 616 + "primaryKey": false, 617 + "notNull": true, 618 + "autoincrement": false 619 + }, 620 + "pds_uri": { 621 + "name": "pds_uri", 622 + "type": "text", 623 + "primaryKey": false, 624 + "notNull": false, 625 + "autoincrement": false 626 + }, 627 + "created_at": { 628 + "name": "created_at", 629 + "type": "text", 630 + "primaryKey": false, 631 + "notNull": true, 632 + "autoincrement": false, 633 + "default": "(datetime('now'))" 634 + } 635 + }, 636 + "indexes": { 637 + "idx_feature_request_comment_votes_comment": { 638 + "name": "idx_feature_request_comment_votes_comment", 639 + "columns": [ 640 + "comment_id" 641 + ], 642 + "isUnique": false 643 + } 644 + }, 645 + "foreignKeys": { 646 + "feature_request_comment_votes_comment_id_feature_request_comments_id_fk": { 647 + "name": "feature_request_comment_votes_comment_id_feature_request_comments_id_fk", 648 + "tableFrom": "feature_request_comment_votes", 649 + "tableTo": "feature_request_comments", 650 + "columnsFrom": [ 651 + "comment_id" 652 + ], 653 + "columnsTo": [ 654 + "id" 655 + ], 656 + "onDelete": "no action", 657 + "onUpdate": "no action" 658 + } 659 + }, 660 + "compositePrimaryKeys": { 661 + "feature_request_comment_votes_comment_id_author_did_pk": { 662 + "columns": [ 663 + "comment_id", 664 + "author_did" 665 + ], 666 + "name": "feature_request_comment_votes_comment_id_author_did_pk" 667 + } 668 + }, 669 + "uniqueConstraints": {}, 670 + "checkConstraints": {} 671 + }, 672 + "feature_request_comments": { 673 + "name": "feature_request_comments", 674 + "columns": { 675 + "id": { 676 + "name": "id", 677 + "type": "text", 678 + "primaryKey": true, 679 + "notNull": true, 680 + "autoincrement": false 681 + }, 682 + "request_id": { 683 + "name": "request_id", 684 + "type": "text", 685 + "primaryKey": false, 686 + "notNull": true, 687 + "autoincrement": false 688 + }, 689 + "author_did": { 690 + "name": "author_did", 691 + "type": "text", 692 + "primaryKey": false, 693 + "notNull": true, 694 + "autoincrement": false 695 + }, 696 + "content": { 697 + "name": "content", 698 + "type": "text", 699 + "primaryKey": false, 700 + "notNull": true, 701 + "autoincrement": false 702 + }, 703 + "pds_uri": { 704 + "name": "pds_uri", 705 + "type": "text", 706 + "primaryKey": false, 707 + "notNull": false, 708 + "autoincrement": false 709 + }, 710 + "updated_at": { 711 + "name": "updated_at", 712 + "type": "text", 713 + "primaryKey": false, 714 + "notNull": true, 715 + "autoincrement": false, 716 + "default": "(datetime('now'))" 717 + }, 718 + "hidden_at": { 719 + "name": "hidden_at", 720 + "type": "text", 721 + "primaryKey": false, 722 + "notNull": false, 723 + "autoincrement": false 724 + }, 725 + "moderated_by": { 726 + "name": "moderated_by", 727 + "type": "text", 728 + "primaryKey": false, 729 + "notNull": false, 730 + "autoincrement": false 731 + } 732 + }, 733 + "indexes": { 734 + "idx_feature_request_comments_request": { 735 + "name": "idx_feature_request_comments_request", 736 + "columns": [ 737 + "request_id" 738 + ], 739 + "isUnique": false 740 + }, 741 + "idx_feature_request_comments_author_request": { 742 + "name": "idx_feature_request_comments_author_request", 743 + "columns": [ 744 + "author_did", 745 + "request_id" 746 + ], 747 + "isUnique": false 748 + } 749 + }, 750 + "foreignKeys": { 751 + "feature_request_comments_request_id_feature_requests_id_fk": { 752 + "name": "feature_request_comments_request_id_feature_requests_id_fk", 753 + "tableFrom": "feature_request_comments", 754 + "tableTo": "feature_requests", 755 + "columnsFrom": [ 756 + "request_id" 757 + ], 758 + "columnsTo": [ 759 + "id" 760 + ], 761 + "onDelete": "no action", 762 + "onUpdate": "no action" 763 + } 764 + }, 765 + "compositePrimaryKeys": {}, 766 + "uniqueConstraints": {}, 767 + "checkConstraints": {} 768 + }, 769 + "feature_request_statuses": { 770 + "name": "feature_request_statuses", 771 + "columns": { 772 + "id": { 773 + "name": "id", 774 + "type": "text", 775 + "primaryKey": true, 776 + "notNull": true, 777 + "autoincrement": false 778 + }, 779 + "request_id": { 780 + "name": "request_id", 781 + "type": "text", 782 + "primaryKey": false, 783 + "notNull": true, 784 + "autoincrement": false 785 + }, 786 + "author_did": { 787 + "name": "author_did", 788 + "type": "text", 789 + "primaryKey": false, 790 + "notNull": true, 791 + "autoincrement": false 792 + }, 793 + "status": { 794 + "name": "status", 795 + "type": "text", 796 + "primaryKey": false, 797 + "notNull": true, 798 + "autoincrement": false 799 + }, 800 + "pds_uri": { 801 + "name": "pds_uri", 802 + "type": "text", 803 + "primaryKey": false, 804 + "notNull": false, 805 + "autoincrement": false 806 + } 807 + }, 808 + "indexes": { 809 + "idx_feature_request_statuses_request": { 810 + "name": "idx_feature_request_statuses_request", 811 + "columns": [ 812 + "request_id" 813 + ], 814 + "isUnique": false 815 + } 816 + }, 817 + "foreignKeys": { 818 + "feature_request_statuses_request_id_feature_requests_id_fk": { 819 + "name": "feature_request_statuses_request_id_feature_requests_id_fk", 820 + "tableFrom": "feature_request_statuses", 821 + "tableTo": "feature_requests", 822 + "columnsFrom": [ 823 + "request_id" 824 + ], 825 + "columnsTo": [ 826 + "id" 827 + ], 828 + "onDelete": "no action", 829 + "onUpdate": "no action" 830 + } 831 + }, 832 + "compositePrimaryKeys": {}, 833 + "uniqueConstraints": {}, 834 + "checkConstraints": {} 835 + }, 836 + "feature_request_votes": { 837 + "name": "feature_request_votes", 838 + "columns": { 839 + "request_id": { 840 + "name": "request_id", 841 + "type": "text", 842 + "primaryKey": false, 843 + "notNull": true, 844 + "autoincrement": false 845 + }, 846 + "author_did": { 847 + "name": "author_did", 848 + "type": "text", 849 + "primaryKey": false, 850 + "notNull": true, 851 + "autoincrement": false 852 + }, 853 + "pds_uri": { 854 + "name": "pds_uri", 855 + "type": "text", 856 + "primaryKey": false, 857 + "notNull": false, 858 + "autoincrement": false 859 + }, 860 + "created_at": { 861 + "name": "created_at", 862 + "type": "text", 863 + "primaryKey": false, 864 + "notNull": true, 865 + "autoincrement": false, 866 + "default": "(datetime('now'))" 867 + } 868 + }, 869 + "indexes": { 870 + "idx_feature_request_votes_request": { 871 + "name": "idx_feature_request_votes_request", 872 + "columns": [ 873 + "request_id" 874 + ], 875 + "isUnique": false 876 + } 877 + }, 878 + "foreignKeys": { 879 + "feature_request_votes_request_id_feature_requests_id_fk": { 880 + "name": "feature_request_votes_request_id_feature_requests_id_fk", 881 + "tableFrom": "feature_request_votes", 882 + "tableTo": "feature_requests", 883 + "columnsFrom": [ 884 + "request_id" 885 + ], 886 + "columnsTo": [ 887 + "id" 888 + ], 889 + "onDelete": "no action", 890 + "onUpdate": "no action" 891 + } 892 + }, 893 + "compositePrimaryKeys": { 894 + "feature_request_votes_request_id_author_did_pk": { 895 + "columns": [ 896 + "request_id", 897 + "author_did" 898 + ], 899 + "name": "feature_request_votes_request_id_author_did_pk" 900 + } 901 + }, 902 + "uniqueConstraints": {}, 903 + "checkConstraints": {} 904 + }, 905 + "feature_requests": { 906 + "name": "feature_requests", 907 + "columns": { 908 + "id": { 909 + "name": "id", 910 + "type": "text", 911 + "primaryKey": true, 912 + "notNull": true, 913 + "autoincrement": false 914 + }, 915 + "sphere_id": { 916 + "name": "sphere_id", 917 + "type": "text", 918 + "primaryKey": false, 919 + "notNull": true, 920 + "autoincrement": false 921 + }, 922 + "number": { 923 + "name": "number", 924 + "type": "integer", 925 + "primaryKey": false, 926 + "notNull": true, 927 + "autoincrement": false 928 + }, 929 + "author_did": { 930 + "name": "author_did", 931 + "type": "text", 932 + "primaryKey": false, 933 + "notNull": true, 934 + "autoincrement": false 935 + }, 936 + "title": { 937 + "name": "title", 938 + "type": "text", 939 + "primaryKey": false, 940 + "notNull": true, 941 + "autoincrement": false 942 + }, 943 + "description": { 944 + "name": "description", 945 + "type": "text", 946 + "primaryKey": false, 947 + "notNull": true, 948 + "autoincrement": false 949 + }, 950 + "status": { 951 + "name": "status", 952 + "type": "text", 953 + "primaryKey": false, 954 + "notNull": true, 955 + "autoincrement": false, 956 + "default": "'requested'" 957 + }, 958 + "duplicate_of_id": { 959 + "name": "duplicate_of_id", 960 + "type": "text", 961 + "primaryKey": false, 962 + "notNull": false, 963 + "autoincrement": false 964 + }, 965 + "pds_uri": { 966 + "name": "pds_uri", 967 + "type": "text", 968 + "primaryKey": false, 969 + "notNull": false, 970 + "autoincrement": false 971 + }, 972 + "hidden_at": { 973 + "name": "hidden_at", 974 + "type": "text", 975 + "primaryKey": false, 976 + "notNull": false, 977 + "autoincrement": false 978 + }, 979 + "moderated_by": { 980 + "name": "moderated_by", 981 + "type": "text", 982 + "primaryKey": false, 983 + "notNull": false, 984 + "autoincrement": false 985 + }, 986 + "label_tid": { 987 + "name": "label_tid", 988 + "type": "text", 989 + "primaryKey": false, 990 + "notNull": false, 991 + "autoincrement": false 992 + }, 993 + "updated_at": { 994 + "name": "updated_at", 995 + "type": "text", 996 + "primaryKey": false, 997 + "notNull": true, 998 + "autoincrement": false, 999 + "default": "(datetime('now'))" 1000 + } 1001 + }, 1002 + "indexes": { 1003 + "idx_feature_requests_sphere_number": { 1004 + "name": "idx_feature_requests_sphere_number", 1005 + "columns": [ 1006 + "sphere_id", 1007 + "number" 1008 + ], 1009 + "isUnique": true 1010 + }, 1011 + "idx_feature_requests_sphere": { 1012 + "name": "idx_feature_requests_sphere", 1013 + "columns": [ 1014 + "sphere_id" 1015 + ], 1016 + "isUnique": false 1017 + }, 1018 + "idx_feature_requests_status": { 1019 + "name": "idx_feature_requests_status", 1020 + "columns": [ 1021 + "status" 1022 + ], 1023 + "isUnique": false 1024 + } 1025 + }, 1026 + "foreignKeys": { 1027 + "feature_requests_sphere_id_spheres_id_fk": { 1028 + "name": "feature_requests_sphere_id_spheres_id_fk", 1029 + "tableFrom": "feature_requests", 1030 + "tableTo": "spheres", 1031 + "columnsFrom": [ 1032 + "sphere_id" 1033 + ], 1034 + "columnsTo": [ 1035 + "id" 1036 + ], 1037 + "onDelete": "no action", 1038 + "onUpdate": "no action" 1039 + } 1040 + }, 1041 + "compositePrimaryKeys": {}, 1042 + "uniqueConstraints": {}, 1043 + "checkConstraints": {} 1044 + }, 1045 + "feed_posts": { 1046 + "name": "feed_posts", 1047 + "columns": { 1048 + "id": { 1049 + "name": "id", 1050 + "type": "text", 1051 + "primaryKey": true, 1052 + "notNull": true, 1053 + "autoincrement": false 1054 + }, 1055 + "author_did": { 1056 + "name": "author_did", 1057 + "type": "text", 1058 + "primaryKey": false, 1059 + "notNull": true, 1060 + "autoincrement": false 1061 + }, 1062 + "content": { 1063 + "name": "content", 1064 + "type": "text", 1065 + "primaryKey": false, 1066 + "notNull": true, 1067 + "autoincrement": false 1068 + }, 1069 + "parent_id": { 1070 + "name": "parent_id", 1071 + "type": "text", 1072 + "primaryKey": false, 1073 + "notNull": false, 1074 + "autoincrement": false 1075 + }, 1076 + "pds_uri": { 1077 + "name": "pds_uri", 1078 + "type": "text", 1079 + "primaryKey": false, 1080 + "notNull": false, 1081 + "autoincrement": false 1082 + }, 1083 + "updated_at": { 1084 + "name": "updated_at", 1085 + "type": "text", 1086 + "primaryKey": false, 1087 + "notNull": true, 1088 + "autoincrement": false, 1089 + "default": "(datetime('now'))" 1090 + } 1091 + }, 1092 + "indexes": { 1093 + "idx_feed_posts_parent": { 1094 + "name": "idx_feed_posts_parent", 1095 + "columns": [ 1096 + "parent_id" 1097 + ], 1098 + "isUnique": false 1099 + } 1100 + }, 1101 + "foreignKeys": {}, 1102 + "compositePrimaryKeys": {}, 1103 + "uniqueConstraints": {}, 1104 + "checkConstraints": {} 1105 + }, 1106 + "kanban_columns": { 1107 + "name": "kanban_columns", 1108 + "columns": { 1109 + "id": { 1110 + "name": "id", 1111 + "type": "text", 1112 + "primaryKey": true, 1113 + "notNull": true, 1114 + "autoincrement": false 1115 + }, 1116 + "sphere_id": { 1117 + "name": "sphere_id", 1118 + "type": "text", 1119 + "primaryKey": false, 1120 + "notNull": true, 1121 + "autoincrement": false 1122 + }, 1123 + "slug": { 1124 + "name": "slug", 1125 + "type": "text", 1126 + "primaryKey": false, 1127 + "notNull": true, 1128 + "autoincrement": false 1129 + }, 1130 + "label": { 1131 + "name": "label", 1132 + "type": "text", 1133 + "primaryKey": false, 1134 + "notNull": true, 1135 + "autoincrement": false 1136 + }, 1137 + "position": { 1138 + "name": "position", 1139 + "type": "integer", 1140 + "primaryKey": false, 1141 + "notNull": true, 1142 + "autoincrement": false 1143 + }, 1144 + "created_at": { 1145 + "name": "created_at", 1146 + "type": "text", 1147 + "primaryKey": false, 1148 + "notNull": true, 1149 + "autoincrement": false, 1150 + "default": "(datetime('now'))" 1151 + } 1152 + }, 1153 + "indexes": { 1154 + "idx_kanban_columns_sphere_slug": { 1155 + "name": "idx_kanban_columns_sphere_slug", 1156 + "columns": [ 1157 + "sphere_id", 1158 + "slug" 1159 + ], 1160 + "isUnique": true 1161 + }, 1162 + "idx_kanban_columns_sphere_position": { 1163 + "name": "idx_kanban_columns_sphere_position", 1164 + "columns": [ 1165 + "sphere_id", 1166 + "position" 1167 + ], 1168 + "isUnique": false 1169 + } 1170 + }, 1171 + "foreignKeys": { 1172 + "kanban_columns_sphere_id_spheres_id_fk": { 1173 + "name": "kanban_columns_sphere_id_spheres_id_fk", 1174 + "tableFrom": "kanban_columns", 1175 + "tableTo": "spheres", 1176 + "columnsFrom": [ 1177 + "sphere_id" 1178 + ], 1179 + "columnsTo": [ 1180 + "id" 1181 + ], 1182 + "onDelete": "no action", 1183 + "onUpdate": "no action" 1184 + } 1185 + }, 1186 + "compositePrimaryKeys": {}, 1187 + "uniqueConstraints": {}, 1188 + "checkConstraints": {} 1189 + }, 1190 + "kanban_task_comments": { 1191 + "name": "kanban_task_comments", 1192 + "columns": { 1193 + "id": { 1194 + "name": "id", 1195 + "type": "text", 1196 + "primaryKey": true, 1197 + "notNull": true, 1198 + "autoincrement": false 1199 + }, 1200 + "task_id": { 1201 + "name": "task_id", 1202 + "type": "text", 1203 + "primaryKey": false, 1204 + "notNull": true, 1205 + "autoincrement": false 1206 + }, 1207 + "author_did": { 1208 + "name": "author_did", 1209 + "type": "text", 1210 + "primaryKey": false, 1211 + "notNull": true, 1212 + "autoincrement": false 1213 + }, 1214 + "content": { 1215 + "name": "content", 1216 + "type": "text", 1217 + "primaryKey": false, 1218 + "notNull": true, 1219 + "autoincrement": false 1220 + }, 1221 + "pds_uri": { 1222 + "name": "pds_uri", 1223 + "type": "text", 1224 + "primaryKey": false, 1225 + "notNull": false, 1226 + "autoincrement": false 1227 + }, 1228 + "updated_at": { 1229 + "name": "updated_at", 1230 + "type": "text", 1231 + "primaryKey": false, 1232 + "notNull": true, 1233 + "autoincrement": false, 1234 + "default": "(datetime('now'))" 1235 + }, 1236 + "hidden_at": { 1237 + "name": "hidden_at", 1238 + "type": "text", 1239 + "primaryKey": false, 1240 + "notNull": false, 1241 + "autoincrement": false 1242 + }, 1243 + "moderated_by": { 1244 + "name": "moderated_by", 1245 + "type": "text", 1246 + "primaryKey": false, 1247 + "notNull": false, 1248 + "autoincrement": false 1249 + } 1250 + }, 1251 + "indexes": { 1252 + "idx_kanban_task_comments_task": { 1253 + "name": "idx_kanban_task_comments_task", 1254 + "columns": [ 1255 + "task_id" 1256 + ], 1257 + "isUnique": false 1258 + }, 1259 + "idx_kanban_task_comments_author_task": { 1260 + "name": "idx_kanban_task_comments_author_task", 1261 + "columns": [ 1262 + "author_did", 1263 + "task_id" 1264 + ], 1265 + "isUnique": false 1266 + } 1267 + }, 1268 + "foreignKeys": { 1269 + "kanban_task_comments_task_id_kanban_tasks_id_fk": { 1270 + "name": "kanban_task_comments_task_id_kanban_tasks_id_fk", 1271 + "tableFrom": "kanban_task_comments", 1272 + "tableTo": "kanban_tasks", 1273 + "columnsFrom": [ 1274 + "task_id" 1275 + ], 1276 + "columnsTo": [ 1277 + "id" 1278 + ], 1279 + "onDelete": "no action", 1280 + "onUpdate": "no action" 1281 + } 1282 + }, 1283 + "compositePrimaryKeys": {}, 1284 + "uniqueConstraints": {}, 1285 + "checkConstraints": {} 1286 + }, 1287 + "kanban_task_status_changes": { 1288 + "name": "kanban_task_status_changes", 1289 + "columns": { 1290 + "id": { 1291 + "name": "id", 1292 + "type": "text", 1293 + "primaryKey": true, 1294 + "notNull": true, 1295 + "autoincrement": false 1296 + }, 1297 + "task_id": { 1298 + "name": "task_id", 1299 + "type": "text", 1300 + "primaryKey": false, 1301 + "notNull": true, 1302 + "autoincrement": false 1303 + }, 1304 + "author_did": { 1305 + "name": "author_did", 1306 + "type": "text", 1307 + "primaryKey": false, 1308 + "notNull": true, 1309 + "autoincrement": false 1310 + }, 1311 + "status": { 1312 + "name": "status", 1313 + "type": "text", 1314 + "primaryKey": false, 1315 + "notNull": true, 1316 + "autoincrement": false 1317 + }, 1318 + "pds_uri": { 1319 + "name": "pds_uri", 1320 + "type": "text", 1321 + "primaryKey": false, 1322 + "notNull": false, 1323 + "autoincrement": false 1324 + } 1325 + }, 1326 + "indexes": { 1327 + "idx_kanban_task_status_changes_task": { 1328 + "name": "idx_kanban_task_status_changes_task", 1329 + "columns": [ 1330 + "task_id" 1331 + ], 1332 + "isUnique": false 1333 + } 1334 + }, 1335 + "foreignKeys": { 1336 + "kanban_task_status_changes_task_id_kanban_tasks_id_fk": { 1337 + "name": "kanban_task_status_changes_task_id_kanban_tasks_id_fk", 1338 + "tableFrom": "kanban_task_status_changes", 1339 + "tableTo": "kanban_tasks", 1340 + "columnsFrom": [ 1341 + "task_id" 1342 + ], 1343 + "columnsTo": [ 1344 + "id" 1345 + ], 1346 + "onDelete": "no action", 1347 + "onUpdate": "no action" 1348 + } 1349 + }, 1350 + "compositePrimaryKeys": {}, 1351 + "uniqueConstraints": {}, 1352 + "checkConstraints": {} 1353 + }, 1354 + "kanban_tasks": { 1355 + "name": "kanban_tasks", 1356 + "columns": { 1357 + "id": { 1358 + "name": "id", 1359 + "type": "text", 1360 + "primaryKey": true, 1361 + "notNull": true, 1362 + "autoincrement": false 1363 + }, 1364 + "sphere_id": { 1365 + "name": "sphere_id", 1366 + "type": "text", 1367 + "primaryKey": false, 1368 + "notNull": true, 1369 + "autoincrement": false 1370 + }, 1371 + "number": { 1372 + "name": "number", 1373 + "type": "integer", 1374 + "primaryKey": false, 1375 + "notNull": true, 1376 + "autoincrement": false 1377 + }, 1378 + "author_did": { 1379 + "name": "author_did", 1380 + "type": "text", 1381 + "primaryKey": false, 1382 + "notNull": true, 1383 + "autoincrement": false 1384 + }, 1385 + "title": { 1386 + "name": "title", 1387 + "type": "text", 1388 + "primaryKey": false, 1389 + "notNull": true, 1390 + "autoincrement": false 1391 + }, 1392 + "description": { 1393 + "name": "description", 1394 + "type": "text", 1395 + "primaryKey": false, 1396 + "notNull": true, 1397 + "autoincrement": false, 1398 + "default": "''" 1399 + }, 1400 + "status": { 1401 + "name": "status", 1402 + "type": "text", 1403 + "primaryKey": false, 1404 + "notNull": true, 1405 + "autoincrement": false, 1406 + "default": "'backlog'" 1407 + }, 1408 + "position": { 1409 + "name": "position", 1410 + "type": "integer", 1411 + "primaryKey": false, 1412 + "notNull": true, 1413 + "autoincrement": false, 1414 + "default": 0 1415 + }, 1416 + "assignee_did": { 1417 + "name": "assignee_did", 1418 + "type": "text", 1419 + "primaryKey": false, 1420 + "notNull": false, 1421 + "autoincrement": false 1422 + }, 1423 + "pds_uri": { 1424 + "name": "pds_uri", 1425 + "type": "text", 1426 + "primaryKey": false, 1427 + "notNull": false, 1428 + "autoincrement": false 1429 + }, 1430 + "hidden_at": { 1431 + "name": "hidden_at", 1432 + "type": "text", 1433 + "primaryKey": false, 1434 + "notNull": false, 1435 + "autoincrement": false 1436 + }, 1437 + "moderated_by": { 1438 + "name": "moderated_by", 1439 + "type": "text", 1440 + "primaryKey": false, 1441 + "notNull": false, 1442 + "autoincrement": false 1443 + }, 1444 + "label_tid": { 1445 + "name": "label_tid", 1446 + "type": "text", 1447 + "primaryKey": false, 1448 + "notNull": false, 1449 + "autoincrement": false 1450 + }, 1451 + "updated_at": { 1452 + "name": "updated_at", 1453 + "type": "text", 1454 + "primaryKey": false, 1455 + "notNull": true, 1456 + "autoincrement": false, 1457 + "default": "(datetime('now'))" 1458 + } 1459 + }, 1460 + "indexes": { 1461 + "idx_kanban_tasks_sphere_number": { 1462 + "name": "idx_kanban_tasks_sphere_number", 1463 + "columns": [ 1464 + "sphere_id", 1465 + "number" 1466 + ], 1467 + "isUnique": true 1468 + }, 1469 + "idx_kanban_tasks_sphere": { 1470 + "name": "idx_kanban_tasks_sphere", 1471 + "columns": [ 1472 + "sphere_id" 1473 + ], 1474 + "isUnique": false 1475 + }, 1476 + "idx_kanban_tasks_status": { 1477 + "name": "idx_kanban_tasks_status", 1478 + "columns": [ 1479 + "status" 1480 + ], 1481 + "isUnique": false 1482 + }, 1483 + "idx_kanban_tasks_sphere_status_position": { 1484 + "name": "idx_kanban_tasks_sphere_status_position", 1485 + "columns": [ 1486 + "sphere_id", 1487 + "status", 1488 + "position" 1489 + ], 1490 + "isUnique": false 1491 + } 1492 + }, 1493 + "foreignKeys": { 1494 + "kanban_tasks_sphere_id_spheres_id_fk": { 1495 + "name": "kanban_tasks_sphere_id_spheres_id_fk", 1496 + "tableFrom": "kanban_tasks", 1497 + "tableTo": "spheres", 1498 + "columnsFrom": [ 1499 + "sphere_id" 1500 + ], 1501 + "columnsTo": [ 1502 + "id" 1503 + ], 1504 + "onDelete": "no action", 1505 + "onUpdate": "no action" 1506 + } 1507 + }, 1508 + "compositePrimaryKeys": {}, 1509 + "uniqueConstraints": {}, 1510 + "checkConstraints": {} 1511 + } 1512 + }, 1513 + "views": {}, 1514 + "enums": {}, 1515 + "_meta": { 1516 + "schemas": {}, 1517 + "tables": {}, 1518 + "columns": {} 1519 + }, 1520 + "internal": { 1521 + "indexes": {} 1522 + } 1523 + }
+8 -1
drizzle/meta/_journal.json
··· 43 43 "when": 1776250350625, 44 44 "tag": "0005_volatile_mystique", 45 45 "breakpoints": true 46 + }, 47 + { 48 + "idx": 6, 49 + "version": "6", 50 + "when": 1776417674886, 51 + "tag": "0006_melodic_menace", 52 + "breakpoints": true 46 53 } 47 54 ] 48 - } 55 + }
+7 -20
packages/app/e2e/seed.ts
··· 81 81 number: 1, 82 82 title: "Add dark mode support", 83 83 description: "It would be great to have a dark mode option for better readability at night.", 84 - category: "enhancement", 85 84 status: "approved", 86 85 authorDid: MEMBER_DID, 87 86 }, ··· 90 89 number: 2, 91 90 title: "Export data as CSV", 92 91 description: "Allow users to export their data in CSV format for analysis.", 93 - category: "general", 94 92 status: "requested", 95 93 authorDid: OWNER_DID, 96 94 }, ··· 99 97 number: 3, 100 98 title: "Mobile app", 101 99 description: "A native mobile application would improve the user experience significantly.", 102 - category: "general", 103 100 status: "requested", 104 101 authorDid: MEMBER_DID, 105 102 }, ··· 108 105 number: 4, 109 106 title: "Keyboard shortcuts", 110 107 description: "Add keyboard shortcuts for common actions like voting and navigation.", 111 - category: "enhancement", 112 108 status: "done", 113 109 authorDid: OWNER_DID, 114 110 }, ··· 117 113 number: 5, 118 114 title: "Windows phone support", 119 115 description: "Please add support for Windows Phone platform.", 120 - category: "general", 121 116 status: "not-planned", 122 117 authorDid: MEMBER_DID, 123 118 }, ··· 125 120 126 121 for (const fr of featureRequests) { 127 122 db.run( 128 - `INSERT INTO feature_requests (id, sphere_id, number, title, description, category, status, author_did) 129 - VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, 130 - [fr.id, SPHERE_ID, fr.number, fr.title, fr.description, fr.category, fr.status, fr.authorDid], 123 + `INSERT INTO feature_requests (id, sphere_id, number, title, description, status, author_did) 124 + VALUES (?, ?, ?, ?, ?, ?, ?)`, 125 + [fr.id, SPHERE_ID, fr.number, fr.title, fr.description, fr.status, fr.authorDid], 131 126 ); 132 127 } 133 128 ··· 194 189 number: 1, 195 190 title: "Alpha dark mode", 196 191 description: "Dark mode for Alpha sphere.", 197 - category: "enhancement", 198 192 status: "approved", 199 193 authorDid: OWNER_DID, 200 194 }, ··· 203 197 number: 2, 204 198 title: "Alpha CSV export", 205 199 description: "CSV export for Alpha sphere.", 206 - category: "general", 207 200 status: "requested", 208 201 authorDid: MEMBER_DID, 209 202 }, ··· 212 205 number: 3, 213 206 title: "Alpha done feature", 214 207 description: "A completed feature.", 215 - category: "general", 216 208 status: "done", 217 209 authorDid: OWNER_DID, 218 210 }, ··· 221 213 number: 4, 222 214 title: "Alpha rejected idea", 223 215 description: "A rejected feature.", 224 - category: "general", 225 216 status: "not-planned", 226 217 authorDid: MEMBER_DID, 227 218 }, ··· 229 220 230 221 for (const fr of alphaRequests) { 231 222 db.run( 232 - `INSERT INTO feature_requests (id, sphere_id, number, title, description, category, status, author_did) 233 - VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, 223 + `INSERT INTO feature_requests (id, sphere_id, number, title, description, status, author_did) 224 + VALUES (?, ?, ?, ?, ?, ?, ?)`, 234 225 [ 235 226 fr.id, 236 227 "sphere-alpha", 237 228 fr.number, 238 229 fr.title, 239 230 fr.description, 240 - fr.category, 241 231 fr.status, 242 232 fr.authorDid, 243 233 ], ··· 280 270 number: 1, 281 271 title: "Beta mobile app", 282 272 description: "Mobile app for Beta sphere.", 283 - category: "general", 284 273 status: "requested", 285 274 authorDid: MEMBER_DID, 286 275 }, ··· 289 278 number: 2, 290 279 title: "Beta API access", 291 280 description: "Public API for Beta sphere.", 292 - category: "enhancement", 293 281 status: "approved", 294 282 authorDid: OWNER_DID, 295 283 }, ··· 297 285 298 286 for (const fr of betaRequests) { 299 287 db.run( 300 - `INSERT INTO feature_requests (id, sphere_id, number, title, description, category, status, author_did) 301 - VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, 288 + `INSERT INTO feature_requests (id, sphere_id, number, title, description, status, author_did) 289 + VALUES (?, ?, ?, ?, ?, ?, ?)`, 302 290 [ 303 291 fr.id, 304 292 "sphere-beta", 305 293 fr.number, 306 294 fr.title, 307 295 fr.description, 308 - fr.category, 309 296 fr.status, 310 297 fr.authorDid, 311 298 ],
-93
packages/core/src/db/migrate.ts
··· 4 4 5 5 const migrationsFolder = process.env.MIGRATIONS_PATH || "drizzle"; 6 6 7 - const categoryDefaults = [ 8 - { name: "General", slug: "general", color: "#6b7280", position: 0 }, 9 - { name: "Enhancement", slug: "enhancement", color: "#3b82f6", position: 1 }, 10 - { name: "Bug", slug: "bug", color: "#ef4444", position: 2 }, 11 - { name: "Integration", slug: "integration", color: "#8b5cf6", position: 3 }, 12 - { name: "UI / UX", slug: "ui-ux", color: "#f59e0b", position: 4 }, 13 - ] as const; 14 - 15 7 migrate(getDb(), { migrationsFolder }); 16 8 17 9 // Data migration: renumber feature requests and kanban tasks to use the 18 10 // shared sphere_entry_counter. Runs only once — skips if counter rows exist. 19 11 seedEntryCounters(); 20 - 21 - // Data migration: convert hardcoded feature request categories into 22 - // sphere_labels + entity_labels. Runs only once — skips if labels already exist. 23 - seedLabelsFromCategories(); 24 12 25 13 function seedEntryCounters() { 26 14 const dbPath = process.env.DATABASE_PATH || "exosphere.sqlite"; ··· 97 85 db.close(); 98 86 } 99 87 100 - function seedLabelsFromCategories() { 101 - const dbPath = process.env.DATABASE_PATH || "exosphere.sqlite"; 102 - const db = new Database(dbPath); 103 - 104 - // Check if the sphere_labels table exists 105 - const tableExists = db 106 - .query<{ name: string }, []>( 107 - "SELECT name FROM sqlite_master WHERE type='table' AND name='sphere_labels'", 108 - ) 109 - .get(); 110 - if (!tableExists) { 111 - db.close(); 112 - return; 113 - } 114 - 115 - // Skip if already seeded 116 - const existing = db.query<{ c: number }, []>("SELECT count(*) as c FROM sphere_labels").get(); 117 - if (existing && existing.c > 0) { 118 - db.close(); 119 - return; 120 - } 121 - 122 - // Check if feature_requests table exists (module may not be enabled) 123 - const frTableExists = db 124 - .query<{ name: string }, []>( 125 - "SELECT name FROM sqlite_master WHERE type='table' AND name='feature_requests'", 126 - ) 127 - .get(); 128 - if (!frTableExists) { 129 - db.close(); 130 - return; 131 - } 132 - 133 - // Find spheres that have feature requests 134 - const spheres = db 135 - .query<{ sphere_id: string }, []>("SELECT DISTINCT sphere_id FROM feature_requests") 136 - .all(); 137 - 138 - if (spheres.length === 0) { 139 - db.close(); 140 - return; 141 - } 142 - 143 - let labelCounter = 0; 144 - 145 - for (const { sphere_id } of spheres) { 146 - const tx = db.transaction(() => { 147 - // Create labels for this sphere 148 - const labelIds: Record<string, string> = {}; 149 - for (const cat of categoryDefaults) { 150 - const id = `label_migration_${sphere_id}_${labelCounter++}`; 151 - db.run( 152 - "INSERT INTO sphere_labels (id, sphere_id, name, description, color, position) VALUES (?, ?, ?, NULL, ?, ?)", 153 - [id, sphere_id, cat.name, cat.color, cat.position], 154 - ); 155 - labelIds[cat.slug] = id; 156 - } 157 - 158 - // Link existing feature requests to their corresponding labels 159 - const requests = db 160 - .query<{ id: string; category: string }, [string]>( 161 - "SELECT id, category FROM feature_requests WHERE sphere_id = ? AND category IS NOT NULL", 162 - ) 163 - .all(sphere_id); 164 - 165 - for (const req of requests) { 166 - const labelId = labelIds[req.category]; 167 - if (labelId) { 168 - db.run( 169 - "INSERT OR IGNORE INTO entity_labels (label_id, entity_id, entity_type) VALUES (?, ?, ?)", 170 - [labelId, req.id, "feature-request"], 171 - ); 172 - } 173 - } 174 - }); 175 - tx(); 176 - console.log(`[migrate] Sphere ${sphere_id}: created labels from categories`); 177 - } 178 - 179 - db.close(); 180 - }
-1
packages/core/src/generated/lexicon-records.ts
··· 17 17 export interface FeatureRequestEntryRecord { 18 18 title: string; 19 19 description?: string; 20 - category?: string; 21 20 /** did — DID of the Sphere owner (the identity hosting the site.exosphere.sphere.profile record). */ 22 21 subject: string; 23 22 /** datetime */
+1 -5
packages/feature-requests/src/__tests__/db-operations.test.ts
··· 50 50 authorDid: AUTHOR_DID, 51 51 title: "Test FR", 52 52 description: "A test feature request", 53 - category: "general" as const, 53 + status: "requested" as const, 54 54 ...overrides, 55 55 }; 56 56 db.insert(featureRequests).values(values).run(); ··· 72 72 authorDid: AUTHOR_DID, 73 73 title: "First", 74 74 description: "Desc", 75 - category: "general", 76 75 pdsUri: null, 77 76 }); 78 77 expect(fr1).toBeDefined(); ··· 84 83 authorDid: AUTHOR_DID, 85 84 title: "Second", 86 85 description: "Desc", 87 - category: "bug", 88 86 pdsUri: null, 89 87 }); 90 88 expect(fr2!.number).toBe(2); ··· 97 95 authorDid: AUTHOR_DID, 98 96 title: "Original", 99 97 description: "Desc", 100 - category: "general", 101 98 pdsUri: null, 102 99 }); 103 100 ··· 108 105 authorDid: AUTHOR_DID, 109 106 title: "Duplicate", 110 107 description: "Desc", 111 - category: "general", 112 108 pdsUri: null, 113 109 }); 114 110 expect(dup).toBeDefined();
+2 -10
packages/feature-requests/src/__tests__/schemas.test.ts
··· 15 15 16 16 it("accepts valid input with defaults", () => { 17 17 const result = createFeatureRequestSchema.parse(valid); 18 - expect(result.category).toBe("general"); 19 - }); 20 - 21 - it("accepts an explicit category", () => { 22 - const result = createFeatureRequestSchema.parse({ ...valid, category: "bug" }); 23 - expect(result.category).toBe("bug"); 24 - }); 25 - 26 - it("rejects unknown category", () => { 27 - expect(() => createFeatureRequestSchema.parse({ ...valid, category: "nope" })).toThrow(); 18 + expect(result.title).toBe("Add dark mode"); 19 + expect(result.labelIds).toEqual([]); 28 20 }); 29 21 30 22 it("rejects empty title", () => {
+1 -4
packages/feature-requests/src/api/requests.ts
··· 40 40 authorDid: featureRequests.authorDid, 41 41 title: featureRequests.title, 42 42 description: featureRequests.description, 43 - category: featureRequests.category, 44 43 status: featureRequests.status, 45 44 duplicateOfId: featureRequests.duplicateOfId, 46 45 pdsUri: featureRequests.pdsUri, ··· 164 163 return c.json({ error: z.flattenError(result.error) }, 400); 165 164 } 166 165 167 - const { title, description, category, labelIds } = result.data; 166 + const { title, description, labelIds } = result.data; 168 167 const sphereId = c.var.sphereId; 169 168 const sphereOwnerDid = c.var.sphereOwnerDid; 170 169 const sphereVisibility = c.var.sphereVisibility; ··· 173 172 174 173 let pdsUri: string | null = null; 175 174 176 - // Write to PDS for public spheres (category deprecated — no longer written) 177 175 if (sphereVisibility === "public") { 178 176 const session = c.var.session; 179 177 pdsUri = await putPdsRecord(session, COLLECTION, id, { ··· 189 187 authorDid: did, 190 188 title, 191 189 description, 192 - category, 193 190 pdsUri, 194 191 }); 195 192
+1 -3
packages/feature-requests/src/db/operations.ts
··· 11 11 featureRequestCommentVotes, 12 12 featureRequestStatuses, 13 13 } from "./schema.ts"; 14 - import type { Category, Status } from "../schemas/feature-request.ts"; 14 + import type { Status } from "../schemas/feature-request.ts"; 15 15 16 16 // ---- Feature Requests ---- 17 17 ··· 21 21 authorDid: string; 22 22 title: string; 23 23 description: string; 24 - category: Category; 25 24 pdsUri: string | null; 26 25 }): typeof featureRequests.$inferSelect | undefined { 27 26 const db = getDb(); ··· 43 42 authorDid: params.authorDid, 44 43 title: params.title, 45 44 description: params.description, 46 - category: params.category, 47 45 pdsUri: params.pdsUri, 48 46 }) 49 47 .run();
+1 -5
packages/feature-requests/src/db/schema.ts
··· 9 9 import { sql } from "drizzle-orm"; 10 10 import type { InferSelectModel } from "drizzle-orm"; 11 11 import { spheres } from "@exosphere/core/db/schema"; 12 - import { categories, statuses } from "../schemas/feature-request.ts"; 12 + import { statuses } from "../schemas/feature-request.ts"; 13 13 14 14 export const featureRequests = sqliteTable( 15 15 "feature_requests", ··· 22 22 authorDid: text("author_did").notNull(), 23 23 title: text("title").notNull(), 24 24 description: text("description").notNull(), 25 - category: text("category", { enum: [...categories] }) 26 - .notNull() 27 - .default("general"), 28 25 status: text("status", { enum: [...statuses] }) 29 26 .notNull() 30 27 .default("requested"), ··· 41 38 uniqueIndex("idx_feature_requests_sphere_number").on(table.sphereId, table.number), 42 39 index("idx_feature_requests_sphere").on(table.sphereId), 43 40 index("idx_feature_requests_status").on(table.status), 44 - index("idx_feature_requests_category").on(table.category), 45 41 ], 46 42 ); 47 43
+2 -8
packages/feature-requests/src/indexer.ts
··· 12 12 import { eq, and } from "@exosphere/core/db/drizzle"; 13 13 import { spheres } from "@exosphere/core/db/schema"; 14 14 import { featureRequests, featureRequestComments } from "./db/schema.ts"; 15 - import { categories, statuses } from "./schemas/feature-request.ts"; 16 - import type { Category, Status } from "./schemas/feature-request.ts"; 15 + import { statuses } from "./schemas/feature-request.ts"; 16 + import type { Status } from "./schemas/feature-request.ts"; 17 17 import { 18 18 insertFeatureRequest, 19 19 deleteFeatureRequestCascade, ··· 111 111 if (!access.allowed || !access.sphereId) return; 112 112 const sphereId = access.sphereId; 113 113 114 - const rawCategory = record.category as string; 115 - const category: Category = (categories as readonly string[]).includes(rawCategory) 116 - ? (rawCategory as Category) 117 - : "general"; 118 - 119 114 insertFeatureRequest({ 120 115 id: rkey, 121 116 sphereId, 122 117 authorDid: did, 123 118 title: (record.title as string) ?? "", 124 119 description: (record.description as string) ?? "", 125 - category, 126 120 pdsUri, 127 121 }); 128 122 return;
+1 -1
packages/feature-requests/src/mcp.ts
··· 15 15 { 16 16 name: "list_feature_requests", 17 17 description: 18 - "List feature requests with optional filtering by status and sorting. Returns title, description, category, status, vote count, and comment count for each.", 18 + "List feature requests with optional filtering by status and sorting. Returns title, description, status, vote count, and comment count for each.", 19 19 inputSchema: { 20 20 type: "object", 21 21 properties: {
-13
packages/feature-requests/src/schemas/feature-request.ts
··· 1 1 import { z } from "zod"; 2 2 3 - export const categories = ["general", "enhancement", "bug", "integration", "ui-ux"] as const; 4 - 5 - export type Category = (typeof categories)[number]; 6 - 7 - export const categoryLabels: Record<Category, string> = { 8 - general: "General", 9 - enhancement: "Enhancement", 10 - bug: "Bug", 11 - integration: "Integration", 12 - "ui-ux": "UI / UX", 13 - }; 14 - 15 3 export const statuses = [ 16 4 "requested", 17 5 "not-planned", ··· 54 42 export const createFeatureRequestSchema = z.object({ 55 43 title: z.string().min(1).max(200), 56 44 description: z.string().min(1).max(10000), 57 - category: z.enum(categories).default("general"), 58 45 labelIds: z.array(z.string()).default([]), 59 46 }); 60 47
+1 -3
packages/feature-requests/src/types.ts
··· 1 1 export type { FeatureRequest, FeatureRequestComment, FeatureRequestStatus } from "./db/schema.ts"; 2 - export type { Category, Status, SettableStatus } from "./schemas/feature-request.ts"; 2 + export type { Status, SettableStatus } from "./schemas/feature-request.ts"; 3 3 export { 4 - categoryLabels, 5 - categories, 6 4 statuses, 7 5 settableStatuses, 8 6 statusLabels,
-2
packages/feature-requests/src/ui/api/feature-requests.ts
··· 27 27 export function createFeatureRequest(body: { 28 28 title: string; 29 29 description: string; 30 - /** @deprecated Kept for backward compat with PDS indexer; defaults to "general" server-side. */ 31 - category?: string; 32 30 labelIds?: string[]; 33 31 }) { 34 32 return moduleFetch<{ featureRequest: FeatureRequest }>("/feature-requests", {