{"id":31692498,"url":"https://github.com/wmblw/search-engine-example","last_synced_at":"2026-04-10T00:46:35.022Z","repository":{"id":317826719,"uuid":"1067342541","full_name":"wMBLw/search-engine-example","owner":"wMBLw","description":"Example of implementing enterprise application practices on Laravel","archived":false,"fork":false,"pushed_at":"2025-10-03T09:33:56.000Z","size":256,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-10-03T10:27:45.836Z","etag":null,"topics":["abstract-factory-pattern","adapter-pattern","chain-of-responsibility","circuit-breaker-pattern","distributed-lock","docker","event-sourcing","github-actions","jwt-authentication","laravel","localization","observer-pattern","pest","php","race-conditions","redis","repository-pattern","restful-api","sanctum-authentication","strategy-pattern"],"latest_commit_sha":null,"homepage":"https://mulkenburak.com","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wMBLw.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-30T18:11:01.000Z","updated_at":"2025-10-03T09:34:01.000Z","dependencies_parsed_at":"2025-10-06T09:00:25.470Z","dependency_job_id":null,"html_url":"https://github.com/wMBLw/search-engine-example","commit_stats":null,"previous_names":["wmblw/search-engine-example"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/wMBLw/search-engine-example","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wMBLw%2Fsearch-engine-example","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wMBLw%2Fsearch-engine-example/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wMBLw%2Fsearch-engine-example/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wMBLw%2Fsearch-engine-example/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wMBLw","download_url":"https://codeload.github.com/wMBLw/search-engine-example/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wMBLw%2Fsearch-engine-example/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278963832,"owners_count":26076542,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-08T02:00:06.501Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["abstract-factory-pattern","adapter-pattern","chain-of-responsibility","circuit-breaker-pattern","distributed-lock","docker","event-sourcing","github-actions","jwt-authentication","laravel","localization","observer-pattern","pest","php","race-conditions","redis","repository-pattern","restful-api","sanctum-authentication","strategy-pattern"],"created_at":"2025-10-08T14:53:31.805Z","updated_at":"2025-10-08T14:53:37.228Z","avatar_url":"https://github.com/wMBLw.png","language":"PHP","readme":"#Search Engine Example\n\n\n\n[![Tests](https://img.shields.io/badge/tests-Pest-passing?style=flat-square\u0026logo=php)](https://pestphp.com/)\n[![PHP](https://img.shields.io/badge/PHP-8.2+-777BB4?style=flat-square\u0026logo=php)](https://www.php.net/)\n[![Laravel](https://img.shields.io/badge/Laravel-12.x-FF2D20?style=flat-square\u0026logo=laravel)](https://laravel.com/)\n[![Docker](https://img.shields.io/badge/Docker-Ready-2496ED?style=flat-square\u0026logo=docker)](https://www.docker.com/)\n[![License](https://img.shields.io/badge/License-MIT-green.svg?style=flat-square)](LICENSE)\n\n---\n\n## İçindekiler\n\n- [Teknoloji Yığını](#-teknoloji-yığını)\n- [Kurulum](#-kurulum)\n- [API Dokümantasyonu](#-api-dokümantasyonu)\n- [Kullanılan Tasarım Desenleri](#-kullanılan-tasarım-desenleri)\n- [Proje Yapısı](#-proje-yapisi)\n- [Konseptler](#-konseptler)\n\n---\n\n## Teknoloji Yığını\n\n### Backend\n- **PHP 8.2+**\n- **Laravel 12.x**\n- **MySQL 8.0** - Veritabanı\n- **Redis 7.2** - Cache ve Queue\n- **Guzzle HTTP** - API istekleri\n\n### DevOps\n- **Docker \u0026 Docker Compose** - Containerization\n- **Nginx** - Web server\n- **Supervisor** - Process management\n\n### Testing \u0026 Quality\n- **Pest PHP** - Testing framework\n- **GitHub Actions** - CI/CD\n\n### Monitoring \u0026 Debugging\n- **Laravel Telescope** - Application debugging\n- **Laravel Horizon** - Queue monitoring\n\n---\n\n## Kurulum\n\n### Gereksinimler\n\n- Docker ve Docker Compose\n\n### Kurulum Adımları\n\n**1. Projeyi klonlayın:**\n```bash\ngit clone https://github.com/wMBLw/search-engine-example.git\ncd search-engine-example/docker\n```\n\n**2. Environment dosyasını oluşturun:**\n```bash\ncp ../.env.example ../.env\n```\n\n\u003e **Not:** .env.example dosyası hazır ayarlarla gelir, değişiklik yapmanıza gerek yoktur.\n\n**3. Docker container'ları başlatın:**\n```bash\ndocker compose --env-file ../.env up -d --build\n```\n\n**4. Tamamlandı**\n\nUygulama otomatik olarak:\n- Bağımlılıkları yükler (composer, npm)\n- Veritabanını oluşturur ve migrate eder\n- Seed verilerini yükler\n\n### Erişim Bilgileri\n\n**API Base URL:** http://localhost/api\n\n**Test Kullanıcısı:**\n- Email: test@example.com\n- Şifre: password\n\n**Servisler:**\n- **Web Application:** http://localhost\n- **Telescope (Debug):** http://localhost/telescope\n- **Horizon (Queue):** http://localhost/horizon\n- **MySQL:** localhost:3306\n- **Redis:** localhost:6379\n\n---\n\n## API Dokümantasyonu\n\n### Postman Collection\n\nProje içinde hazır Postman collection ve environment dosyaları bulunmaktadır:\n- postman/SearchEngineExample.postman_collection.json\n- postman/SearchEngineExample.postman_environment.json\n\n### Endpoints\n\n#### Authentication\n\n**1. Login**\n```http\nPOST /api/login\nContent-Type: application/json\n\n{\n  \"email\": \"test@example.com\",\n  \"password\": \"password\"\n}\n```\n\n**Response (200):**\n```json\n{\n  \"data\": {\n    \"user\": {\n      \"id\": 1,\n      \"name\": \"Test User\",\n      \"email\": \"test@example.com\"\n    },\n    \"access_token\": \"1|xxxxxxxxxxxxx\",\n    \"refresh_token\": \"2|xxxxxxxxxxxxx\",\n    \"access_token_expires_at\": \"2025-10-03T13:00:00.000000Z\",\n    \"refresh_token_expires_at\": \"2025-11-02T12:00:00.000000Z\"\n  }\n}\n```\n\n**2. Refresh Token**\n```http\nPOST /api/refresh-token\nAuthorization: Bearer {refresh_token}\n```\n\n**3. Get Logged In User**\n```http\nGET /api/user\nAuthorization: Bearer {access_token}\n```\n\n**4. Logout**\n```http\nGET /api/user/logout\nAuthorization: Bearer {access_token}\n```\n\n#### Search\n\n**5. Search Contents**\n```http\nGET /api/search?keyword=laravel\u0026type=article\u0026sort_by=score\u0026per_page=10\u0026page=1\nAuthorization: Bearer {access_token}\n```\n\n**Query Parameters:**\n\n| Parameter | Type | Required | Default | Description |\n|-----------|------|----------|---------|-------------|\n| keyword | string | No | - | Aranacak kelime (min: 2, max: 255) |\n| type | string | No | - | İçerik tipi: video, article |\n| sort_by | string | No | score | Sıralama: score, title, views, likes, published_at |\n| sort_direction | string | No | desc | Sıralama yönü: asc, desc |\n| per_page | integer | No | 20 | Sayfa başına kayıt (min: 1, max: 100) |\n| page | integer | No | 1 | Sayfa numarası |\n\n**Response (200):**\n```json\n{\n  \"data\": [\n    {\n      \"id\": 1,\n      \"external_id\": \"ext-123\",\n      \"title\": \"Laravel 12 Yenilikleri\",\n      \"type\": \"article\",\n      \"views\": 15000,\n      \"likes\": 1200,\n      \"tags\": [\"laravel\", \"php\", \"framework\"],\n      \"published_at\": \"2025-10-01T10:00:00.000000Z\",\n      \"score\": 125.75,\n      \"provider\": {\n        \"id\": 1,\n        \"name\": \"Provider 1\"\n      }\n    }\n  ],\n  \"meta\": {\n    \"current_page\": 1,\n    \"per_page\": 10,\n    \"total\": 100\n  }\n}\n```\n\n**6. Get Statistics**\n```http\nGET /api/search/statistics\nAuthorization: Bearer {access_token}\n```\n\n**Response (200):**\n```json\n{\n  \"data\": {\n    \"total_contents\": 1250,\n    \"total_videos\": 750,\n    \"total_articles\": 500,\n    \"total_providers\": 2,\n    \"active_providers\": 2\n  }\n}\n```\n\n\n---\n\n## Kullanılan Tasarım Desenleri\n\n### 1.Abstract Factory Pattern\n\n**Kullanım Alanı:** Provider Adapter'ları oluşturmak için\n\n**Amaç:** Farklı veri formatlarını (JSON, XML) destekleyen provider adapter'larını dinamik olarak oluşturmak.\n\n```\n┌────────────────────────────────────────┐\n│    ProviderAdapterFactory              │\n│    (Abstract Factory)                  │\n└────────────────────────────────────────┘\n                 │\n                 │ creates\n                 ▼\n┌────────────────────────────────────────┐\n│    AbstractProviderAdapter             │\n│    (Abstract Product)                  │\n└────────────────────────────────────────┘\n                 △\n                 │ implements\n        ┌────────┴────────┐\n        │                 │\n┌───────────────┐  ┌──────────────┐\n│ JsonProvider  │  │ XmlProvider  │\n│   Adapter     │  │   Adapter    │\n└───────────────┘  └──────────────┘\n```\n\n---\n\n### 2.Adapter Pattern\n\n**Kullanım Alanı:** Dış API'lerden gelen farklı formatları normalize etmek\n\n**Amaç:** JSON ve XML formatındaki farklı veri yapılarını ortak bir formata dönüştürmek.\n\n```\nExternal APIs            Adapters              Application\n┌──────────┐         ┌──────────────┐      ┌──────────────┐\n│ JSON API │────────\u003e│ JsonAdapter  │─────\u003e│              │\n└──────────┘         └──────────────┘      │  Normalized  │\n┌──────────┐         ┌──────────────┐      │   Content    │\n│ XML API  │────────\u003e│ XmlAdapter   │─────\u003e│     DTO      │\n└──────────┘         └──────────────┘      └──────────────┘\n```\n\n---\n\n### 3.Strategy Pattern\n\n**Kullanım Alanı:** İçerik puanlama (scoring) algoritmaları\n\n**Amaç:** Video ve Article içerikleri için farklı puanlama algoritmaları uygulamak.\n\n```\n┌────────────────────────────────┐\n│   ScoringStrategyFactory       │\n└────────────────────────────────┘\n                │\n                │ creates\n                ▼\n┌────────────────────────────────┐\n│   ScoringStrategyInterface     │\n└────────────────────────────────┘\n                △\n                │ implements\n        ┌───────┴────────┐\n        │                │\n┌───────────────┐  ┌────────────────┐\n│ VideoScoring  │  │ ArticleScoring │\n│   Strategy    │  │    Strategy    │\n└───────────────┘  └────────────────┘\n```\n\n\n---\n\n### 4.Chain of Responsibility Pattern\n\n**Kullanım Alanı:** Arama filtreleri\n\n**Amaç:** Arama sorgusuna birden fazla filtreyi zincirleme şekilde uygulamak.\n\n```\nSearch Query\n      │\n      ▼\n┌──────────────────┐\n│  KeywordFilter   │ → keyword varsa filtrele\n└──────────────────┘\n      │\n      ▼\n┌──────────────────┐\n│ ContentTypeFilter│ → type varsa filtrele\n└──────────────────┘\n      │\n      ▼\n┌──────────────────┐\n│  SortingFilter   │ → sıralama uygula\n└──────────────────┘\n      │\n      ▼\n   Final Result\n```\n---\n\n### 5.Circuit Breaker Pattern\n\n**Kullanım Alanı:** Provider senkronizasyonu hata yönetimi\n\n**Amaç:** Sürekli başarısız olan provider'ları geçici olarak devre dışı bırakmak.\n\n```\n┌─────────────────────────────────────────────────┐\n│              Circuit Breaker States              │\n└─────────────────────────────────────────────────┘\n\n     ┌──────────┐\n     │  CLOSED  │  (Normal çalışma)\n     └──────────┘\n          │\n          │ Başarısız istekler artıyor\n          │ (consecutive_failures \u003e= 3)\n          ▼\n     ┌──────────┐\n     │   OPEN   │  (Devre dışı - 30 dakika)\n     └──────────┘\n          │\n          │ Timeout süresi doldu\n          ▼\n     ┌──────────┐\n     │  CLOSED  │  (Tekrar aktif)\n     └──────────┘\n```\n\n**Veritabanı Yapısı:**\n```sql\nproviders\n├── consecutive_failures (int)    -- Ardışık hata sayısı\n└── disabled_until (timestamp)    -- Devre dışı kalma süresi\n```\n---\n\n### 6.Distributed Lock Pattern\n\n**Kullanım Alanı:** Provider senkronizasyonu\n\n**Amaç:** Aynı provider'ın aynı anda birden fazla process tarafından senkronize edilmesini önlemek.\n\n```\n┌──────────────┐         ┌──────────────┐         ┌──────────────┐\n│  Process 1   │         │  Process 2   │         │  Process 3   │\n└──────────────┘         └──────────────┘         └──────────────┘\n        │                        │                        │\n        │ Lock Al                │ Lock Almaya Çalış     │ Lock Almaya Çalış\n        ▼                        ▼                        ▼\n┌────────────────────────────────────────────────────────────────┐\n│                         Redis Lock                              │\n│                 provider_sync_1: uuid-xxx-xxx                   │\n└────────────────────────────────────────────────────────────────┘\n        │                        │                        │\n        │ ✅ Lock Alındı         │ ❌ Bekle              │ ❌ Bekle\n        ▼                        │                        │\n    İşlem Yap                    │                        │\n        │                        │                        │\n        │ Lock Serbest Bırak     │                        │\n        ▼                        ▼                        ▼\n    ✅ Tamamlandı           ✅ Şimdi Alabilir        ✅ Şimdi Alabilir\n```\n\n---\n\n### 7.Observer Pattern\n\n**Kullanım Alanı:** Content modeli değişikliklerinde cache yönetimi\n\n---\n\n### 8.Repository Pattern\n\n**Kullanım Alanı:** Veri erişim katmanı\n\n**Amaç:** Business logic ile veri erişim mantığını ayırmak.\n\n---\n\n### 9.Event-Driven Architecture\n\n**Kullanım Alanı:** Kullanıcı login loglama\n\n**Akış:**\n```\nLogin → Event Dispatch → Listener → Queue Job → Database\n```\n\n---\n\n### CI/CD Pipeline\n\nGitHub Actions master branch'e PR açıldığında otomatik test çalıştırır:\n\n```yaml\n# .github/workflows/run-tests.yml\nname: Run Pest Tests\n\non:\n  pull_request:\n    branches: [ master ]\n\njobs:\n  laravel-tests:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - run: composer install\n      - run: ./vendor/bin/pest\n```\n\n---\n\n## Proje Yapısı\n\n```\nsearch-engine-example/\n│\n├── app/\n│   ├── Console/Commands/      # Artisan komutları\n│   ├── Enums/                 # Enum'lar\n│   ├── Events/                # Event'ler\n│   ├── Exceptions/            # Custom exception'lar\n│   ├── Filters/               # Chain of Responsibility\n│   ├── Http/\n│   │   ├── Controllers/\n│   │   ├── Requests/\n│   │   └── Resources/\n│   ├── Jobs/                  # Queue jobs\n│   ├── Listeners/             # Event listeners\n│   ├── Models/\n│   ├── Observers/             # Observer pattern\n│   ├── Repositories/          # Repository pattern\n│   └── Services/\n│       ├── Auth/\n│       ├── Content/           # Sync, Lock\n│       ├── Providers/         # Adapter, Factory\n│       └── Search/            # Strategy pattern\n│\n├── config/\n├── database/\n│   ├── factories/\n│   ├── migrations/\n│   └── seeders/\n│\n├── docker/\n│   ├── docker-compose.yml\n│   ├── Dockerfile\n│   ├── entrypoint.sh\n│   └── supervisord.conf\n│\n├── routes/\n│   ├── api.php\n│   └── web.php\n│\n├── tests/\n│   ├── Feature/\n│   └── Unit/\n│\n└── .github/workflows/         # CI/CD\n    └── run-tests.yml\n```\n\n---\n\n## Mimari Diyagramlar\n\n### Provider Sync Akışı\n\n```\nArtisan Command\n      │\n      ▼\n┌──────────────────────┐\n│ContentSyncService    │\n└──────────────────────┘\n      │\n      ▼\n┌──────────────────────┐\n│ Distributed Lock     │\n│   Acquire Lock       │──── ❌ Skip if locked\n└──────────────────────┘\n      │\n      │ ✅ Lock Alındı\n      ▼\n┌──────────────────────┐\n│ Provider Adapter     │\n│  Factory.make()      │\n└──────────────────────┘\n      │\n      ├──→ JSON Adapter\n      └──→ XML Adapter\n           │\n           ▼\n┌──────────────────────┐\n│   External API       │\n│  (JSON/XML Data)     │\n└──────────────────────┘\n           │\n           ▼\n┌──────────────────────┐\n│ NormalizedContentDTO │\n└──────────────────────┘\n           │\n           ▼\n┌──────────────────────┐\n│   Content Model      │\n│    (Database)        │\n└──────────────────────┘\n           │\n           ▼\n┌──────────────────────┐\n│  ContentObserver     │\n│ clearStatisticsCache │\n└──────────────────────┘\n```\n\n### Arama Akışı\n\n```\nUser Request\n      │\n      ▼\n┌──────────────────────┐\n│  SearchController    │\n└──────────────────────┘\n      │\n      ▼\n┌──────────────────────┐\n│   SearchService      │\n└──────────────────────┘\n      │\n      ▼\n┌──────────────────────┐\n│  SearchRepository    │\n└──────────────────────┘\n      │\n      ▼\n┌──────────────────────────────────────┐\n│   Pipeline (Chain of Responsibility) │\n│                                      │\n│  Query → KeywordFilter               │\n│       → ContentTypeFilter            │\n│       → SortingFilter                │\n└──────────────────────────────────────┘\n      │\n      ▼\n┌──────────────────────┐\n│      Database        │\n└──────────────────────┘\n      │\n      ▼\n┌──────────────────────┐\n│  ScoreCalculator     │\n│  (Strategy Pattern)  │\n└──────────────────────┘\n      │\n      ▼\n┌──────────────────────┐\n│  SearchResultDTO     │\n└──────────────────────┘\n```\n\n---\n\n## Uygulanan Konseptler\n\n### Tasarım Desenleri\n- Abstract Factory Pattern\n- Adapter Pattern\n- Strategy Pattern\n- Chain of Responsibility Pattern\n- Circuit Breaker Pattern\n- Observer Pattern\n- Repository Pattern\n- Factory Pattern\n\n### Yazılım Prensipleri\n- SOLID Prensipleri\n- Clean Code\n- KISS\n- DRY\n- Dependency Injection\n\n### Mimari Konseptler\n- Layered Architecture\n- Event-Driven Architecture\n- DTO\n- Service Layer Pattern\n- Distributed Lock\n- Race Condition Prevention\n- Circuit Breaker\n\n### Laravel Özellikleri\n- Sanctum Authentication (JWT)\n- Eloquent ORM \u0026 Relationships\n- Query Scopes (Global \u0026 Local)\n- Model Observers\n- Events \u0026 Listeners\n- Queue Jobs (Redis)\n- Laravel Horizon\n- Laravel Telescope\n- Service Providers\n- Middleware\n- Custom Artisan Commands\n\n\n### Testing\n- Pest PHP Testing Framework\n- Unit Tests\n- Feature Tests\n\n---\n\n## Önemli Komutlar\n\n### Artisan Commands\n\n```bash\n# Seed data\nphp artisan db:seed\n\n# Provider senkronizasyonu\nphp artisan providers:sync\n\n```\n\n### Docker Commands\n\n```bash\n# Container'ları başlat\ndocker compose --env-file ../.env up -d --build\n\n# Container'ları durdur\ndocker compose down\n```\n\n---\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwmblw%2Fsearch-engine-example","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwmblw%2Fsearch-engine-example","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwmblw%2Fsearch-engine-example/lists"}