Over FlexForBelsimpel
Dit project is gebouwd als showcase voor mijn sollicitatie bij Belsimpel. Hieronder leg ik uit welke technologieën ik heb gebruikt en waarom, zodat je kunt zien hoe ik met jullie stack werk.
8
Docker services
11
Database tables
15+
GraphQL types
20+
React components
10+
Storybook stories
5000+
Lines of code
Backend
Backend: PHP 8.3 + Laravel 11
- Laravel 11's slim app structure — bootstrap/app.php replaces the old kernel classes
- Eloquent ORM with 8 models, proper relationships (belongsTo, hasMany, belongsToMany)
- Database migrations with foreign keys, indexes, and decimal precision for prices
- Seeders with realistic Dutch market data (25 phones, 18 plans, ~450 price combos)
- Model observers that dispatch queue jobs when data changes
- Event-driven architecture: PriceChanged event → HandlePriceChange listener → alert notifications
API
API: GraphQL with Lighthouse
- Schema-first approach: types and queries defined in .graphql files, not PHP code
- Split into domain files: phone.graphql, plan.graphql, wishlist.graphql, auth.graphql
- Custom resolvers for complex queries (search, compare, recommendations)
- Input types for filters with proper nullable fields
- Sanctum-based authentication for protected mutations (wishlist, price alerts)
Database
Database: MariaDB 11.2
- 8 domain tables + 3 job infrastructure tables
- Pivot table (phone_plans) with calculated pricing — monthly, upfront, and total costs
- Proper indexes on foreign keys and commonly filtered columns (slug, is_active)
- Decimal(8,2) for all money columns — never use floats for currency
- Europe/Amsterdam timezone matching Belsimpel's location
Infrastructure
Cache & Sessions: Redis 7.2
- Three separate Redis databases: default (0), cache (1), session (2)
- Query result caching with 5-minute TTL for search results
- 24-hour cache for recommendation queries (content doesn't change often)
- Session storage — faster than database sessions, supports horizontal scaling
- API rate limiting: 60 requests/minute for guests, 120 for authenticated users
Search
Search: Elasticsearch 8.12
- Two indices: flex_phones and flex_plans with explicit field mappings
- Multi-field matching with fuzziness for typo tolerance ('samung' → 'samsung')
- Faceted filters using Elasticsearch aggregations (brand, price range, storage)
- Bool queries combining must (search terms) + filter (exact matches) clauses
- Custom indexing commands with progress bars (php artisan es:index-phones)
Async
Message Queue: RabbitMQ 3.13
- Three named queues: search-sync, notifications, recommendations
- Automatic ES sync: phone/plan create/update/delete dispatches sync jobs
- Price alert notifications: price drop → find matching alerts → send emails
- Supervisord runs queue workers alongside PHP-FPM in the same container
- Management UI available at port 15672 for monitoring
Frontend
Frontend: React 18 + TypeScript + React Router v7
- React Router v7 in framework mode — the official successor to Remix v2
- Server-side rendering (SSR) — pages load with data, no loading spinners
- Loaders fetch data on the server before the component renders
- URL-driven state — all search filters stored in search params (shareable, bookmarkable)
- urql as the GraphQL client — ~5KB vs Apollo's ~30KB, perfect for SSR
Styling
Styling: CSS Modules + Design Tokens
- CSS Modules for component-scoped styles — no class name collisions
- CSS custom properties (variables) for the entire design system
- Belsimpel-inspired color palette: orange (#ff6b00) primary accent
- Consistent spacing scale, typography, shadows, and border radius
- No CSS framework — hand-written styles demonstrate CSS proficiency
Testing
Testing: Jest + PHPUnit
- PHPUnit for backend: model relationships, GraphQL queries, auth mutations
- Jest + Testing Library for frontend: component rendering, user interactions
- Storybook 8 for visual component testing and documentation
- Test isolation: array cache + sync queue driver in test environment
DevOps
Infrastructure: Docker Compose
- 8 interconnected services with health checks and dependency ordering
- Nginx reverse proxy: /graphql → PHP-FPM, everything else → Node SSR
- Volume mounts for hot-reloading in development
- Named network (flex-network) for service discovery
- GitLab CI/CD pipeline config with lint, test, build, and deploy stages
Interesse?
De volledige broncode is beschikbaar op GitLab. Ik sta open voor vragen over de architectuur, code, of mijn aanpak.
Chiril Ojoga — flexforbelsimpel.chirilojoga.com