311 lines
8.1 KiB
Markdown
311 lines
8.1 KiB
Markdown
# Story 15.1: Database Schema & Model Setup
|
|
|
|
## Story
|
|
|
|
**As an** admin
|
|
**I want to** have a database structure for potential clients
|
|
**So that** I can store and manage prospective client information
|
|
|
|
## Acceptance Criteria
|
|
|
|
### AC1: Database Migration
|
|
|
|
**Given** the system needs to store potential clients
|
|
**When** the migration runs
|
|
**Then** a `potential_clients` table is created with:
|
|
- `id` - bigint, primary key, auto-increment
|
|
- `type` - varchar, stores potential client type (individual, company, agency)
|
|
- `name` - varchar(255), nullable
|
|
- `phone` - varchar(50), nullable
|
|
- `email` - varchar(255), nullable
|
|
- `address` - text, nullable
|
|
- `social_media` - varchar(255), nullable
|
|
- `website` - varchar(255), nullable
|
|
- `notes` - text, nullable
|
|
- `created_at` - timestamp
|
|
- `updated_at` - timestamp
|
|
|
|
### AC2: PotentialClientType Enum
|
|
|
|
**Given** potential clients have different types
|
|
**When** the enum is created
|
|
**Then** `App\Enums\PotentialClientType` contains:
|
|
- `Individual` = 'individual'
|
|
- `Company` = 'company'
|
|
- `Agency` = 'agency'
|
|
|
|
And includes a `label()` method returning translated labels.
|
|
|
|
### AC3: PotentialClient Model
|
|
|
|
**Given** the migration exists
|
|
**When** the model is created
|
|
**Then** `App\Models\PotentialClient` includes:
|
|
- Proper `$fillable` array for all fields
|
|
- Cast `type` to `PotentialClientType` enum
|
|
- No relationships required (standalone model)
|
|
|
|
### AC4: Model Factory
|
|
|
|
**Given** tests need potential client data
|
|
**When** the factory is created
|
|
**Then** `Database\Factories\PotentialClientFactory` generates:
|
|
- Random type from enum values
|
|
- Realistic fake data for all fields
|
|
- State methods: `individual()`, `company()`, `agency()`
|
|
|
|
### AC5: Translation Keys
|
|
|
|
**Given** the system is bilingual
|
|
**When** translations are added
|
|
**Then** create keys in `lang/en/potential-clients.php` and `lang/ar/potential-clients.php`:
|
|
- Model name (singular/plural)
|
|
- Enum type labels
|
|
- All field labels
|
|
|
|
## Technical Notes
|
|
|
|
### Files to Create
|
|
|
|
| File | Purpose |
|
|
|------|---------|
|
|
| `database/migrations/xxxx_create_potential_clients_table.php` | Database schema |
|
|
| `app/Enums/PotentialClientType.php` | Type enum |
|
|
| `app/Models/PotentialClient.php` | Eloquent model |
|
|
| `database/factories/PotentialClientFactory.php` | Test factory |
|
|
| `lang/en/potential-clients.php` | English translations |
|
|
| `lang/ar/potential-clients.php` | Arabic translations |
|
|
|
|
### Migration Schema
|
|
|
|
```php
|
|
Schema::create('potential_clients', function (Blueprint $table) {
|
|
$table->id();
|
|
$table->string('type');
|
|
$table->string('name')->nullable();
|
|
$table->string('phone', 50)->nullable();
|
|
$table->string('email')->nullable();
|
|
$table->text('address')->nullable();
|
|
$table->string('social_media')->nullable();
|
|
$table->string('website')->nullable();
|
|
$table->text('notes')->nullable();
|
|
$table->timestamps();
|
|
});
|
|
```
|
|
|
|
### Enum Implementation
|
|
|
|
```php
|
|
<?php
|
|
|
|
namespace App\Enums;
|
|
|
|
enum PotentialClientType: string
|
|
{
|
|
case Individual = 'individual';
|
|
case Company = 'company';
|
|
case Agency = 'agency';
|
|
|
|
public function label(): string
|
|
{
|
|
return match($this) {
|
|
self::Individual => __('potential-clients.types.individual'),
|
|
self::Company => __('potential-clients.types.company'),
|
|
self::Agency => __('potential-clients.types.agency'),
|
|
};
|
|
}
|
|
}
|
|
```
|
|
|
|
### Model Implementation
|
|
|
|
```php
|
|
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use App\Enums\PotentialClientType;
|
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
|
|
class PotentialClient extends Model
|
|
{
|
|
use HasFactory;
|
|
|
|
protected $fillable = [
|
|
'type',
|
|
'name',
|
|
'phone',
|
|
'email',
|
|
'address',
|
|
'social_media',
|
|
'website',
|
|
'notes',
|
|
];
|
|
|
|
protected function casts(): array
|
|
{
|
|
return [
|
|
'type' => PotentialClientType::class,
|
|
];
|
|
}
|
|
}
|
|
```
|
|
|
|
### Factory Implementation
|
|
|
|
```php
|
|
<?php
|
|
|
|
namespace Database\Factories;
|
|
|
|
use App\Enums\PotentialClientType;
|
|
use App\Models\PotentialClient;
|
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
|
|
|
class PotentialClientFactory extends Factory
|
|
{
|
|
protected $model = PotentialClient::class;
|
|
|
|
public function definition(): array
|
|
{
|
|
return [
|
|
'type' => fake()->randomElement(PotentialClientType::cases()),
|
|
'name' => fake()->name(),
|
|
'phone' => fake()->phoneNumber(),
|
|
'email' => fake()->safeEmail(),
|
|
'address' => fake()->address(),
|
|
'social_media' => fake()->url(),
|
|
'website' => fake()->url(),
|
|
'notes' => fake()->optional()->sentence(),
|
|
];
|
|
}
|
|
|
|
public function individual(): static
|
|
{
|
|
return $this->state(['type' => PotentialClientType::Individual]);
|
|
}
|
|
|
|
public function company(): static
|
|
{
|
|
return $this->state(['type' => PotentialClientType::Company]);
|
|
}
|
|
|
|
public function agency(): static
|
|
{
|
|
return $this->state(['type' => PotentialClientType::Agency]);
|
|
}
|
|
}
|
|
```
|
|
|
|
### Translation Files
|
|
|
|
```php
|
|
// lang/en/potential-clients.php
|
|
return [
|
|
'title' => 'Potential Clients',
|
|
'singular' => 'Potential Client',
|
|
'types' => [
|
|
'individual' => 'Individual',
|
|
'company' => 'Company',
|
|
'agency' => 'Agency',
|
|
],
|
|
'fields' => [
|
|
'type' => 'Type',
|
|
'name' => 'Name',
|
|
'phone' => 'Phone',
|
|
'email' => 'Email',
|
|
'address' => 'Address',
|
|
'social_media' => 'Social Media',
|
|
'website' => 'Website',
|
|
'notes' => 'Notes',
|
|
],
|
|
];
|
|
|
|
// lang/ar/potential-clients.php
|
|
return [
|
|
'title' => 'العملاء المحتملون',
|
|
'singular' => 'عميل محتمل',
|
|
'types' => [
|
|
'individual' => 'فرد',
|
|
'company' => 'شركة',
|
|
'agency' => 'وكالة',
|
|
],
|
|
'fields' => [
|
|
'type' => 'النوع',
|
|
'name' => 'الاسم',
|
|
'phone' => 'الهاتف',
|
|
'email' => 'البريد الإلكتروني',
|
|
'address' => 'العنوان',
|
|
'social_media' => 'وسائل التواصل',
|
|
'website' => 'الموقع الإلكتروني',
|
|
'notes' => 'ملاحظات',
|
|
],
|
|
];
|
|
```
|
|
|
|
## Dev Checklist
|
|
|
|
- [x] Create migration file with proper schema
|
|
- [x] Run migration successfully
|
|
- [x] Create `PotentialClientType` enum with `label()` method
|
|
- [x] Create `PotentialClient` model with fillable and casts
|
|
- [x] Create factory with all state methods
|
|
- [x] Create English translations
|
|
- [x] Create Arabic translations
|
|
- [x] Write model unit tests
|
|
- [x] Verify factory generates valid data
|
|
|
|
## Estimation
|
|
|
|
**Complexity:** Low
|
|
**Risk:** Low - Standard model/migration setup
|
|
|
|
## Dependencies
|
|
|
|
- None (foundation for other stories in this epic)
|
|
|
|
---
|
|
|
|
## Dev Agent Record
|
|
|
|
### Status
|
|
|
|
Ready for Review
|
|
|
|
### Agent Model Used
|
|
|
|
Claude Opus 4.5 (claude-opus-4-5-20251101)
|
|
|
|
### Completion Notes
|
|
|
|
All acceptance criteria met:
|
|
- AC1: Migration created with all specified fields and proper schema
|
|
- AC2: PotentialClientType enum with Individual, Company, Agency cases and label() method
|
|
- AC3: PotentialClient model with fillable array and type casting to enum
|
|
- AC4: Factory with definition() and state methods (individual(), company(), agency())
|
|
- AC5: English and Arabic translation files with all required keys
|
|
|
|
### File List
|
|
|
|
| File | Action |
|
|
|------|--------|
|
|
| `database/migrations/2026_01_09_163956_create_potential_clients_table.php` | Created |
|
|
| `app/Enums/PotentialClientType.php` | Created |
|
|
| `app/Models/PotentialClient.php` | Created |
|
|
| `database/factories/PotentialClientFactory.php` | Created |
|
|
| `lang/en/potential-clients.php` | Created |
|
|
| `lang/ar/potential-clients.php` | Created |
|
|
| `tests/Unit/Models/PotentialClientTest.php` | Created |
|
|
| `tests/Unit/Enums/PotentialClientTypeTest.php` | Created |
|
|
|
|
### Change Log
|
|
|
|
- 2026-01-09: Initial implementation of Story 15.1
|
|
- Created potential_clients table migration with all specified columns
|
|
- Created PotentialClientType enum with label() method for bilingual support
|
|
- Created PotentialClient model with proper fillable and casts
|
|
- Created factory with realistic data and state methods
|
|
- Added English and Arabic translations
|
|
- Added comprehensive unit tests for model and enum (13 tests, 32 assertions)
|