Wiki
This commit is contained in:
121
API-reference.md
Normal file
121
API-reference.md
Normal file
@@ -0,0 +1,121 @@
|
||||
# API Reference
|
||||
|
||||
Všechny API endpointy vyžadují `X-Site-Key` header nebo `?site_key=` parametr (ověření přes `ResolveTrackingSite` middleware).
|
||||
|
||||
---
|
||||
|
||||
## Browser Tracking API
|
||||
|
||||
Endpointy používané `collect.js` z prohlížeče.
|
||||
|
||||
### `POST /api/collect`
|
||||
Obecný tracking event (page_view, newsletter_subscribe, gallery_config_submit...).
|
||||
|
||||
```json
|
||||
{
|
||||
"visitor_id": "string (required)",
|
||||
"event": "string (required)",
|
||||
"payload": {},
|
||||
"occurred_at": "ISO 8601"
|
||||
}
|
||||
```
|
||||
|
||||
### `POST /api/identify`
|
||||
Identifikace návštěvníka (propojení visitor_id s emailem nebo ftclid tokenem).
|
||||
|
||||
```json
|
||||
{
|
||||
"visitor_id": "string",
|
||||
"email": "string (nebo ftclid)",
|
||||
"ftclid": "string",
|
||||
"name": "string",
|
||||
"user_id": "string"
|
||||
}
|
||||
```
|
||||
|
||||
### `GET /api/me`
|
||||
Vrátí informace o aktuálním návštěvníkovi (kontakt propojený s visitor_id).
|
||||
|
||||
### `POST /api/cart`
|
||||
Upsert košíku z prohlížeče.
|
||||
|
||||
```json
|
||||
{
|
||||
"visitor_id": "string",
|
||||
"event": "cart_upsert",
|
||||
"payload": {
|
||||
"cart_id": null,
|
||||
"cart": {
|
||||
"items": [{ "code": "...", "qty": 1, "unit_no_tax": 99 }],
|
||||
"totals": { "currency": "CZK", "total_no_tax": 99 }
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `POST /api/cart/complete`
|
||||
Dokončení košíku z prohlížeče.
|
||||
|
||||
```json
|
||||
{
|
||||
"visitor_id": "string",
|
||||
"event": "cart_completed",
|
||||
"payload": {
|
||||
"cart_id": 42,
|
||||
"order_id": "ORD-001",
|
||||
"total": 198.00,
|
||||
"currency": "CZK",
|
||||
"checkout": {
|
||||
"shipping_no_tax": 89,
|
||||
"shipping_label": "PPL",
|
||||
"cod_fee_no_tax": 29
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Eshop API (server-to-server)
|
||||
|
||||
Viz [Integrace Eshop API](Integrace-Eshop-API).
|
||||
|
||||
### `POST /api/eshop/cart`
|
||||
Košík z eshopu – párování podle emailu. Logováno do `eshop-YYYY-MM-DD.log`.
|
||||
|
||||
### `POST /api/eshop/order`
|
||||
Objednávka z eshopu – párování podle emailu.
|
||||
|
||||
---
|
||||
|
||||
## Integrace Webhooky
|
||||
|
||||
### `POST /api/integrations/smartemailing/webhook`
|
||||
Příjem webhooků ze SmartEmailing (odhlášení, události).
|
||||
|
||||
---
|
||||
|
||||
## Veřejné endpointy
|
||||
|
||||
### `GET /feeds/products.xml`
|
||||
XML produktový feed (`ProductFeedController`).
|
||||
|
||||
### `GET /e/o/{token}`
|
||||
Email open tracking pixel.
|
||||
|
||||
### `GET /email/u/{token}`
|
||||
Unsubscribe stránka z emailu.
|
||||
|
||||
### `GET /unsubscribe/{contact}` *(signed URL)*
|
||||
Globální odhlášení kontaktu.
|
||||
|
||||
---
|
||||
|
||||
## Chybové kódy
|
||||
|
||||
| HTTP | Situace |
|
||||
|------|---------|
|
||||
| 401 | Chybějící nebo neplatný Site Key |
|
||||
| 404 | Záznam nenalezen (cart_not_found...) |
|
||||
| 422 | Validační chyba – chybí povinné pole |
|
||||
| 500 | Serverová chyba |
|
||||
47
Admin.md
Normal file
47
Admin.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# Admin rozhraní
|
||||
|
||||
Admin UI je dostupné po přihlášení pod doménou `APP_MAIN_DOMAIN`. Postaveno na **Livewire 3** + **Tailwind CSS**.
|
||||
|
||||
## Navigace
|
||||
|
||||
| URL | Livewire komponenta / Controller | Popis |
|
||||
|-----|----------------------------------|-------|
|
||||
| `/dashboard` | `Admin\Dashboard` | Hlavní dashboard |
|
||||
| `/admin/live` | – | Live tracking |
|
||||
| `/admin/liveTracking` | `Admin\LiveTracking` | Real-time přehled návštěvníků |
|
||||
| `/admin/tracking-sites/{site}` | `Admin\TrackingSiteShow` | Nastavení tracking webu |
|
||||
| `/admin/siteCarts/{siteId}` | `Admin\CartsTable` | Přehled košíků |
|
||||
| `/admin/contacts` | `Admin\ContactsIndex` | Seznam kontaktů |
|
||||
| `/admin/contacts/{contact}` | `Admin\ContactShow` | Detail kontaktu |
|
||||
| `/admin/contacts/import` | `Admin\ContactsImportCsv` | Import CSV |
|
||||
| `/admin/companies` | `Admin\CompaniesIndex` | Seznam firem |
|
||||
| `/admin/companies/{company}` | `Admin\CompanyShow` | Detail firmy |
|
||||
| `/admin/phonebooks` | `Admin\PhonebooksBrowser` | Telefonní seznamy |
|
||||
| `/admin/funnel/segments` | `Admin\SegmentsIndex` | Správa segmentů |
|
||||
| `/admin/funnel/segments/{id}/columns` | `Admin\SegmentColumns` | Sloupce segmentu |
|
||||
| `/admin/funnel/segments/{id}/rules` | `Admin\SegmentRules` | Pravidla segmentu |
|
||||
| `/admin/funnel/segments/{id}/board` | `Admin\SegmentBoard` | Kanban board kontaktů |
|
||||
| `/admin/funnel/actions` | `Admin\ActionsIndex` | Seznam akcí |
|
||||
| `/admin/funnel/action-runs` | `Admin\ActionRunsIndex` | Historie spuštění akcí |
|
||||
| `/admin/funnel/automations` | `Admin\FunnelAutomations` | Editor automací |
|
||||
| `/admin/automations/{siteId}` | `Admin\AutomationsEditor` | Editor pro konkrétní web |
|
||||
| `/admin/funnel/email-campaigns` | `Admin\EmailCampaignsIndex` | Seznam kampaní |
|
||||
| `/admin/funnel/email-campaigns/{id}` | `Admin\EmailCampaignShow` | Detail kampaně |
|
||||
| `/admin/funnel/email-categories` | `Admin\EmailCategories` | Kategorie emailů |
|
||||
| `/admin/email-templates/editor/{id}` | `AdminEmailTemplateEditorController` | Editor šablon |
|
||||
| `/admin/integrations` | `Admin\IntegrationsIndex` | Přehled integrací |
|
||||
| `/admin/funnel/integrations/smtp` | `Admin\IntegrationsSmtp` | SMTP nastavení |
|
||||
| `/admin/mostVisitedCategories` | `Admin\MostVisitedCategories` | Nejnavštěvovanější kategorie |
|
||||
| `/admin/userFlow` | `Admin\UserFlow` | Tok uživatelů |
|
||||
| `/admin/configuratorFlow` | `Admin\ConfiguratorFlow` | Tok konfigurátoru |
|
||||
| `/admin/products/clicks` | `Admin\ProductClicks` | Kliky na produkty |
|
||||
| `/admin/vario/doklady` | `Admin\VarioDokladyController` | Vario doklady |
|
||||
| `/admin/ai-assistant` | `Admin\AdminAiConsole` | AI asistent (OpenAI) |
|
||||
|
||||
## Přihlášení a týmy
|
||||
|
||||
Autentizace přes **Laravel Jetstream**. Jeden uživatel může být členem více týmů (`Membership` model). Každý tým má vlastní data (multi-tenancy přes `team_id`).
|
||||
|
||||
## Notifikace
|
||||
|
||||
Interní notifikace přes `Notification` model. Zobrazeny v `Admin\NotificationsPanel`.
|
||||
69
Architektura.md
Normal file
69
Architektura.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# Architektura
|
||||
|
||||
## Technologický stack
|
||||
|
||||
| Vrstva | Technologie |
|
||||
|--------|-------------|
|
||||
| Framework | Laravel 12, PHP 8.2+ |
|
||||
| Frontend | Livewire 3, Tailwind CSS, Vite |
|
||||
| Autentizace | Laravel Jetstream + Sanctum |
|
||||
| Queue | Laravel Queue (databáze nebo Redis) |
|
||||
| Debugging | Laravel Telescope, Laravel Pulse |
|
||||
| Email | SMTP / Microsoft Graph |
|
||||
| Externí integrace | SmartEmailing API, Vario SOAP, PBX |
|
||||
|
||||
## Adresářová struktura
|
||||
|
||||
```
|
||||
app/
|
||||
├── Console/Commands/ # Artisan příkazy (sync, rebuild, backfill...)
|
||||
├── Http/
|
||||
│ ├── Controllers/
|
||||
│ │ ├── Api/Tracking/ # Browser tracking endpointy
|
||||
│ │ ├── Api/Eshop/ # Server-to-server eshop endpointy
|
||||
│ │ └── Admin/ # Web admin controllery
|
||||
│ └── Middleware/
|
||||
│ ├── ResolveTrackingSite # Ověření X-Site-Key
|
||||
│ ├── CorsForTracking # CORS pro tracking API
|
||||
│ └── LogEshopRequest # Logování eshop requestů
|
||||
├── Jobs/ # Background joby (queue)
|
||||
├── Livewire/Admin/ # Livewire komponenty admin UI
|
||||
├── Models/ # Eloquent modely
|
||||
├── Services/
|
||||
│ ├── Actions/ # ActionRunner + drivery akcí
|
||||
│ ├── Ai/ # OpenAI integrace
|
||||
│ ├── Funnel/ # RulesEngine, FunnelAssigner
|
||||
│ ├── GeoIP/ # Geo-lookup
|
||||
│ ├── Ingest/ # IngestEvent pipeline
|
||||
│ ├── Integrations/ # SmartEmailing klient
|
||||
│ ├── Tracking/ # IdentityLinker, CategoryTree, BotDetector...
|
||||
│ └── Vario/ # Vario SOAP sync
|
||||
public/
|
||||
└── collect.js # Tracking skript pro weby/eshopy
|
||||
routes/
|
||||
├── api.php # API endpointy
|
||||
└── web.php # Admin web rozhraní
|
||||
```
|
||||
|
||||
## Klíčové modely
|
||||
|
||||
| Model | Tabulka | Popis |
|
||||
|-------|---------|-------|
|
||||
| `Contact` | `contacts` | Identifikovaný zákazník/návštěvník |
|
||||
| `FunnelCart` | `funnel_carts` | Nákupní košík |
|
||||
| `FunnelEvent` | `funnel_events` | Každá trackovací událost |
|
||||
| `FunnelRule` | `funnel_rules` | Pravidlo automace (trigger + podmínky) |
|
||||
| `FunnelAction` | `funnel_actions` | Akce spouštěná pravidlem |
|
||||
| `FunnelState` | `funnel_states` | Aktuální stav kontaktu v segmentu/sloupci |
|
||||
| `Segment` | `segments` | Skupina kontaktů s vlastními pravidly |
|
||||
| `FunnelColumn` | `funnel_columns` | Sloupec (stav) v segmentu |
|
||||
| `EmailCampaign` | `email_campaigns` | Emailová kampaň |
|
||||
| `EmailCampaignSend` | `email_campaign_sends` | Jeden plánovaný email send |
|
||||
| `EmailTemplate` | `email_templates` | Šablona emailu |
|
||||
| `TrackingSite` | `tracking_sites` | Web/eshop identifikovaný Site Key |
|
||||
| `TrackingProduct` | `tracking_products` | Produkt zaznamenaný z košíků |
|
||||
| `VisitorIdentity` | `visitor_identities` | Mapping visitor_id → contact_id |
|
||||
|
||||
## Multi-tenancy
|
||||
|
||||
Aplikace je multi-tenant přes `team_id`. Každý tým má vlastní kontakty, segmenty, kampaně a tracking sites. Autentizace týmů probíhá přes Laravel Jetstream.
|
||||
98
Automations.md
Normal file
98
Automations.md
Normal file
@@ -0,0 +1,98 @@
|
||||
# Automations a Funnel
|
||||
|
||||
## Přehled
|
||||
|
||||
Automační systém reaguje na eventy a pohybuje kontakty mezi stavy (sloupci) v segmentu. Při přechodu do nového sloupce se spouštějí akce (email, webhook, tag...).
|
||||
|
||||
```
|
||||
FunnelEvent
|
||||
│
|
||||
▼
|
||||
RulesEngine.evaluate()
|
||||
│
|
||||
├─ Projde FunnelRule záznamy pro aktivní segmenty kontaktu
|
||||
├─ Vyhodnotí podmínky (when_event, conditions)
|
||||
└─ Pokud pravidlo platí → FunnelState přesune kontakt do target_column
|
||||
│
|
||||
▼
|
||||
RunFunnelActionsJob
|
||||
│
|
||||
▼
|
||||
FunnelAction → ActionRunner → Driver
|
||||
```
|
||||
|
||||
## Klíčové třídy
|
||||
|
||||
| Třída | Popis |
|
||||
|-------|-------|
|
||||
| `RulesEngine` | Vyhodnocuje pravidla pro daný event a kontakt |
|
||||
| `FunnelAssigner` | Přiřazuje kontakt do segmentu (vytváří FunnelState) |
|
||||
| `ActionRunner` | Spouští akce pro daný FunnelState |
|
||||
| `DriverFactory` | Vrací správný driver podle typu akce |
|
||||
|
||||
## Modely
|
||||
|
||||
### FunnelRule
|
||||
Pravidlo triggeru a přechodu.
|
||||
|
||||
| Pole | Popis |
|
||||
|------|-------|
|
||||
| `segment_id` | Ke kterému segmentu patří |
|
||||
| `when_event` | Event který pravidlo triggeruje (např. `cart_upsert`) |
|
||||
| `conditions` | JSON podmínky (payload hodnoty, tagy...) |
|
||||
| `target_column_id` | Cílový sloupec po splnění pravidla |
|
||||
| `apply_once` | Aplikovat jen jednou na kontakt |
|
||||
| `priority` | Pořadí vyhodnocení |
|
||||
|
||||
### FunnelAction
|
||||
Akce spouštěná při přechodu do sloupce.
|
||||
|
||||
| Pole | Popis |
|
||||
|------|-------|
|
||||
| `segment_id` | Příslušný segment |
|
||||
| `column_id` | Sloupec který spouští akci |
|
||||
| `trigger` | `on_enter` / `on_exit` / `scheduled` |
|
||||
| `type` | Typ akce (viz níže) |
|
||||
| `config` | JSON konfigurace akce |
|
||||
| `throttle` | Omezení frekvence spuštění |
|
||||
|
||||
### FunnelState
|
||||
Aktuální pozice kontaktu v segmentu.
|
||||
|
||||
| Pole | Popis |
|
||||
|------|-------|
|
||||
| `contact_id` | Kontakt |
|
||||
| `segment_id` | Segment |
|
||||
| `column_id` | Aktuální sloupec |
|
||||
|
||||
## Typy akcí (Drivers)
|
||||
|
||||
| Typ | Driver | Popis |
|
||||
|-----|--------|-------|
|
||||
| `send_mail` | `SendMailDriver` | Odeslání emailu |
|
||||
| `set_tag` | `SetTagDriver` | Přidání tagu kontaktu |
|
||||
| `set_flag` | `SetFlagDriver` | Nastavení příznaku |
|
||||
| `move_to_column` | `MoveToColumnDriver` | Přesun do jiného sloupce |
|
||||
| `webhook` | `WebhookDriver` | HTTP webhook |
|
||||
| `slack` | `SlackDriver` | Slack notifikace |
|
||||
| `notify` | `NotifyDriver` | Interní notifikace |
|
||||
| `internal_note` | `InternalNoteDriver` | Poznámka ke kontaktu |
|
||||
| `smartemailing_sync` | `SmartEmailingAddToListDriver` | Přidání do SmartEmailing listu |
|
||||
| `smartemailing_add_tag` | `SmartEmailingAddTagDriver` | Tag v SmartEmailing |
|
||||
| `smartemailing_unsubscribe` | `SmartEmailingUnsubscribeDriver` | Odhlášení v SmartEmailing |
|
||||
|
||||
## Placeholders v akcích
|
||||
|
||||
`PlaceholderReplacer` nahrazuje `{{contact.email}}`, `{{contact.name}}` apod. v textech akcí.
|
||||
|
||||
## Replay
|
||||
|
||||
Command `FunnelReplaySegment` / job `ReplaySegmentAutomationsJob` přehraje eventy pro všechny kontakty v segmentu – užitečné při změně pravidel.
|
||||
|
||||
## Inaktivita
|
||||
|
||||
Command `FunnelEvaluateInactivity` / job `FunnelInactivityJob` spouští pravidla pro kontakty které dlouho nevykazovaly aktivitu.
|
||||
|
||||
## Naplánované akce
|
||||
|
||||
`FunnelScheduledAction` – akce naplánované do budoucnosti (např. "pošli email za 3 dny"). Zpracovává `RunScheduledFunnelActionJob`.
|
||||
67
Email-kampane.md
Normal file
67
Email-kampane.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# Email kampaně
|
||||
|
||||
## Přehled
|
||||
|
||||
Systém podporuje hromadné emailové kampaně s plánováním, schvalováním, sledováním otevření a kliků.
|
||||
|
||||
## Klíčové modely
|
||||
|
||||
| Model | Tabulka | Popis |
|
||||
|-------|---------|-------|
|
||||
| `EmailCampaign` | `email_campaigns` | Definice kampaně |
|
||||
| `EmailCampaignSend` | `email_campaign_sends` | Jeden naplánovaný email jednomu příjemci |
|
||||
| `EmailTemplate` | `email_templates` | HTML šablona emailu |
|
||||
| `EmailCategory` | `email_categories` | Kategorie (pro odhlašování per kategorie) |
|
||||
| `EmailCategoryUnsubscribe` | – | Odhlášení z konkrétní kategorie |
|
||||
| `ContactCampaignStat` | – | Statistiky kampaně per kontakt |
|
||||
| `CampaignEventStat` | – | Agregované statistiky eventů |
|
||||
| `CampaignCartDailyStat` | – | Denní statistiky košíků per kampaň |
|
||||
|
||||
## Životní cyklus kampaně
|
||||
|
||||
```
|
||||
1. Vytvoření kampaně (EmailCampaign)
|
||||
2. Výběr segmentu + šablony
|
||||
3. Naplánování (schedule) nebo odeslání ihned (send-now)
|
||||
4. PrepareEmailCampaignSendsJob → vytvoří EmailCampaignSend záznamy
|
||||
5. Schválení (approval workflow)
|
||||
6. BatchSendEmailCampaignSendsJob → SendEmailCampaignSendJob → odeslání
|
||||
7. Tracking otevření (pixel /e/o/{token})
|
||||
8. Tracking kliků (ftclid parametr v odkazech)
|
||||
```
|
||||
|
||||
## Odesílání
|
||||
|
||||
Kampaně odesílá command `SendDueEmailCampaigns` (cron). Selhat může přes `RetryFailedEmailCampaignSends`.
|
||||
|
||||
Podporované mail drivery:
|
||||
- **SMTP** – standardní Laravel mailer
|
||||
- **Microsoft Graph** – `MicrosoftGraphMailService` (přes Microsoft 365 API)
|
||||
|
||||
## Šablony
|
||||
|
||||
Editor šablon je dostupný na `/admin/email-templates/editor/{id}`. Šablony podporují:
|
||||
- HTML s inline CSS (`tijsverkoyen/css-to-inline-styles`)
|
||||
- Placeholdery (`{{contact.email}}`, `{{contact.name}}` apod.)
|
||||
- Unsubscribe link
|
||||
|
||||
## Tracking
|
||||
|
||||
- **Otevření** – 1×1px tracking pixel `/e/o/{token}` → `EmailOpenTrackingController`
|
||||
- **Kliky** – `ftclid` parametr v odkazech; při kliknutí `collect.js` automaticky identifikuje návštěvníka a propojí ho s kontaktem
|
||||
|
||||
## Schvalování
|
||||
|
||||
Před odesláním může být vyžadováno schválení přes `EmailSendApprovalController`:
|
||||
- `GET /email-sends/pending` – seznam čekajících
|
||||
- `POST /email-sends/{send}/approve` – schválení
|
||||
- `POST /email-sends/{send}/reject` – zamítnutí
|
||||
|
||||
## Statistiky
|
||||
|
||||
Rebuild statistik:
|
||||
```bash
|
||||
php artisan rebuild:campaign-event-stats
|
||||
php artisan rebuild:campaign-cart-daily-stats
|
||||
php artisan rebuild:contact-campaign-stats
|
||||
```
|
||||
43
Home.md
Normal file
43
Home.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# Home – Funnel-1 Wiki
|
||||
|
||||
**Funnel-1** je interní marketing automation & CRM platforma postavená na Laravel 12. Slouží ke sledování chování návštěvníků na webech a eshopech, správě kontaktů, segmentaci, automatizaci emailových kampaní a integraci s externími systémy.
|
||||
|
||||
---
|
||||
|
||||
## Obsah wiki
|
||||
|
||||
| Stránka | Popis |
|
||||
|-----------------------------------------------|-------|
|
||||
| [Architektura.](Architektura.md) | Přehled technologií, vrstev a klíčových modulů |
|
||||
| [Instalace a spuštění](Instalace.md) | Jak projekt lokálně rozběhnout |
|
||||
| [Tracking systém](Tracking.md) | Jak funguje sledování návštěvníků přes `collect.js` |
|
||||
| [Košíky](Kosiky.md) | FunnelCart – sledování a konverze košíků |
|
||||
| [Integrace eshop API](Integrace-Eshop-API.md) | Server-to-server API pro eshopy (email-based) |
|
||||
| [Kontakty a CRM](Kontakty.md) | Contact model, identifikace, segmenty |
|
||||
| [Automations a Funnel](Automations.md) | RulesEngine, FunnelRule, FunnelAction |
|
||||
| [Email kampaně](Email-kampane.md) | Tvorba, odesílání a tracking emailů |
|
||||
| [Integrace](Integrace.md) | SmartEmailing, Vario, PBX, Microsoft Graph |
|
||||
| [API reference](API-reference.md) | Přehled všech API endpointů |
|
||||
| [Admin rozhraní](Admin.md) | Přehled Livewire admin sekcí |
|
||||
| [Jobs a Cron](Jobs-Cron.md) | Background joby a scheduled tasky |
|
||||
| [Logování](Logovani.md) | Log kanály a co se kde loguje |
|
||||
|
||||
---
|
||||
|
||||
## Rychlý přehled
|
||||
|
||||
```
|
||||
Eshop / web
|
||||
│
|
||||
├─ collect.js (browser tracking)
|
||||
│ └─ POST /api/collect, /api/cart, /api/identify
|
||||
│
|
||||
└─ Server-to-server (PHP backend eshopu)
|
||||
└─ POST /api/eshop/cart, /api/eshop/order
|
||||
│
|
||||
▼
|
||||
[ FunnelEvent ] ──► [ RulesEngine ] ──► [ FunnelAction ]
|
||||
│
|
||||
▼
|
||||
[ Contact ] ──► [ Segment ] ──► [ EmailCampaign ]
|
||||
```
|
||||
85
Instalace.md
Normal file
85
Instalace.md
Normal file
@@ -0,0 +1,85 @@
|
||||
# Instalace a spuštění
|
||||
|
||||
## Požadavky
|
||||
|
||||
- PHP 8.2+
|
||||
- Composer
|
||||
- Node.js 18+
|
||||
- MySQL / PostgreSQL
|
||||
- (volitelně) Redis pro queue
|
||||
|
||||
## Rychlá instalace
|
||||
|
||||
```bash
|
||||
composer install
|
||||
cp .env.example .env
|
||||
php artisan key:generate
|
||||
php artisan migrate
|
||||
npm install
|
||||
npm run build
|
||||
```
|
||||
|
||||
Nebo přes composer script:
|
||||
|
||||
```bash
|
||||
composer setup
|
||||
```
|
||||
|
||||
## Vývoj (dev server)
|
||||
|
||||
Spustí paralelně: PHP server, queue worker, Pail log viewer a Vite hot-reload:
|
||||
|
||||
```bash
|
||||
composer dev
|
||||
```
|
||||
|
||||
## Klíčové .env proměnné
|
||||
|
||||
```env
|
||||
APP_URL=https://app.domena.cz
|
||||
APP_MAIN_DOMAIN=app.domena.cz
|
||||
APP_TOR_UNSUB_DOMAIN=unsub.domena.cz
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_DATABASE=funnel
|
||||
|
||||
QUEUE_CONNECTION=database # nebo redis
|
||||
|
||||
# Email
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=...
|
||||
MAIL_FROM_ADDRESS=...
|
||||
|
||||
# Microsoft Graph (alternativní mailer)
|
||||
MICROSOFT_GRAPH_TENANT_ID=...
|
||||
MICROSOFT_GRAPH_CLIENT_ID=...
|
||||
MICROSOFT_GRAPH_CLIENT_SECRET=...
|
||||
|
||||
# SmartEmailing
|
||||
SMARTEMAILING_API_URL=...
|
||||
SMARTEMAILING_API_KEY=...
|
||||
|
||||
# GeoIP
|
||||
GEOIP_DATABASE_PATH=...
|
||||
|
||||
# Logging
|
||||
LOG_CHANNEL=stack
|
||||
LOG_LEVEL=info
|
||||
```
|
||||
|
||||
## Spuštění queue workera
|
||||
|
||||
```bash
|
||||
php artisan queue:listen --tries=1
|
||||
# nebo
|
||||
php artisan queue:work
|
||||
```
|
||||
|
||||
## Scheduled tasks (cron)
|
||||
|
||||
Přidat do crontabu serveru:
|
||||
|
||||
```cron
|
||||
* * * * * cd /path/to/project && php artisan schedule:run >> /dev/null 2>&1
|
||||
```
|
||||
138
Integrace-Eshop-API.md
Normal file
138
Integrace-Eshop-API.md
Normal file
@@ -0,0 +1,138 @@
|
||||
# Integrace Eshop API
|
||||
|
||||
Server-to-server integrace pro eshopy. Eshop posílá data přímo ze svého backendu – párování probíhá podle e-mailu zákazníka, **žádný browser tracking není potřeba**.
|
||||
|
||||
Podrobná dokumentace pro programátora eshopu je v [`docs/integrace-eshop.md`](../docs/integrace-eshop.md).
|
||||
|
||||
---
|
||||
|
||||
## Autentizace
|
||||
|
||||
Každý request musí obsahovat Site Key:
|
||||
|
||||
```
|
||||
X-Site-Key: <site-key>
|
||||
# nebo
|
||||
?site_key=<site-key>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Endpointy
|
||||
|
||||
### `POST /api/eshop/cart` – Stav košíku
|
||||
|
||||
Volejte při každé změně košíku. Párování probíhá podle `email`.
|
||||
|
||||
```json
|
||||
{
|
||||
"email": "zakaznik@example.cz",
|
||||
"currency": "CZK",
|
||||
"total_no_tax": 198.00,
|
||||
"cart_id": null,
|
||||
"items": [
|
||||
{
|
||||
"code": "PROD-001",
|
||||
"name": "Název produktu",
|
||||
"qty": 2,
|
||||
"unit_no_tax": 99.00,
|
||||
"total_no_tax": 198.00,
|
||||
"url": "https://eshop.cz/produkt"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Odpověď:**
|
||||
```json
|
||||
{ "ok": true, "cart_id": 42, "status": "open", "changed": true }
|
||||
```
|
||||
|
||||
Logika controlleru `EshopCartController`:
|
||||
1. Najde nebo vytvoří `Contact` podle emailu
|
||||
2. Hledá poslední otevřený košík pro daný kontakt
|
||||
3. Porovná obsah (hash z items + currency + total) – pokud se nezměnil, jen obnoví `last_seen_at`
|
||||
4. Uloží/aktualizuje `FunnelCart`, upsertuje `TrackingProduct` záznamy
|
||||
5. Zapiše `FunnelEvent` (event `cart_upsert`, source `eshop`)
|
||||
|
||||
---
|
||||
|
||||
### `POST /api/eshop/order` – Dokončení objednávky
|
||||
|
||||
Volejte jednorázově při úspěšném dokončení.
|
||||
|
||||
```json
|
||||
{
|
||||
"email": "zakaznik@example.cz",
|
||||
"cart_id": 42,
|
||||
"order_id": "ORD-2026-0042",
|
||||
"total_no_tax": 198.00,
|
||||
"currency": "CZK",
|
||||
"checkout": {
|
||||
"shipping_no_tax": 89.00,
|
||||
"shipping_label": "PPL",
|
||||
"cod_fee_no_tax": 29.00
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Odpověď:**
|
||||
```json
|
||||
{ "ok": true, "cart_id": 42, "order_id": "ORD-2026-0042", "status": "converted" }
|
||||
```
|
||||
|
||||
Logika controlleru `EshopOrderController`:
|
||||
1. Najde kontakt podle emailu
|
||||
2. Hledá košík – podle `cart_id`, nebo poslední `open`/`empty` pro daný kontakt
|
||||
3. Pokud košík nenajde → `404 cart_not_found`
|
||||
4. Uloží data objednávky, status → `converted`
|
||||
5. Zapiše `FunnelEvent` (event `cart_completed`, source `eshop`)
|
||||
|
||||
---
|
||||
|
||||
## Logování
|
||||
|
||||
Všechny requesty na `/api/eshop/*` jsou logovány do `storage/logs/eshop-YYYY-MM-DD.log` přes middleware `LogEshopRequest`. E-mail je maskován (`za***@example.cz`).
|
||||
|
||||
---
|
||||
|
||||
## Chybové stavy
|
||||
|
||||
| HTTP | Kód | Řešení |
|
||||
|------|-----|--------|
|
||||
| 401 | – | Chybný nebo chybějící Site Key |
|
||||
| 422 | – | Chybí povinné pole |
|
||||
| 404 | `cart_not_found` | Žádný otevřený košík pro daný email |
|
||||
|
||||
---
|
||||
|
||||
## PHP příklad
|
||||
|
||||
```php
|
||||
// Při změně košíku
|
||||
$res = Http::withHeaders(['X-Site-Key' => config('tracking.site_key')])
|
||||
->post('https://app.domena.cz/api/eshop/cart', [
|
||||
'email' => $customer->email,
|
||||
'currency' => 'CZK',
|
||||
'total_no_tax' => $cart->totalNoTax(),
|
||||
'cart_id' => session('ft_cart_id'),
|
||||
'items' => $cart->items->map(fn($i) => [
|
||||
'code' => $i->sku,
|
||||
'name' => $i->name,
|
||||
'qty' => $i->qty,
|
||||
'unit_no_tax' => $i->unitPriceNoTax,
|
||||
])->toArray(),
|
||||
]);
|
||||
|
||||
session(['ft_cart_id' => $res->json('cart_id')]);
|
||||
|
||||
// Při dokončení
|
||||
Http::withHeaders(['X-Site-Key' => config('tracking.site_key')])
|
||||
->post('https://app.domena.cz/api/eshop/order', [
|
||||
'email' => $customer->email,
|
||||
'cart_id' => session('ft_cart_id'),
|
||||
'order_id' => $order->id,
|
||||
'total_no_tax' => $order->totalNoTax(),
|
||||
'currency' => 'CZK',
|
||||
]);
|
||||
```
|
||||
83
Integrace.md
Normal file
83
Integrace.md
Normal file
@@ -0,0 +1,83 @@
|
||||
# Integrace
|
||||
|
||||
## SmartEmailing
|
||||
|
||||
CRM/mailing systém SmartEmailing.
|
||||
|
||||
**Klient:** `App\Services\Integrations\SmartEmailingClient`
|
||||
|
||||
**Synchronizace kontaktů:** `SmartEmailingContactsSyncService`
|
||||
|
||||
**Akce z automací:**
|
||||
- `SmartEmailingAddToListDriver` – přidání kontaktu do listu
|
||||
- `SmartEmailingAddTagDriver` – přidání tagu
|
||||
- `SmartEmailingUnsubscribeDriver` – odhlášení kontaktu
|
||||
|
||||
**Webhook příjem:** `POST /api/integrations/smartemailing/webhook` → `SmartEmailingWebhookController`
|
||||
|
||||
**Healthcheck:** `SmartEmailingHealthcheck` – kontrola dostupnosti API
|
||||
|
||||
---
|
||||
|
||||
## Vario ERP
|
||||
|
||||
ERP systém pro správu firem, kontaktů, kategorií a produktů. Komunikace přes **SOAP**.
|
||||
|
||||
**Klient:** `App\Services\Vario\VarioSoapClient`
|
||||
|
||||
**Sync commandy:**
|
||||
|
||||
| Command | Popis |
|
||||
|---------|-------|
|
||||
| `vario:sync` | Master sync (spouští ostatní) |
|
||||
| `vario:sync-contacts` | Sync kontaktů |
|
||||
| `vario:sync-companies` | Sync firem |
|
||||
| `vario:sync-categories` | Sync kategorií produktů |
|
||||
| `vario:sync-phonebooks` | Sync telefonních seznamů |
|
||||
| `vario:sync-product` | Sync jednotlivého produktu |
|
||||
|
||||
**Klíčové třídy:**
|
||||
- `VarioImporter` – orchestrace importu
|
||||
- `VarioContactMapper` / `VarioCompanyMapper` – mapování polí
|
||||
- `VarioSnapshotBuilder` – snapshot dat pro porovnání změn
|
||||
- `VarioDatapackParser` – parsování datapaku ze SOAP odpovědi
|
||||
|
||||
**Admin UI:** `/admin/vario/doklady` – prohlížení a parsování Vario dokladů
|
||||
|
||||
---
|
||||
|
||||
## PBX (telefonní ústředna)
|
||||
|
||||
**Klient:** `App\Services\Pbx\PbxClient`
|
||||
|
||||
**Telefonní seznamy:** `Phonebook`, `PhonebookEntry`, `PhonebookContact` modely
|
||||
|
||||
**Sync:** `PushPhonebookToPbxJob` – nahraje telefonní seznam do PBX
|
||||
|
||||
**Admin UI:** `/admin/phonebooks` – prohlížeč telefonních seznamů
|
||||
|
||||
---
|
||||
|
||||
## Microsoft Graph (Email)
|
||||
|
||||
Alternativní odesílač emailů přes Microsoft 365 API.
|
||||
|
||||
**Service:** `App\Services\MicrosoftGraph\MicrosoftGraphMailService`
|
||||
|
||||
**Konfigurace v .env:**
|
||||
```env
|
||||
MICROSOFT_GRAPH_TENANT_ID=
|
||||
MICROSOFT_GRAPH_CLIENT_ID=
|
||||
MICROSOFT_GRAPH_CLIENT_SECRET=
|
||||
MICROSOFT_GRAPH_FROM_ADDRESS=
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Logování integrací
|
||||
|
||||
Všechny integrace logují výsledky do `IntegrationLog` (`integration_logs` tabulka). Přehled dostupný v admin UI na `/admin/integrations/logs/{log}`.
|
||||
|
||||
`IntegrationLogger` je helper pro jednotné logování úspěchů a chyb.
|
||||
|
||||
Stav integrace (poslední sync, chyby) ukládá `IntegrationState` model.
|
||||
75
Jobs-Cron.md
Normal file
75
Jobs-Cron.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# Jobs a Cron
|
||||
|
||||
## Artisan Commands (Scheduled Tasks)
|
||||
|
||||
Příkazy spouštěné přes `php artisan schedule:run` (cron každou minutu).
|
||||
|
||||
| Command | Popis |
|
||||
|---------|-------|
|
||||
| `SendDueEmailCampaigns` | Odesílá naplánované emailové kampaně |
|
||||
| `RetryFailedEmailCampaignSends` | Opakuje selhaná odeslání emailů |
|
||||
| `ExpireFunnelCarts` | Označí staré otevřené košíky jako `expired` |
|
||||
| `FunnelEvaluateInactivity` | Vyhodnotí pravidla pro neaktivní kontakty |
|
||||
| `FunnelReplaySegment` | Přehraje eventy pro kontakty v segmentu |
|
||||
| `VarioSync` | Master sync z Vario ERP |
|
||||
| `VarioSyncContacts` | Sync kontaktů z Vario |
|
||||
| `VarioSyncCompanies` | Sync firem z Vario |
|
||||
| `VarioSyncCategories` | Sync kategorií z Vario |
|
||||
| `VarioSyncPhonebooks` | Sync telefonních seznamů z Vario |
|
||||
| `VarioSyncProduct` | Sync jednoho produktu z Vario |
|
||||
| `SyncFunnelEventTypes` | Synchronizuje typy funnel eventů |
|
||||
| `DashboardIngestEvents` | Ingestuje events pro dashboard |
|
||||
| `DashboardBackfill` | Backfill dat pro dashboard |
|
||||
|
||||
## Rebuild Commands (manuální)
|
||||
|
||||
| Command | Popis |
|
||||
|---------|-------|
|
||||
| `RebuildCampaignCartDailyStats` | Přepočítá denní košíkové statistiky per kampaň |
|
||||
| `RebuildProductGroupCartDailyStats` | Přepočítá košíkové statistiky per produktová skupina |
|
||||
| `RebuildCampaignEventStats` | Přepočítá event statistiky kampaní |
|
||||
| `RebuildContactCampaignStats` | Přepočítá statistiky kampaní per kontakt |
|
||||
| `BackfillFunnelCarts` | Backfill chybějících dat košíků |
|
||||
| `BackfillFunnelEventContacts` | Backfill `contact_id` u starých eventů |
|
||||
| `BackfillFunnelEventBots` | Backfill bot flag u starých eventů |
|
||||
| `GenerateDataBuilderConfig` | Generuje konfiguraci pro DataBuilder (AI) |
|
||||
|
||||
## Queue Jobs
|
||||
|
||||
Joby zpracovávané na pozadí přes Laravel Queue.
|
||||
|
||||
| Job | Popis |
|
||||
|-----|-------|
|
||||
| `RunFunnelActionsJob` | Spustí akce pro daný FunnelState |
|
||||
| `RunFunnelActionByIdJob` | Spustí konkrétní akci |
|
||||
| `RunActionByIdJob` | Spustí akci podle ID |
|
||||
| `RunScheduledFunnelActionJob` | Spustí naplánovanou akci |
|
||||
| `FunnelInactivityJob` | Zpracuje inaktivitu kontaktu |
|
||||
| `ReplaySegmentAutomationsJob` | Přehraje automace pro segment |
|
||||
| `ExpireFunnelCartsJob` | Expiruje košíky |
|
||||
| `PrepareEmailCampaignSendsJob` | Připraví send záznamy pro kampaň |
|
||||
| `PrepareEmailCampaignSendJob` | Připraví jeden send |
|
||||
| `BatchSendEmailCampaignSendsJob` | Hromadné odesílání emailů |
|
||||
| `SendEmailCampaignSendJob` | Odeslání jednoho emailu |
|
||||
| `RetryFailedEmailCampaignSendsJob` | Retry selhaných emailů |
|
||||
| `QueueEmailCampaignSendsFromCsvJob` | Načte příjemce z CSV do fronty |
|
||||
| `SyncVarioContactsJob` | Async sync Vario kontaktů |
|
||||
| `SyncVarioProductCategoryJob` | Async sync Vario kategorií |
|
||||
| `VarioSyncJob` | Async master Vario sync |
|
||||
| `VarioHealthcheckJob` | Healthcheck Vario připojení |
|
||||
| `PushPhonebookToPbxJob` | Nahrání telefonního seznamu do PBX |
|
||||
| `BackfillFunnelEventContactsJob` | Async backfill contact_id |
|
||||
| `RebuildCampaignEventStatsJob` | Async rebuild statistik |
|
||||
| `RebuildCampaignCartDailyStatsJob` | Async rebuild košíkových statistik |
|
||||
| `RebuildContactCampaignStatsJob` | Async rebuild statistik per kontakt |
|
||||
| `RebuildProductGroupCartDailyStatsJob` | Async rebuild produktových statistik |
|
||||
|
||||
## Spuštění queue workera
|
||||
|
||||
```bash
|
||||
# vývoj
|
||||
php artisan queue:listen --tries=1
|
||||
|
||||
# produkce
|
||||
php artisan queue:work --tries=3 --sleep=3 --timeout=90
|
||||
```
|
||||
69
Kontakty.md
Normal file
69
Kontakty.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# Kontakty a CRM
|
||||
|
||||
## Model Contact
|
||||
|
||||
`App\Models\Contact` – tabulka `contacts`
|
||||
|
||||
| Sloupec | Typ | Popis |
|
||||
|---------|-----|-------|
|
||||
| `id` | bigint | PK |
|
||||
| `team_id` | bigint | Příslušnost k týmu |
|
||||
| `email` | string | E-mail (unikátní per team) |
|
||||
| `name` | string | Celé jméno |
|
||||
| `phone` | string | Telefon |
|
||||
| `source` | string | Zdroj (`web`, `eshop`, `import`...) |
|
||||
| `user_id` | string | ID zákazníka v externím systému |
|
||||
| `tags` | json | Pole tagů |
|
||||
| `flags` | json | Slovník příznaků (user_id, kampaně...) |
|
||||
| `traits` | json | Vlastnosti kontaktu |
|
||||
| `meta` | json | Libovolná metadata |
|
||||
| `identify_token` | string | Token pro identifikaci z emailového odkazu |
|
||||
| `last_activity_at` | timestamp | Poslední aktivita |
|
||||
| `email_opt_out_at` | timestamp | Datum odhlášení z emailů |
|
||||
| `internal` | boolean | Interní kontakt (nezapočítává se do statistik) |
|
||||
| `smartemailing_id` | int | ID v SmartEmailing |
|
||||
| `vario_ids` | json | ID záznamu v Vario ERP |
|
||||
|
||||
## Identifikace (IdentityLinker)
|
||||
|
||||
`App\Services\Tracking\IdentityLinker` zajišťuje propojení anonymního `visitor_id` s `Contact`:
|
||||
|
||||
```
|
||||
visitor_id ──► visitor_identities ──► contact_id
|
||||
```
|
||||
|
||||
### Metody
|
||||
|
||||
- **`identify($teamId, $data)`** – párování podle emailu; vytvoří kontakt pokud neexistuje; backfilluje `contact_id` ke starším eventům
|
||||
- **`identifyByToken($teamId, $data)`** – párování přes `ftclid` (click token z emailové kampaně); dohledá `EmailCampaignSend` → `Contact`
|
||||
- **`contactIdForVisitor($teamId, $visitorId)`** – rychlý lookup mapping
|
||||
|
||||
## Segmenty
|
||||
|
||||
`Segment` sdružuje kontakty do skupiny. Každý segment má:
|
||||
- **`FunnelColumn`** – sloupce (stavy), ve kterých se kontakt nachází (Kanban-style)
|
||||
- **`FunnelRule`** – pravidla pro přechod mezi sloupci
|
||||
- **`FunnelState`** – aktuální stav konkrétního kontaktu v segmentu
|
||||
|
||||
## Tagy
|
||||
|
||||
Kontakty lze tagovat. Tagy jsou uloženy jako JSON pole. Přidávání tagů probíhá přes:
|
||||
- `SetTagDriver` (akce automace)
|
||||
- `SmartEmailingAddTagDriver` (sync do SmartEmailing)
|
||||
- Automaticky při kliknutí na kampaňový email (`email_campaign:{id}`)
|
||||
|
||||
## Import kontaktů
|
||||
|
||||
- **CSV import** – `ContactsImportCsv` Livewire + `JsonContactImporter`
|
||||
- **Vario sync** – `VarioSyncContacts` command / `SyncVarioContactsJob`
|
||||
- **SmartEmailing webhook** – `SmartEmailingWebhookController`
|
||||
|
||||
## Firmy (Company)
|
||||
|
||||
Kontakty mohou být přiřazeny k firmám (`Company` model). Firmy se synchronizují z Vario ERP přes `VarioSyncCompanies`.
|
||||
|
||||
## Odhlášení z emailů
|
||||
|
||||
- `email_opt_out_at` – globální odhlášení
|
||||
- `EmailCategoryUnsubscribe` – odhlášení z konkrétní kategorie emailů
|
||||
- Unsubscribe link vede na `UnsubscribeController` nebo `EmailUnsubscribeController` (TOR-friendly doména)
|
||||
76
Kosiky.md
Normal file
76
Kosiky.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# Košíky (FunnelCart)
|
||||
|
||||
## Model
|
||||
|
||||
`App\Models\FunnelCart` – tabulka `funnel_carts`
|
||||
|
||||
| Sloupec | Typ | Popis |
|
||||
|---------|-----|-------|
|
||||
| `id` | bigint | PK |
|
||||
| `team_id` | bigint | Příslušnost k týmu |
|
||||
| `tracking_site_id` | bigint | Příslušný web/eshop |
|
||||
| `visitor_id` | string | ID anonymního návštěvníka |
|
||||
| `contact_id` | bigint | Propojený kontakt (nullable) |
|
||||
| `status` | string | `open` / `empty` / `converted` / `expired` |
|
||||
| `items` | json | Pole položek košíku |
|
||||
| `currency` | string | ISO kód měny |
|
||||
| `total_no_tax` | decimal | Celková suma bez DPH |
|
||||
| `shipping_fee_no_tax` | decimal | Cena dopravy bez DPH |
|
||||
| `cod_fee_no_tax` | decimal | Poplatek za dobírku bez DPH |
|
||||
| `shipping_label` | string | Název dopravce |
|
||||
| `first_seen_at` | timestamp | Kdy košík vznikl |
|
||||
| `last_seen_at` | timestamp | Poslední aktivita |
|
||||
| `completed_at` | timestamp | Kdy byl dokončen |
|
||||
| `is_completed` | boolean | Flag dokončení |
|
||||
| `is_expired` | boolean | Flag expirování |
|
||||
|
||||
## Formát položky košíku (`items[]`)
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "PROD-001",
|
||||
"name": "Název produktu",
|
||||
"qty": 2,
|
||||
"unit_no_tax": 99.00,
|
||||
"total_no_tax": 198.00,
|
||||
"url": "https://eshop.cz/produkt",
|
||||
"package": {}
|
||||
}
|
||||
```
|
||||
|
||||
## Stavy košíku
|
||||
|
||||
```
|
||||
open – košík má položky, zákazník nakupuje
|
||||
empty – košík byl vyprázdněn
|
||||
converted – objednávka dokončena
|
||||
expired – košík expiroval (job ExpireFunnelCarts)
|
||||
```
|
||||
|
||||
## Browser tracking (collect.js)
|
||||
|
||||
Košíky z prohlížeče jdou přes dva endpointy:
|
||||
|
||||
- **`POST /api/cart`** – `CartController` – upsert košíku (event `cart_upsert`)
|
||||
- **`POST /api/cart/complete`** – `CartCompleteController` – dokončení (event `cart_completed`)
|
||||
|
||||
Deduplikace přes `external_event_id` ve formátu `cart:{id}:cart_upsert:{hash}` kde hash je SHA1 z obsahu (kódy produktů, množství, ceny, měna).
|
||||
|
||||
## Server-to-server (eshop API)
|
||||
|
||||
Viz samostatná stránka [Integrace Eshop API](Integrace-Eshop-API).
|
||||
|
||||
- **`POST /api/eshop/cart`** – `EshopCartController` – párování podle emailu
|
||||
- **`POST /api/eshop/order`** – `EshopOrderController` – dokončení podle emailu
|
||||
|
||||
## Expirování košíků
|
||||
|
||||
Job `ExpireFunnelCartsJob` (command `ExpireFunnelCarts`) pravidelně označuje staré otevřené košíky jako `expired`.
|
||||
|
||||
## Statistiky
|
||||
|
||||
Denní statistiky košíků se agregují do:
|
||||
- `campaign_cart_daily_stats` – košíky per kampaň
|
||||
- `product_group_cart_daily_stats` – košíky per produktová skupina
|
||||
|
||||
Rebuild přes command `RebuildCampaignCartDailyStats` / `RebuildProductGroupCartDailyStats`.
|
||||
63
Logovani.md
Normal file
63
Logovani.md
Normal file
@@ -0,0 +1,63 @@
|
||||
# Logování
|
||||
|
||||
Projekt používá více log kanálů pro oddělení různých typů událostí.
|
||||
|
||||
## Kanály
|
||||
|
||||
| Kanál | Soubor | Driver | Rotace | Popis |
|
||||
|-------|--------|--------|--------|-------|
|
||||
| `stack` | *(dle konfigurace)* | stack | – | Výchozí kanál |
|
||||
| `single` | `storage/logs/laravel.log` | single | ne | Obecné logy Laravelu |
|
||||
| `daily` | `storage/logs/laravel-YYYY-MM-DD.log` | daily | 14 dní | Daily logy |
|
||||
| `funnel` | `storage/logs/funnel.log` | single | ne | Funnel/automace logy |
|
||||
| `eshop` | `storage/logs/eshop-YYYY-MM-DD.log` | daily | 30 dní | Eshop API requesty |
|
||||
|
||||
## Co se loguje kde
|
||||
|
||||
### `funnel.log`
|
||||
- `RulesEngine` – vyhodnocování pravidel (`rules_engine.evaluate:*`)
|
||||
- Debug konkrétních kontaktů při průchodu automacemi
|
||||
|
||||
### `eshop-YYYY-MM-DD.log`
|
||||
Každý request na `/api/eshop/cart` a `/api/eshop/order`:
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "api/eshop/cart",
|
||||
"context": {
|
||||
"method": "POST",
|
||||
"ip": "1.2.3.4",
|
||||
"site_key": "abc123",
|
||||
"body": {
|
||||
"email": "za***@example.cz",
|
||||
"currency": "CZK",
|
||||
"items": [...]
|
||||
},
|
||||
"status": 200,
|
||||
"response": { "ok": true, "cart_id": 42, ... }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> E-mail je automaticky maskován (`za***@example.cz`) z důvodu GDPR.
|
||||
|
||||
### Laravel Telescope
|
||||
Dostupný na `/telescope` – loguje HTTP requesty, queue joby, SQL dotazy, výjimky, emaily. Pouze ve vývojovém prostředí.
|
||||
|
||||
### Laravel Pulse
|
||||
Dostupný na `/pulse` – real-time monitoring výkonu (slow queries, failed jobs, queue depth...).
|
||||
|
||||
## Rotace logů
|
||||
|
||||
Pro produkci doporučujeme `logrotate` nebo nastavit `daily` driver s odpovídajícím `days` limitem. Aktuální nastavení:
|
||||
- `eshop`: 30 dní
|
||||
- `daily` (Laravel): 14 dní
|
||||
|
||||
## Přidání vlastního logu
|
||||
|
||||
```php
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
Log::channel('funnel')->info('my_event', ['data' => $data]);
|
||||
Log::channel('eshop')->warning('something_wrong', [...]);
|
||||
```
|
||||
67
Tracking.md
Normal file
67
Tracking.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# Tracking systém
|
||||
|
||||
## Jak to funguje
|
||||
|
||||
Tracking probíhá přes JavaScript soubor `public/collect.js`, který se vloží na sledovaný web. Každý web/eshop má přiřazený **Site Key** (`TrackingSite.public_key`), který se předává jako `data-site-key` atribut scriptu.
|
||||
|
||||
```html
|
||||
<script src="https://app.domena.cz/collect.js"
|
||||
data-site-key="abc123"
|
||||
data-api-base="https://app.domena.cz">
|
||||
</script>
|
||||
```
|
||||
|
||||
## Visitor ID
|
||||
|
||||
- Každý anonymní návštěvník dostane náhodné `visitor_id` (UUID), které se ukládá do cookie `ft_vid` a localStorage.
|
||||
- Po identifikaci (přihlášení, vyplnění emailu) se `visitor_id` propojí s `Contact` přes tabulku `visitor_identities` – viz `IdentityLinker`.
|
||||
|
||||
## IngestEvent pipeline
|
||||
|
||||
Všechny eventy (browser i server-side) prochází přes `App\Services\Ingest\IngestEvent::ingest()`:
|
||||
|
||||
1. Parsuje a normalizuje data (visitor_id, contact_id, occurred_at...)
|
||||
2. Volitelně provede identify (pokud přišel `identity.email`)
|
||||
3. Pokud chybí `visitor_id`, generuje náhradní (`contact:{id}` nebo `integration:{source}`)
|
||||
4. Uloží `FunnelEvent` do databáze (idempotentně přes `external_event_id`)
|
||||
5. Vrátí uložený `FunnelEvent`
|
||||
|
||||
Po ingestion volají controllery `RulesEngine::evaluate()` – viz [Automations](Automations).
|
||||
|
||||
## Události (event typy)
|
||||
|
||||
| Event | Kdy se posílá |
|
||||
|-------|--------------|
|
||||
| `page_view` | Každé zobrazení stránky |
|
||||
| `cart_upsert` | Změna obsahu košíku |
|
||||
| `cart_completed` | Dokončení objednávky |
|
||||
| `newsletter_subscribe` | Přihlášení k newsletteru |
|
||||
| `gallery_config_submit` | Odeslání konfigurátoru |
|
||||
| `identify` | Identifikace návštěvníka |
|
||||
|
||||
## Identifikace návštěvníka
|
||||
|
||||
Třída `IdentityLinker` zajišťuje propojení `visitor_id → Contact`:
|
||||
|
||||
- **`identify()`** – podle emailu (přihlášení, formulář)
|
||||
- **`identifyByToken()`** – podle `ftclid` (klik z emailové kampaně)
|
||||
- Mapping ukládá do `visitor_identities`
|
||||
- Backfilluje `contact_id` ke starším eventům pro stejné `visitor_id`
|
||||
|
||||
## Automatická identifikace v collect.js
|
||||
|
||||
1. Přes `ftclid` v URL (z emailového odkazu)
|
||||
2. Přes `gident` / `tag` UTM parametr
|
||||
3. Přes email v payloadu (při odeslání formuláře)
|
||||
|
||||
## Bot detekce
|
||||
|
||||
`BotDetector` flaguje requesty od crawlerů a botů. `FunnelEvent.bot = 1` pro botí eventy – tyto se do statistik nezapočítávají.
|
||||
|
||||
## GTM / dataLayer integrace
|
||||
|
||||
`collect.js` naslouchá na `window.dataLayer.push()` a zachytává standardní ecommerce eventy (`purchase`, `order_completed`, `transaction`, `ecommerce_purchase`) – automaticky je převede na `cart_completed`.
|
||||
|
||||
## Cross-domain tracking
|
||||
|
||||
Pokud zákazník přechází mezi doménami, `collect.js` automaticky doplňuje `visitor_id` jako URL parametr do odkazů podle konfigurace `data-propagate-link-domains`.
|
||||
Reference in New Issue
Block a user