From 3ef0a2489631dfb8c9a79abc7eb875c54782eb7a Mon Sep 17 00:00:00 2001
From: Tajim
Date: Wed, 26 Aug 2026 12:23:58 +0600
Subject: [PATCH 1/3] feat(db): add username column with default student_{id}
assignment
---
app/Models/User.php | 10 ++++++
..._26_120400_add_username_to_users_table.php | 33 +++++++++++++++++++
2 files changed, 43 insertions(+)
create mode 100644 database/migrations/2026_08_26_120400_add_username_to_users_table.php
diff --git a/app/Models/User.php b/app/Models/User.php
index 206f211..3417c47 100644
--- a/app/Models/User.php
+++ b/app/Models/User.php
@@ -38,6 +38,7 @@ class User extends Authenticatable
protected $fillable = [
'name',
+ 'username',
'email',
'receive_emails',
'google_id',
@@ -50,6 +51,15 @@ class User extends Authenticatable
'instagram',
'github',
];
+ protected static function booted(): void
+ {
+ static::created(function (User $user) {
+ if (! $user->username) {
+ $user->updateQuietly(['username' => "student_{$user->id}"]);
+ $user->username = "student_{$user->id}";
+ }
+ });
+ }
protected $appends = [
'image_url',
diff --git a/database/migrations/2026_08_26_120400_add_username_to_users_table.php b/database/migrations/2026_08_26_120400_add_username_to_users_table.php
new file mode 100644
index 0000000..fc37b18
--- /dev/null
+++ b/database/migrations/2026_08_26_120400_add_username_to_users_table.php
@@ -0,0 +1,33 @@
+string('username')->nullable()->unique()->after('name');
+ });
+
+ User::whereNull('username')->each(function ($user) {
+ $user->updateQuietly(['username' => "student_{$user->id}"]);
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::table('users', function (Blueprint $table) {
+ $table->dropColumn('username');
+ });
+ }
+};
From 14cfe0d1b8ae784c7e4b4539fbb6089169718cba Mon Sep 17 00:00:00 2001
From: Tajim
Date: Wed, 26 Aug 2026 12:24:03 +0600
Subject: [PATCH 2/3] feat(profile): add username validation and edit field in
profile settings
---
.../Requests/Profile/UpdateProfileRequest.php | 9 ++++
resources/js/pages/Profile.vue | 42 +++++++++++++++++++
2 files changed, 51 insertions(+)
diff --git a/app/Http/Requests/Profile/UpdateProfileRequest.php b/app/Http/Requests/Profile/UpdateProfileRequest.php
index 867d782..a503ee0 100644
--- a/app/Http/Requests/Profile/UpdateProfileRequest.php
+++ b/app/Http/Requests/Profile/UpdateProfileRequest.php
@@ -4,6 +4,7 @@
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Foundation\Http\FormRequest;
+use Illuminate\Validation\Rule;
class UpdateProfileRequest extends FormRequest
{
@@ -24,6 +25,14 @@ public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
+ 'username' => [
+ 'sometimes',
+ 'string',
+ 'min:3',
+ 'max:30',
+ 'regex:/^[a-zA-Z0-9_]+$/',
+ Rule::unique('users', 'username')->ignore($this->user()->id),
+ ],
'file' => ['sometimes', 'nullable', 'image', 'max:2048'],
'about' => ['sometimes', 'nullable', 'string'],
'institution' => ['sometimes', 'nullable', 'string', 'max:255'],
diff --git a/resources/js/pages/Profile.vue b/resources/js/pages/Profile.vue
index 7ab6e00..fe1696d 100644
--- a/resources/js/pages/Profile.vue
+++ b/resources/js/pages/Profile.vue
@@ -32,6 +32,7 @@ const showConfirmModal = ref(false);
const form = useForm({
_method: 'PUT',
name: user.value?.name || '',
+ username: user.value?.username || '',
file: null as File | null,
about: user.value?.about || '',
institution: user.value?.institution || '',
@@ -178,6 +179,47 @@ const submitForm = () => {
+
+
+
+
+ @
+
+
+
+
+ {{ form.errors.username }}
+
+
+ Letters, numbers, and underscores (3–30 chars).
+
+
+