Konfigurácia
Balík funguje bez akejkoľvek konfigurácie. config/tickets.php publikujte, len ak chcete niečo prepísať:
php artisan vendor:publish --tag=tickets-configKaždý kľúč sa číta cez validujúcu čítačku (Support\TicketsConfig, nad Config z toolkitu): nezmyselná hodnota vyhodí InvalidTicketsConfigurationException (alebo InvalidConfigurationException z toolkitu) s názvom kľúča — nikdy sa potichu nepoužije náhradná hodnota.
- Booleany sa čítajú ako on/off (aj true/false, 1/0, yes/no); čokoľvek iné vyhodí výnimku. Prázdna hodnota v env znamená dodanú predvolenú hodnotu.
- Dĺžky trvania sú ISO-8601 (P7D, PT4H, P1DT12H); off prijímajú len kľúče, pri ktorých je to uvedené.
- Test kontraktu konfigurácie stráži oba smery: každý kľúč, ktorý kód číta, je dodaný, a každý dodaný kľúč sa číta.
Konfiguračný súbor
// config/tickets.php (imports omitted)
return [
'primary_key_type' => env('TICKETS_PRIMARY_KEY_TYPE', 'bigint'),
'key_type' => env('TICKETS_KEY_TYPE', 'bigint'),
'models' => [
'ticket' => Ticket::class,
'category' => TicketCategory::class,
'field' => TicketField::class,
'tag' => TicketTag::class,
'guest' => TicketGuest::class,
],
'lifecycle' => TicketLifecycle::class,
'auto_close' => [
'after' => env('TICKETS_AUTO_CLOSE_AFTER', 'P7D'),
],
'priority' => [
'enum' => TicketPriority::class,
'default' => env('TICKETS_DEFAULT_PRIORITY', 'normal'),
],
'reference' => [
'prefix' => env('TICKETS_REFERENCE_PREFIX', 'TCK'),
],
'channels' => ['web', 'email', 'api', 'phone', 'chat'],
'default_channel' => 'api',
'assignment' => [
'strategy' => CategoryDefaultStrategy::class,
],
'due' => [
'resolver' => CategoryDueDateResolver::class,
'soon_window' => env('TICKETS_DUE_SOON_WINDOW', 'PT4H'),
],
'requesters' => ['user' => 'App\\Models\\User'],
'assignables' => ['user' => 'App\\Models\\User'],
'watchables' => null,
'projects' => [],
'guests' => [
'enabled' => env('TICKETS_GUESTS', 'on'),
'fields' => [
'name' => ['type' => 'string', 'rules' => ['required', 'string', 'max:120'], 'display' => true],
'email' => ['type' => 'string', 'rules' => ['nullable', 'email:rfc', 'max:191'], 'identifying' => true, 'route' => 'mail', 'normalize' => 'email'],
'phone' => ['type' => 'string', 'rules' => ['nullable', 'string', 'max:32'], 'identifying' => true, 'route' => 'vonage', 'normalize' => 'phone', 'encrypted' => false],
],
'require_one_identifying' => true,
'update_on_resolve' => false,
'link_ttl' => env('TICKETS_GUEST_LINK_TTL', 'P30D'),
'revoke_on_close' => env('TICKETS_GUESTS_REVOKE_ON_CLOSE', 'off'),
'link_generator' => SignedRouteLinkGenerator::class,
],
'categories' => [
'max_depth' => 5,
],
'fields' => [
'allowed_rules' => ['min', 'max', 'between', 'regex', 'digits', 'digits_between', 'alpha', 'alpha_num', 'alpha_dash', 'starts_with', 'ends_with'],
],
'comments' => [
'auto_approve' => env('TICKETS_COMMENTS_AUTO_APPROVE', 'on'),
'reply_reopens' => env('TICKETS_REPLY_REOPENS', 'on'),
],
'watchers' => [
'can_view' => env('TICKETS_WATCHERS_CAN_VIEW', 'on'),
'auto' => [
'requester' => env('TICKETS_AUTO_WATCH_REQUESTER', 'on'),
'assignee' => env('TICKETS_AUTO_WATCH_ASSIGNEE', 'on'),
'agent_repliers' => env('TICKETS_AUTO_WATCH_AGENT_REPLIERS', 'on'),
'mentioned' => env('TICKETS_AUTO_WATCH_MENTIONED', 'off'),
],
],
'authorization' => [
'register_policy' => env('TICKETS_REGISTER_POLICY', 'on'),
'policy' => TicketPolicy::class,
'abilities' => [
'agent' => 'tickets.agent',
'assign' => 'tickets.assign',
'merge' => 'tickets.agent',
'manage' => 'tickets.manage',
],
'agent_scope' => null,
'requester_transitions' => ['close', 'reopen'],
'participants_can_transition' => env('TICKETS_PARTICIPANTS_CAN_TRANSITION', 'off'),
'self_service' => env('TICKETS_SELF_SERVICE', 'on'),
'requester_can_edit' => env('TICKETS_REQUESTER_CAN_EDIT', 'on'),
],
'tags' => [
'free_form' => env('TICKETS_TAGS_FREE_FORM', 'on'),
],
'links' => [
'cross_project' => env('TICKETS_LINKS_CROSS_PROJECT', 'on'),
'max_depth' => 50,
],
'merge' => [
'cross_project' => env('TICKETS_MERGE_CROSS_PROJECT', 'off'),
'move_attachments' => env('TICKETS_MERGE_MOVE_ATTACHMENTS', 'on'),
],
'attachments' => [
'bucket' => 'attachments',
'disk' => env('TICKETS_ATTACHMENTS_DISK', 'local'),
'mimes' => [
'image/jpeg', 'image/png', 'image/gif', 'image/webp',
'application/pdf', 'text/plain', 'text/csv',
'application/zip',
'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
],
'max_kb' => 10240,
],
'activity' => [
'enabled' => env('TICKETS_ACTIVITY', 'on'),
],
'actor' => [
'from_auth' => env('TICKETS_ACTOR_FROM_AUTH', 'on'),
'guard' => env('TICKETS_ACTOR_GUARD'),
],
'routes' => [
// Blank means off: the route switch reads a blank value as on.
'enabled' => env('TICKETS_ROUTES') ?: 'off',
'prefix' => env('TICKETS_ROUTES_PREFIX', 'api'),
'middleware' => ['api', 'auth', 'throttle:tickets-api'],
'max_per_page' => 100,
'rate_limit' => 120,
'guest' => [
'middleware' => ['api', 'throttle:tickets-guest'],
'rate_limit' => 30,
],
'bulk' => [
'max' => 100,
],
],
'notifications' => [
'enabled' => env('TICKETS_NOTIFICATIONS', 'on'),
'channels' => ['mail'],
'queue' => env('TICKETS_NOTIFICATIONS_QUEUE'),
'notify_actor' => env('TICKETS_NOTIFY_ACTOR', 'off'),
'guests' => env('TICKETS_NOTIFY_GUESTS', 'on'),
'url' => env('TICKETS_NOTIFICATIONS_URL'),
'types' => [
'created' => TicketCreatedNotification::class,
'assigned' => TicketAssignedNotification::class,
'replied' => TicketRepliedNotification::class,
'requester_replied' => TicketRequesterRepliedNotification::class,
'note_added' => TicketNoteAddedNotification::class,
'mentioned' => TicketMentionedNotification::class,
'status_changed' => TicketStatusChangedNotification::class,
'overdue' => TicketOverdueNotification::class,
'due_soon' => TicketDueSoonNotification::class,
'merged' => TicketMergedNotification::class,
],
],
];Typy kľúčov
| Kľúč | Env | Predvolené | Účel |
|---|---|---|---|
primary_key_type | TICKETS_PRIMARY_KEY_TYPE | bigint | Primárny kľúč modelov Ticket a TicketGuest a každého stĺpca, ktorý ukazuje na tiket — bigint, uuid alebo ulid. Musí sa rovnať lifecycle.key_type, attributes.key_type a comments.key_type. Nastavte ho pred migráciou. |
key_type | TICKETS_KEY_TYPE | bigint | Id polymorfných vzťahov smerom von: žiadateľ, riešiteľ, projekt, sledujúci, aktér, autor prepojenia, predvolený riešiteľ kategórie. Musí sa rovnať kľúčom vašich používateľov, lifecycle.actor_key_type a comments.key_type. Nastavte ho pred migráciou. |
Modely
| Kľúč | Env | Predvolené | Účel |
|---|---|---|---|
models.ticket | — | Models\Ticket | Model tiketu. Náhrada musí dediť od triedy z balíka. |
models.category | — | Models\TicketCategory | Model kategórie; náhrada dedí od triedy z balíka. |
models.field | — | Models\TicketField | Model definície vlastného poľa; náhrada dedí od triedy z balíka. |
models.tag | — | Models\TicketTag | Model štítka; náhrada dedí od triedy z balíka. |
models.guest | — | Models\TicketGuest | Model hosťa (žiadateľa bez účtu); náhrada dedí od triedy z balíka. |
Životný cyklus, priorita, čísla, kanály
| Kľúč | Env | Predvolené | Účel |
|---|---|---|---|
lifecycle | — | Lifecycle\TicketLifecycle | Definícia lifecycle-for-laravel, ktorá implementuje Contracts\TicketLifecycle a ktorej enum stavov implementuje Contracts\TicketState. |
auto_close.after | TICKETS_AUTO_CLOSE_AFTER | P7D | Ako dlho vyriešený tiket čaká, kým ho lifecycle:sweep uzavrie; off = nikdy. Číta sa vo chvíli, keď tiket vstúpi do stavu Resolved. |
priority.enum | — | Enums\TicketPriority | Enum s reťazcovými hodnotami, ktorý implementuje Contracts\Priority. |
priority.default | TICKETS_DEFAULT_PRIORITY | normal | Hodnota tohto enumu; použije sa, keď prioritu nenastaví volajúci ani kategória. |
reference.prefix | TICKETS_REFERENCE_PREFIX | TCK | Prefix tiketov bez projektu; ^[A-Z][A-Z0-9]{0,9}$. |
channels | — | web, email, api, phone, chat | Akceptované vstupné kanály, každý ^[a-z][a-z0-9_]{0,31}$. Prázdny alebo nenastavený zoznam sa číta ako dodaný; kanál, ktorý pridáte, berie popis z tickets::enums.ticket_channel.<value>. |
default_channel | — | api | Jeden z channels (inak api, inak prvý v zozname). |
Predvolené hodnoty pri založení, termíny
| Kľúč | Env | Predvolené | Účel |
|---|---|---|---|
assignment.strategy | — | Assignment\CategoryDefaultStrategy | Contracts\AssignmentStrategy, ktorej sa balík opýta, keď tiket vznikne bez riešiteľa. |
due.resolver | — | Due\CategoryDueDateResolver | Contracts\DueDateResolver, ktorého sa balík opýta, keď tiket vznikne bez termínu. |
due.soon_window | TICKETS_DUE_SOON_WINDOW | PT4H | tickets:sweep raz označí tiket, ktorého termín spadá do tohto okna (TicketDueSoon); off = nikdy. |
Povolené aliasy polymorfných vzťahov
| Kľúč | Env | Predvolené | Účel |
|---|---|---|---|
requesters | — | ['user' => App\Models\User] | Kto smie byť žiadateľom vo vstupe API ({type: alias, id}) — nikdy nie názov triedy. Model hosťa má vždy alias guest. |
assignables | — | ['user' => App\Models\User] | Komu možno tiket priradiť; každá trieda musí implementovať Contracts\Assignee. |
watchables | — | null | null = všetky aliasy žiadateľov a riešiteľov. |
projects | — | [] | Aliasy projektov; každá trieda musí implementovať Contracts\TicketProject. |
Hostia
| Kľúč | Env | Predvolené | Účel |
|---|---|---|---|
guests.enabled | TICKETS_GUESTS | on | Sprístupní endpointy pre hostí (len pri zapnutých routách). Publikovaná konfigurácia bez tohto kľúča sa číta ako on; tickets:doctor upozorní. |
guests.fields | — | name, email, phone | Polia hosťa, uložené cez attributes-for-laravel — pozrite Hostia a odkazy pre hostí. |
guests.require_one_identifying | — | true | Hosť potrebuje aspoň jednu identifikačnú hodnotu. |
guests.update_on_resolve | — | false | Prepísať odlišné neidentifikačné hodnoty, keď sa vracajúci hosť znova ozve. |
guests.link_ttl | TICKETS_GUEST_LINK_TTL | P30D | Platnosť odkazu pre hosťa. |
guests.revoke_on_close | TICKETS_GUESTS_REVOKE_ON_CLOSE | off | Uzavretie tiketu zneplatní všetky odkazy pre hostí k nemu. |
guests.link_generator | — | Guests\SignedRouteLinkGenerator | Implementácia Contracts\GuestLinkGenerator. |
Kategórie, polia, štítky, prepojenia, zlučovanie
| Kľúč | Env | Predvolené | Účel |
|---|---|---|---|
categories.max_depth | — | 5 | Najväčšia hĺbka stromu kategórií, 1–50. |
fields.allowed_rules | — | min, max, between, regex, digits, digits_between, alpha, alpha_num, alpha_dash, starts_with, ends_with | Jediné pravidlá, ktoré smie mať vlastné pole; exists a unique sa odmietnu vždy. |
tags.free_form | TICKETS_TAGS_FREE_FORM | on | Pripojenie neznámeho názvu štítka ho vytvorí; off = len existujúce štítky. |
links.cross_project | TICKETS_LINKS_CROSS_PROJECT | on | Prepájať tikety rôznych projektov. |
links.max_depth | — | 50 | Ako hlboko prechádza kontrola cyklov pre blocks / parent_of, 1–1000. |
merge.cross_project | TICKETS_MERGE_CROSS_PROJECT | off | Zlučovať tikety rôznych projektov. |
merge.move_attachments | TICKETS_MERGE_MOVE_ATTACHMENTS | on | Zlúčenie presunie prílohy zdrojového tiketu na cieľový. |
Konverzácia a sledujúci
| Kľúč | Env | Predvolené | Účel |
|---|---|---|---|
comments.auto_approve | TICKETS_COMMENTS_AUTO_APPROVE | on | Schváliť odpoveď na tiket, ktorú hostiteľské comments.require_approval nechalo čakať — nikdy nie takú, ktorú zadržal blocklist. Pri off a zapnutom require_approval čaká každá odpoveď na moderátora a ani po schválení nemá na tiket účinok (pozrite Odpovede a interné poznámky). |
comments.reply_reopens | TICKETS_REPLY_REOPENS | on | Odpoveď žiadateľa znovu otvorí vyriešený tiket. |
watchers.can_view | TICKETS_WATCHERS_CAN_VIEW | on | Sledujúci, ktorý nie je agent, vidí tiket aj jeho verejné vlákno a smie odpovedať ako účastník. Pri off dostane prihlásený sledujúci 404 a hosť ako sledujúci žiadny odkaz (jeho odkazy vrátia 403, e-maily nemajú tlačidlo). |
watchers.auto.requester | TICKETS_AUTO_WATCH_REQUESTER | on | Žiadateľ začne tiket sledovať pri jeho založení. |
watchers.auto.assignee | TICKETS_AUTO_WATCH_ASSIGNEE | on | Riešiteľ začne tiket sledovať pri priradení. |
watchers.auto.agent_repliers | TICKETS_AUTO_WATCH_AGENT_REPLIERS | on | Agent, ktorý na tiket napíše, ho začne sledovať. |
watchers.auto.mentioned | TICKETS_AUTO_WATCH_MENTIONED | off | Spomenutá osoba (ktorá smie komentár čítať) začne tiket sledovať. |
Autorizácia
| Kľúč | Env | Predvolené | Účel |
|---|---|---|---|
authorization.register_policy | TICKETS_REGISTER_POLICY | on | Zaregistrovať policy pre model tiketu. |
authorization.policy | — | Policies\TicketPolicy | Musí dediť od TicketPolicy; neplatná trieda nezaregistruje nič (doctor to nahlási). |
authorization.abilities.agent | — | tickets.agent | Gate oprávnenie, ktoré z používateľa robí agenta. |
authorization.abilities.assign | — | tickets.assign | Priradiť tiket niekomu inému. |
authorization.abilities.merge | — | tickets.agent | Zlučovať tikety. |
authorization.abilities.manage | — | tickets.manage | Mazať a obnovovať tikety (držiteľ musí byť zároveň agentom pre daný tiket — tickets.agent plus AgentScope); spravovať kategórie, polia a štítky. |
authorization.agent_scope | — | null | Contracts\AgentScope; null naviaže Authorization\UnrestrictedAgentScope (agenti vidia každý tiket). |
authorization.requester_transitions | — | ['close', 'reopen'] | Prechody, ktoré smie žiadateľ spustiť na vlastnom tikete; [] (alebo prázdny reťazec) = žiadne, null = predvolené; funguje aj reťazec oddelený čiarkami. Každý ^[a-z][a-z0-9_]{0,63}$. |
authorization.participants_can_transition | TICKETS_PARTICIPANTS_CAN_TRANSITION | off | Spúšťať ich smie aj sledujúci. |
authorization.self_service | TICKETS_SELF_SERVICE | on | Tiket smie založiť ktokoľvek prihlásený; off = len agenti. |
authorization.requester_can_edit | TICKETS_REQUESTER_CAN_EDIT | on | Žiadateľ smie upraviť predmet a popis, kým tiket nie je vyriešený. |
Prílohy
| Kľúč | Env | Predvolené | Účel |
|---|---|---|---|
attachments.bucket | — | attachments | Skupina (bucket) media-library pre prílohy tiketov (súkromná); ^[a-z][a-z0-9_-]{0,63}$. |
attachments.disk | TICKETS_ATTACHMENTS_DISK | local | Nesmie ho servírovať webový server — predvolený disk media-library (public) je dostupný pod /storage. |
attachments.mimes | — | obrázky, PDF, text, CSV, ZIP, Word, Excel | Akceptované mime typy (type/subtype); [] = akékoľvek. Publikovaná konfigurácia, ktorej pole attachments tento kľúč nemá, dostane tento zoznam, nikdy nie akýkoľvek typ (doctor upozorní). |
attachments.max_kb | — | 10240 | Limit veľkosti v kilobajtoch, aspoň 1. Prílohy odpovedí a poznámok sa namiesto toho riadia comments.media.* z balíka comments. |
Aktivity a aktér
| Kľúč | Env | Predvolené | Účel |
|---|---|---|---|
activity.enabled | TICKETS_ACTIVITY | on | Zapisovať históriu aktivít; off = nezapíše sa nič a endpoint vráti []. |
actor.from_auth | TICKETS_ACTOR_FROM_AUTH | on | Volanie bez explicitného aktéra sa pripíše prihlásenému používateľovi. |
actor.guard | TICKETS_ACTOR_GUARD | prázdne | Guard, ktorý sa na to použije; prázdne = predvolený guard. |
HTTP API
| Kľúč | Env | Predvolené | Účel |
|---|---|---|---|
routes.enabled | TICKETS_ROUTES | off | Sprístupní JSON API. Zapísané ako env('TICKETS_ROUTES') ?: 'off', takže prázdna hodnota zostane off. Publikovaná konfigurácia bez tohto kľúča sa číta ako on (prepínač rout z toolkitu); tickets:doctor upozorní. |
routes.prefix | TICKETS_ROUTES_PREFIX | api | Prefix URI (/ = žiadny); písmená, číslice, -, _, . a /. |
routes.middleware | — | ['api', 'auth', 'throttle:tickets-api'] | Endpointy agentov a žiadateľov; so Sanctum použite auth:sanctum. |
routes.max_per_page | — | 100 | Najväčšia stránka tiketov, 1–1000 (predvolene 20). |
routes.rate_limit | — | 120 | Požiadavky za minútu na používateľa (na IP pri anonymnom volajúcom) na tickets-api, aspoň 1. |
routes.guest.middleware | — | ['api', 'throttle:tickets-guest'] | Endpointy pre hostí; EnsureGuestTicketAccess sa pripojí vždy. |
routes.guest.rate_limit | — | 30 | Požiadavky za minútu na IP a tiket na tickets-guest, aspoň 1. |
routes.bulk.max | — | 100 | Najviac tiketov v jednom hromadnom volaní, 1–1000. |
Notifikácie
| Kľúč | Env | Predvolené | Účel |
|---|---|---|---|
notifications.enabled | TICKETS_NOTIFICATIONS | on | Posielať notifikácie vôbec. |
notifications.channels | — | ['mail'] | database potrebuje vašu tabuľku notifications; každý iný kanál potrebuje podtriedu (pozrite Notifikácie). |
notifications.queue | TICKETS_NOTIFICATIONS_QUEUE | prázdne | Názov fronty; prázdne = predvolená fronta spojenia. |
notifications.notify_actor | TICKETS_NOTIFY_ACTOR | off | Upovedomiť aj toho, kto akciu vykonal (potvrdenie created odíde vždy). |
notifications.guests | TICKETS_NOTIFY_GUESTS | on | Posielať e-maily hosťom — žiadateľom aj sledujúcim — s novým podpísaným odkazom. |
notifications.url | TICKETS_NOTIFICATIONS_URL | prázdne | Tlačidlo v e-maile pre prihlásených príjemcov s doplneným {reference} (https://help.example.com/tickets/{reference}); prázdne = bez tlačidla; musí byť http(s). |
notifications.types.<type> | — | trieda z balíka | Jeden kľúč na typ — created, assigned, replied, requester_replied, note_added, mentioned, status_changed, overdue, due_soon, merged: trieda, ktorá dedí od triedy z balíka, alebo false (aj reťazce false, off, 0, no) na vypnutie; prázdne či nenastavené = trieda z balíka. |
Pri vypnutom authorization.register_policy Laravel cez vlastné vyhľadávanie policy stále priradí Models\Ticket k Policies\TicketPolicy — off neznamená zamietnuť všetko; vlastnú policy zaregistrujte cez Gate::policy(). Limity požiadaviek sa definujú len pri zapnutých routách a platia, len kým je ich middleware throttle: v zozname.
Nastavenia z iných balíkov
| Kľúč | Prečo |
|---|---|
lifecycle.key_type, lifecycle.actor_key_type, comments.key_type, attributes.key_type | Zladenie typov kľúčov (doctor, inštalácia). |
comments.authorization | Upozornenie doctora (pozrite Odpovede a interné poznámky). |
comments.media.private_disk, media.stream.enabled | Kontrola URL príloh v doctorovi. |
query-builder.mode.unknown_filter | reject (predvolené) odpovie na neznámy filter[...] kódom 400; ignore ho zahodí. |
Prostredie (env)
Bežné prepínače sú riadené cez env, takže konfiguráciu publikujete len zriedka:
TICKETS_REFERENCE_PREFIX=TCK
TICKETS_DEFAULT_PRIORITY=normal
TICKETS_AUTO_CLOSE_AFTER=P7D
TICKETS_DUE_SOON_WINDOW=PT4H
TICKETS_ROUTES=on
TICKETS_ATTACHMENTS_DISK=local
TICKETS_NOTIFICATIONS_URL=https://help.example.com/tickets/{reference}
TICKETS_NOTIFY_GUESTS=onPrejavte lásku k open source
Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.
Ďalšie spôsoby podpory vrátane kryptomienOdoslaním daru súhlasíte s našimi podmienkami prijímania darov.
Chcete to zabudovať do svojho produktu?
Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.