# Laravel платформа и MySQL ## Телефон, фирми, условия и адреси на касите Телефонът е криптиран в потребителския профил, попълва се при регистрация или редакция на профила и не се въвежда при всяко добавяне на карта. За старите профили миграцията прехвърля наличния телефон от последната клиентска регистрация. В „Моят профил“ се пазят една или повече фирми за фактура. Задължителни са име, ЕИК (формат 9 или 13 цифри), град, адрес и държава България; ДДС номерът е по избор. Това е проверка на попълването и формата, не справка в Търговския регистър. Данните са криптирани и не се показват в търговския регистър на карти. Редакцията използва revision guard и запазва съществуващите карти и баланси. Собственикът публикува условия от „Общи условия“ в бизнес панела. Създаването на клиентски карти изисква изрично съгласие с актуалната версия; запазват се текстът, версията и моментът на приемане. При присъединяване се създава лична карта и по една фирмена карта за запазените фирми. Нова фирма получава карта при вече присъединените търговци с приети актуални условия. При променени условия нови фирмени карти се създават след повторно приемане. Съществуващи карти и точки не се премахват. Native клиентският endpoint за корпоративен профил вече изисква собствена запазена billing компания; оригиналният интеграционен OpenAPI/Worker договор е запазен. Всяка каса има адрес `/tills/{till_id}` и QR код в „Каси и покупки“. Същият адрес може да се запише в NFC таг. След вход се показват само собствените подходящи карти при търговеца на касата. Една карта се избира автоматично; при няколко клиентът избира. Изпращането към касата изисква действие от клиента, а отварянето на URL не създава покупка. Касите само с баркод показват карта за прочитане на номера. Стари фирмени карти без пълна свързана billing компания не се предлагат за нов native checkout. За реално сканиране от телефон адресът трябва да е достижим от устройството. Локалният Herd домейн `pushcard.test` не става автоматично публичен. QR кодовете се генерират локално и не изпращат URL или потребителски данни към външна услуга. Local fixtures: `php artisan db:seed --class=LocalDemoSeeder` adds five fictional businesses, eight tills and ten published offers lasting 30 days from the first run. It runs only in local/testing, preserves existing records and avoids duplicates. It creates no passwords or business memberships. Customers can discover these businesses and join their loyalty programmes. Локален адрес: http://pushcard.test. Herd обслужва Laravel 12/PHP 8.4. Работната база е MySQL `pushcard`; автоматичните MySQL тестове използват отделна `pushcard_testing`. SQLite in-memory остава за бързи тестове. Достъпът до базата е в `.env`, с отделен потребител, ограничен до тези две бази. ## Реализирани потоци - Клиентска регистрация и вход с парола, сървърна сесия, CSRF и ограничения за заявки. Имена и имейл на профилите са криптирани; търсене по имейл чрез HMAC. - Регистрация на търговец на `/business/register`, собствен портал, каса и регистрационен адрес `/app?join={merchant_id}`. Един потребител има лични карти и членства в един или повече бизнеси. `/business` избира или създава бизнес без нов профил; `/business/team` управлява служители със собствени профили. Собственикът управлява екип и ключове, управителят — промоции/точки/каси, касиерът — покупки. Съществуващите търговски профили са мигрирани като собственици. Старите `users.role`/`merchant_id` са съвместими полета и не дават права; единствен източник е `merchant_user`. - Лична карта чрез включване при търговец; корпоративни подпрофили и карти; отделен баланс и журнал на точки. - Криптирани контакти и фирмени данни. Търговецът получава само псевдонимни идентификатори, тип карта, маскиран номер, баланс и дати. - Каси, заявка за карта, приемане, сметка, финализиране, тестово плащане, неуспешен резултат и повторен опит. Клиентът следи състоянието чрез polling; POS действията и симулираният резултат са в търговския портал. - Промоции с период, аудитория, обекти, чернова/публикуване/спиране и ревизии. Активните предложения са видими при клиента. - Тестови push заявки: точна снимка на картите със съгласие към момента на заявката. Съобщението се показва в тестовата вътрешна кутия на клиента. `delivered_count` остава 0; FCM/APNs не са свързани. - Laravel `/api/v1` реализира съществуващите операции и JSON форми от OpenAPI. Tenant bearer ключовете се издават и отнемат само от собственика в удостоверения портал на съответния бизнес. Няма доверяване на Sites headers в Laravel. `/api/v1/keys` изисква удостоверена търговска сесия с CSRF и не позволява bearer администриране; браузърната конзола използва CSRF-защитен `/internal/merchant/keys`. Данните не се пазят в localStorage. Там остава само предпочитаната тема. Оригиналните прототипи и Node/Worker API остават отделни; `scripts/build-preview.mjs` продължава да използва прототипните Blade изгледи. Native порталът използва `live.blade.php` и `live-*.js`. ## Транзакции и защити Всяка записваща операция заключва реда на конкретния търговец в MySQL. Промяната, събитието, журналът на точки и идемпотентният отговор се записват в една транзакция. Повторение със същия ключ и тяло връща резултата; различно тяло връща 409. Browser ключовете са отделени по потребител; интеграционните ключове споделят tenant namespace. Уникален `points_ledger.payment_id` допълнително предотвратява двойно начисляване. Неуспешните операции не запазват частични записи. Контактните и корпоративните данни използват Laravel encryption чрез APP_KEY. Не сменяй ключа без контролирано прекриптиране на данните. Приложението не свързва автоматично стари интеграционни регистрации с нов акаунт само по съвпадащ имейл. ## Стартиране и проверка 1. `composer install` и `npm ci`. 2. Подготви `.env` с APP_KEY и MySQL достъпа. Създай MySQL базата и потребител с права само за нея. 3. `php artisan migrate --force` и `npm run build`. 4. `herd link pushcard --isolate=8.4`. 5. Регистрирай търговец през `/business/register`, или изпълни `php artisan pushcard:merchant {slug} {name} {email}` (паролата се въвежда скрито). 6. `php artisan test`. За отделната MySQL тестова база: `DB_CONNECTION=mysql DB_DATABASE=pushcard_testing php artisan test`. Никога не насочвай RefreshDatabase тестове към работната база. 7. `npm test` проверява оригиналния sandbox, не Laravel реализацията. При проверката са използвани временен фиктивен търговец `local-verification`, тестов клиент и покупки. След проверката тези записи и временните ключове са премахнати. Проверени са и едновременни HTTP потвърждения през Herd/MySQL със същия и с различни Idempotency-Key: за всяко плащане е създаден само един ledger запис. ## Оставащи външни интеграции Реален банков доставчик/IRIS/Open Banking, FCM/APNs, webhook доставка, координатно търсене, потвърждение на имейл, възстановяване на парола и production lifecycle/retention процедури. `/sandbox/payments/{id}/complete` е изрично симулация и трябва да остане недостъпен за бъдещи production ключове. Sites продължава да хоства само отделния Worker sandbox; няма промяна на неговата идентичност или audience. Native браузърните бизнес заявки посочват `X-Merchant-ID`, проверяван срещу членството, така че два отворени бизнеса не разменят нови записи при смяна на общата сесия. Екипните форми също са обвързани с конкретния бизнес. Премахване на членство отнема бизнес достъпа при следващата заявка, запазвайки личните карти. Добавяне на служител изисква съществуващ PushCard профил; автоматични имейл покани не се изпращат.