libra/docs/stories/story-15.1-database-model.md

267 lines
6.6 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
- [ ] Create migration file with proper schema
- [ ] Run migration successfully
- [ ] Create `PotentialClientType` enum with `label()` method
- [ ] Create `PotentialClient` model with fillable and casts
- [ ] Create factory with all state methods
- [ ] Create English translations
- [ ] Create Arabic translations
- [ ] Write model unit tests
- [ ] Verify factory generates valid data
## Estimation
**Complexity:** Low
**Risk:** Low - Standard model/migration setup
## Dependencies
- None (foundation for other stories in this epic)