diff --git a/app/database/migrations/2026_10_11_000001_create_users_table.php b/app/database/migrations/2026_10_11_000001_create_users_table.php new file mode 100644 index 0000000..37ec582 --- /dev/null +++ b/app/database/migrations/2026_10_11_000001_create_users_table.php @@ -0,0 +1,26 @@ +increments('user_id'); + $table->string('email', 255); + $table->string('password_hash', 255); + $table->string('name', 255); + $table->timestamp('created_datetime')->useCurrent(); + $table->timestamp('updated_datetime')->nullable(); + + $table->unique('email', 'idx_email'); + }); + } + + public function down(): void { + Schema::dropIfExists('users'); + } +}; diff --git a/app/database/migrations/2026_10_11_000002_create_boards_table.php b/app/database/migrations/2026_10_11_000002_create_boards_table.php new file mode 100644 index 0000000..6fd3e90 --- /dev/null +++ b/app/database/migrations/2026_10_11_000002_create_boards_table.php @@ -0,0 +1,29 @@ +increments('board_id'); + $table->string('title', 255); + $table->integer('owner_user_id'); + $table->boolean('is_public')->default(false); + $table->timestamp('created_datetime')->useCurrent(); + $table->timestamp('updated_datetime')->nullable(); + + $table->foreign('owner_user_id') + ->references('user_id') + ->on('users') + ->onDelete('cascade'); + }); + } + + public function down(): void { + Schema::dropIfExists('boards'); + } +}; diff --git a/app/database/migrations/2026_10_11_000003_create_board_columns_table.php b/app/database/migrations/2026_10_11_000003_create_board_columns_table.php new file mode 100644 index 0000000..6351171 --- /dev/null +++ b/app/database/migrations/2026_10_11_000003_create_board_columns_table.php @@ -0,0 +1,30 @@ +increments('column_id'); + $table->integer('board_id'); + $table->smallInteger('ordinal_position'); + $table->string('title', 255); + $table->string('color', 6)->nullable(); + + $table->index('board_id', 'idx_board_id'); + + $table->foreign('board_id') + ->references('board_id') + ->on('boards') + ->onDelete('cascade'); + }); + } + + public function down(): void { + Schema::dropIfExists('board_columns'); + } +}; diff --git a/app/database/migrations/2026_10_11_000004_create_cards_table.php b/app/database/migrations/2026_10_11_000004_create_cards_table.php new file mode 100644 index 0000000..ad82ea7 --- /dev/null +++ b/app/database/migrations/2026_10_11_000004_create_cards_table.php @@ -0,0 +1,41 @@ +increments('card_id'); + $table->integer('board_id'); + $table->integer('column_id'); + $table->smallInteger('sort_index'); + $table->string('title', 255); + $table->text('content')->nullable(); + $table->string('color', 6)->nullable(); + $table->boolean('is_archived')->default(false); + $table->timestamp('created_datetime')->useCurrent(); + $table->timestamp('updated_datetime')->nullable(); + + $table->foreign('board_id') + ->references('board_id') + ->on('boards') + ->onDelete('cascade'); + + $table->foreign('column_id') + ->references('column_id') + ->on('board_columns') + ->onDelete('cascade'); + }); + + DB::statement('create index "idx_active_board_id" on "cards" ("board_id") where "is_archived" = false'); + } + + public function down(): void { + Schema::dropIfExists('cards'); + } +}; diff --git a/app/src/Models/Board.php b/app/src/Models/Board.php new file mode 100644 index 0000000..4965cc4 --- /dev/null +++ b/app/src/Models/Board.php @@ -0,0 +1,39 @@ + 'int', + 'owner_user_id' => 'int', + 'is_public' => 'bool', + 'created_datetime' => 'datetime', + 'updated_datetime' => 'datetime', + ]; + + public function owner(): BelongsTo { + return $this->belongsTo(User::class, 'owner_user_id', 'user_id'); + } + + public function columns(): HasMany { + return $this->hasMany(BoardColumn::class, 'board_id', 'board_id'); + } + + public function cards(): HasMany { + return $this->hasMany(Card::class, 'board_id', 'board_id'); + } +} diff --git a/app/src/Models/BoardColumn.php b/app/src/Models/BoardColumn.php new file mode 100644 index 0000000..7c2e469 --- /dev/null +++ b/app/src/Models/BoardColumn.php @@ -0,0 +1,33 @@ + 'int', + 'board_id' => 'int', + 'ordinal_position' => 'int', + ]; + + public function board(): BelongsTo { + return $this->belongsTo(Board::class, 'board_id', 'board_id'); + } + + public function cards(): HasMany { + return $this->hasMany(Card::class, 'column_id', 'column_id'); + } +} diff --git a/app/src/Models/Card.php b/app/src/Models/Card.php new file mode 100644 index 0000000..e90a46c --- /dev/null +++ b/app/src/Models/Card.php @@ -0,0 +1,36 @@ + 'int', + 'board_id' => 'int', + 'column_id' => 'int', + 'sort_index' => 'int', + 'is_archived' => 'bool', + 'created_datetime' => 'datetime', + 'updated_datetime' => 'datetime', + ]; + + public function board(): BelongsTo { + return $this->belongsTo(Board::class, 'board_id', 'board_id'); + } + + public function column(): BelongsTo { + return $this->belongsTo(BoardColumn::class, 'column_id', 'column_id'); + } +} diff --git a/app/src/Models/User.php b/app/src/Models/User.php new file mode 100644 index 0000000..c7502d8 --- /dev/null +++ b/app/src/Models/User.php @@ -0,0 +1,30 @@ + 'int', + 'created_datetime' => 'datetime', + 'updated_datetime' => 'datetime', + ]; + + public function boards(): HasMany { + return $this->hasMany(Board::class, 'owner_user_id', 'user_id'); + } +}