Initial commit: OAuth IAM Laravel application

Laravel-based OAuth/IAM service with Passport, Vue 3 frontend, and
Docker Compose setup for local and production deployment.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-26 01:02:41 +02:00
commit c2b5291a74
174 changed files with 29318 additions and 0 deletions

119
lang/ca/actions.php Normal file
View File

@@ -0,0 +1,119 @@
<?php
declare(strict_types=1);
return [
'accept' => 'Acceptar',
'action' => 'Acció',
'actions' => 'Accions',
'add' => 'Afegeix',
'admin' => 'Admin',
'agree' => 'Acordar',
'archive' => 'Arxiu',
'assign' => 'Assignar',
'associate' => 'Associat',
'attach' => 'Adjuntar',
'browse' => 'Navega',
'cancel' => 'Cancel · lar',
'choose' => 'Tria',
'choose_file' => 'Trieu l\'arxiu',
'choose_image' => 'Trieu Imatge',
'click_to_copy' => 'Feu clic per copiar',
'close' => 'Tanca',
'collapse' => 'Col·lapse',
'collapse_all' => 'Col · lapsar tot',
'comment' => 'Comenta',
'confirm' => 'Confirmeu',
'connect' => 'Connecta\'t',
'create' => 'Crear',
'delete' => 'Suprimeix',
'detach' => 'Separar',
'details' => 'Detalls',
'disable' => 'Desactivar',
'discard' => 'Descartar',
'done' => 'Fet',
'down' => 'Avall',
'duplicate' => 'Duplicat',
'edit' => 'Edita',
'enable' => 'Activa',
'expand' => 'Ampliar',
'expand_all' => 'Amplia-ho tot',
'explanation' => 'Explicació',
'export' => 'Exporta',
'file' => 'Dossier',
'files' => 'Fitxers',
'go_home' => 'Aneu a l\'inici',
'hide' => 'Amaga',
'home' => 'Inici',
'image' => 'Imatge',
'impersonate' => 'Suplantar la identitat',
'impersonation' => 'Suplantació d\'identitat',
'import' => 'Importar',
'introduction' => 'Introducció',
'like' => 'M\'agrada',
'load' => 'Carrega',
'localize' => 'Localitza',
'log_in' => 'Iniciar Sessió',
'log_out' => 'Tancar sessió',
'named' => [
'add' => 'Afegeix :name',
'choose' => 'Trieu :name',
'create' => 'Crea :name',
'delete' => 'Suprimeix :name',
'duplicate' => 'Duplicat: nom',
'edit' => 'Edita :name',
'export' => 'Export :name',
'hide' => 'Amaga :name',
'import' => 'Importació :name',
'new' => 'Nou :name',
'restore' => 'Restaurar :name',
'save' => 'Estalvia :name',
'search' => 'Cerca :name',
'show' => 'Mostra :name',
'update' => 'Actualització :name',
'view' => 'Vista :name',
],
'new' => 'Nou',
'no' => 'No',
'open' => 'Obert',
'open_website' => 'Obert al lloc web',
'preview' => 'Vista prèvia',
'price' => 'Preu',
'record' => 'Registre',
'restore' => 'Restaurar',
'save' => 'Desa',
'save_and_close' => 'Desa i tanca',
'save_and_return' => 'Guarda i torna',
'search' => 'Cerca',
'select' => 'Seleccioneu',
'select_all' => 'Seleccionar tot',
'send' => 'Enviar',
'settings' => 'Configuració',
'show' => 'Espectacle',
'show_all' => 'Mostrar tots',
'sign_in' => 'Inicieu la sessió',
'solve' => 'Resol',
'start' => 'Començar',
'stop' => 'Atura',
'submit' => 'Presentar',
'subscribe' => 'Subscriu-te',
'switch' => 'Interruptor',
'switch_to_role' => 'Canvia al rol',
'tag' => 'Etiqueta',
'tags' => 'Etiquetes',
'target_link' => [
'blank' => 'Obre en una finestra nova',
'parent' => 'Obre en un marc principal',
'self' => 'Obre en una finestra actual',
'top' => 'Obre al marc superior',
],
'translate' => 'Traduir',
'translate_it' => 'Tradueix-ho',
'unpack' => 'Desempaquetar',
'unsubscribe' => 'Cancel·la la subscripció',
'up' => 'Amunt',
'update' => 'Actualització',
'user' => 'Usuari',
'view' => 'Veure',
'yes' => 'Sí',
];

9
lang/ca/auth.php Normal file
View File

@@ -0,0 +1,9 @@
<?php
declare(strict_types=1);
return [
'failed' => 'Aquestes credencials no concorden amb els nostres registres.',
'password' => 'La contrasenya és incorrecta.',
'throttle' => 'Ha superat el nombre màxim d\'intents d\'accés. Si us plau, torni a intentar-ho en :seconds segons.',
];

84
lang/ca/http-statuses.php Normal file
View File

@@ -0,0 +1,84 @@
<?php
declare(strict_types=1);
return [
'0' => 'Error desconegut',
'100' => 'Continua',
'101' => 'Protocols de commutació',
'102' => 'Processament',
'200' => 'D\'acord',
'201' => 'Creat',
'202' => 'Acceptat',
'203' => 'Informació no autoritzada',
'204' => 'Sense contingut',
'205' => 'Restablir contingut',
'206' => 'Contingut parcial',
'207' => 'Multiestatus',
'208' => 'Ja s\'ha informat',
'226' => 'IM utilitzat',
'300' => 'Opcions múltiples',
'301' => 'Mogut permanentment',
'302' => 'Trobat',
'303' => 'Vegeu Altres',
'304' => 'No modificat',
'305' => 'Utilitzeu el proxy',
'307' => 'Redirecció temporal',
'308' => 'Redirecció permanent',
'400' => 'Petició dolenta',
'401' => 'No autoritzat',
'402' => 'Pagament obligatori',
'403' => 'Prohibit',
'404' => 'No trobat',
'405' => 'Mètode no permès',
'406' => 'No és acceptable',
'407' => 'Es requereix autenticació de proxy',
'408' => 'Temps d\'espera esgotat',
'409' => 'Conflicte',
'410' => 'Desaparegut',
'411' => 'Longitud requerida',
'412' => 'La condició prèvia ha fallat',
'413' => 'Càrrega útil massa gran',
'414' => 'URI massa llarg',
'415' => 'Tipus de suport no compatible',
'416' => 'Interval no satisfactori',
'417' => 'L\'expectativa ha fallat',
'418' => 'Sóc una tetera',
'419' => 'La sessió ha caducat',
'421' => 'Sol·licitud mal dirigida',
'422' => 'Entitat no processable',
'423' => 'Tancat',
'424' => 'Dependència fallida',
'425' => 'Massa aviat',
'426' => 'Actualització necessària',
'428' => 'Condició prèvia requerida',
'429' => 'Massa sol·licituds',
'431' => 'Els camps de la capçalera de la sol·licitud són massa grans',
'444' => 'Connexió tancada sense resposta',
'449' => 'Torna-ho a provar amb',
'451' => 'No disponible per motius legals',
'499' => 'Sol·licitud de client tancada',
'500' => 'error del servidor intern',
'501' => 'No implementat',
'502' => 'Porta d\'enllaç incorrecta',
'503' => 'mode de manteniment',
'504' => 'Temps d\'espera de la passarel·la',
'505' => 'Versió HTTP no compatible',
'506' => 'La variant també es negocia',
'507' => 'Emmagatzematge insuficient',
'508' => 'Bucle detectat',
'509' => 'Límit d\'ample de banda excedit',
'510' => 'No ampliat',
'511' => 'Es requereix autenticació de xarxa',
'520' => 'Error desconegut',
'521' => 'El servidor web està caigut',
'522' => 'Temps de connexió esgotat',
'523' => 'L\'origen és inabastable',
'524' => 'S\'ha produït un temps mort',
'525' => 'SSL Handshake ha fallat',
'526' => 'Certificat SSL no vàlid',
'527' => 'Error de canó de ferrocarril',
'598' => 'Error de temps d\'espera de lectura de la xarxa',
'599' => 'Error de temps d\'espera de connexió a la xarxa',
'unknownError' => 'Error desconegut',
];

13
lang/ca/messages.php Normal file
View File

@@ -0,0 +1,13 @@
<?php
return [
'invalid_credentials' => 'Credencials no vàlides.',
'account_deactivated' => 'Aquest compte està desactivat.',
'account_pending_approval' => 'El teu compte està pendent d\'aprovació per un administrador.',
'registration_pending' => 'Compte creat. Un administrador l\'ha d\'aprovar abans que puguis entrar.',
'cannot_remove_own_admin_role' => 'No et pots treure el rol d\'admin a tu mateix.',
'cannot_delete_self' => 'No pots esborrar el teu propi compte.',
'cannot_delete_last_admin' => 'No pots esborrar l\'últim administrador.',
'self_service_requires_user' => 'Aquest recurs és self-service: necessita un token amb un usuari associat (no funciona amb client_credentials).',
'user_not_trashed' => 'Aquest usuari no és a la paperera.',
];

8
lang/ca/pagination.php Normal file
View File

@@ -0,0 +1,8 @@
<?php
declare(strict_types=1);
return [
'next' => 'Següent &raquo;',
'previous' => '&laquo; Anterior',
];

11
lang/ca/passwords.php Normal file
View File

@@ -0,0 +1,11 @@
<?php
declare(strict_types=1);
return [
'reset' => 'La contrasenya s\'ha restablert!',
'sent' => 'Li hem enviat un correu electrònic amb un enllaç per a reiniciar la teva contrasenya!',
'throttled' => 'Si us plau, esperi abans de tornar-ho a intentar.',
'token' => 'Aquest token de recuperació de contrasenya és invàlid.',
'user' => 'No existeix cap usuari amb aquest correu.',
];

289
lang/ca/validation.php Normal file
View File

@@ -0,0 +1,289 @@
<?php
declare(strict_types=1);
return [
'accepted' => ':Attribute ha de ser acceptat.',
'accepted_if' => 'El :attribute s\'ha d\'acceptar quan :other és :value.',
'active_url' => ':Attribute no és un URL vàlid.',
'after' => ':Attribute ha de ser una data posterior a :date.',
'after_or_equal' => ':Attribute ha de ser una data posterior o igual a :date.',
'alpha' => ':Attribute només pot contenir lletres.',
'alpha_dash' => ':Attribute només pot contenir lletres, números i guions.',
'alpha_num' => ':Attribute només pot contenir lletres i números.',
'any_of' => 'El camp :attribute no és vàlid.',
'array' => ':Attribute ha de ser una matriu.',
'ascii' => 'El :attribute només ha de contenir caràcters i símbols alfanumèrics d\'un sol byte.',
'base64' => 'The :attribute field must be a valid Base64 string.',
'before' => ':Attribute ha de ser una data anterior a :date.',
'before_or_equal' => ':Attribute ha de ser una data anterior o igual a :date.',
'between' => [
'array' => ':Attribute ha de tenir entre :min - :max ítems.',
'file' => ':Attribute ha de pesar entre :min - :max kilobytes.',
'numeric' => ':Attribute ha d\'estar entre :min - :max.',
'string' => ':Attribute ha de tenir entre :min - :max caràcters.',
],
'boolean' => 'El camp :attribute ha de ser verdader o fals',
'can' => 'El camp :attribute conté un valor no autoritzat.',
'confirmed' => 'La confirmació de :attribute no coincideix.',
'contains' => 'Al camp :attribute li falta un valor obligatori.',
'current_password' => 'La contrasenya és incorrecta.',
'date' => ':Attribute no és una data vàlida.',
'date_equals' => 'El :attribute ha de ser una data igual a :date.',
'date_format' => 'El camp :attribute no concorda amb el format :format.',
'decimal' => 'El :attribute ha de tenir :decimal decimals.',
'declined' => 'Els :attribute s\'han de rebutjar.',
'declined_if' => 'El :attribute s\'ha de rebutjar quan :other és :value.',
'different' => ':Attribute i :other han de ser diferents.',
'digits' => ':Attribute ha de tenir :digits dígits.',
'digits_between' => ':Attribute ha de tenir entre :min i :max dígits.',
'dimensions' => 'Les dimensions de la imatge :attribute no són vàlides.',
'distinct' => 'El camp :attribute té un valor duplicat.',
'doesnt_contain' => 'El camp :attribute no ha de contenir cap dels següents: :values.',
'doesnt_end_with' => 'El :attribute no pot acabar amb un dels següents: :values.',
'doesnt_start_with' => 'El :attribute no pot començar amb un dels següents: :values.',
'email' => ':Attribute no és un e-mail vàlid',
'encoding' => 'El camp :attribute s\'ha de codificar en :encoding.',
'ends_with' => 'La :attribute ha d\'acabar amb una de les següents: :values.',
'enum' => 'El :attribute seleccionat no és vàlid.',
'exists' => ':Attribute és invàlid.',
'extensions' => 'El camp :attribute ha de tenir una de les extensions següents: :values.',
'file' => 'El camp :attribute ha de ser un arxiu.',
'filled' => 'El camp :attribute és obligatori.',
'gt' => [
'array' => 'El :attribute ha de tenir més de :value ítems.',
'file' => 'El :attribute ha de ser superior a :value kilobytes.',
'numeric' => 'El :attribute ha de ser superior a :value.',
'string' => 'El :attribute ha de superar els :value caràcters.',
],
'gte' => [
'array' => 'El :attribute ha de tenir :value ítems o més.',
'file' => 'El :attribute ha de ser igual o superior a :value kilobytes.',
'numeric' => 'El :attribute ha de ser igual o superior a :value.',
'string' => 'El :attribute ha de ser igual o superior a :value caràcters.',
],
'hex_color' => 'El camp :attribute ha de ser un color hexadecimal vàlid.',
'image' => ':Attribute ha de ser una imatge.',
'in' => ':Attribute és invàlid',
'in_array' => 'El camp :attribute no existeix dintre de :other.',
'in_array_keys' => 'El camp :attribute ha de contenir almenys una de les tecles següents: :values.',
'integer' => ':Attribute ha de ser un nombre enter.',
'ip' => ':Attribute ha de ser una adreça IP vàlida.',
'ipv4' => ':Attribute ha de ser una adreça IPv4 vàlida.',
'ipv6' => ':Attribute ha de ser una adreça IPv6 vàlida.',
'json' => 'El camp :attribute ha de ser una cadena JSON vàlida.',
'list' => 'El camp :attribute ha de ser una llista.',
'lowercase' => 'El :attribute ha d\'anar en minúscula.',
'lt' => [
'array' => 'El :attribute ha de tenir menys de :value ítems.',
'file' => 'El :attribute ha de ser inferior a :value kilobytes.',
'numeric' => 'El :attribute ha de ser inferior a :value.',
'string' => 'El :attribute no ha de superar els :value caràcters.',
],
'lte' => [
'array' => 'El :attribute no ha de tenir més de :value ítems.',
'file' => 'El :attribute ha de ser igual o inferior a :value kilobytes.',
'numeric' => 'El :attribute ha de ser igual o inferior a :value.',
'string' => 'El :attribute ha de ser igual o inferior a :value caràcters.',
],
'mac_address' => 'El :attribute ha de ser una adreça MAC vàlida.',
'max' => [
'array' => ':Attribute no pot tenir més de :max ítems.',
'file' => ':Attribute no pot ser més gran que :max kilobytes.',
'numeric' => ':Attribute no pot ser més gran que :max.',
'string' => ':Attribute no pot ser més gran que :max caràcters.',
],
'max_digits' => 'El :attribute no ha de tenir més de :max dígits.',
'mimes' => ':Attribute ha de ser un arxiu amb format: :values.',
'mimetypes' => ':Attribute ha de ser un arxiu amb format: :values.',
'min' => [
'array' => ':Attribute ha de tenir almenys :min ítems.',
'file' => 'La mida de :attribute ha de ser d\'almenys :min kilobytes.',
'numeric' => 'La mida de :attribute ha de ser d\'almenys :min.',
'string' => ':Attribute ha de contenir almenys :min caràcters.',
],
'min_digits' => 'El :attribute ha de tenir almenys :min dígits.',
'missing' => 'El camp :attribute ha de faltar.',
'missing_if' => 'El camp :attribute ha de faltar quan :other és :value.',
'missing_unless' => 'El camp :attribute ha de faltar, tret que :other sigui :value.',
'missing_with' => 'El camp :attribute ha de faltar quan hi ha :values.',
'missing_with_all' => 'El camp :attribute ha de faltar quan n\'hi ha :values.',
'multiple_of' => 'La :attribute ha de ser un múltiple de :value',
'not_in' => ':Attribute és invàlid.',
'not_regex' => 'El format de :attribute no és vàlid.',
'numeric' => ':Attribute ha de ser numèric.',
'password' => [
'letters' => 'El :attribute ha de contenir almenys una lletra.',
'mixed' => 'El :attribute ha de contenir almenys una lletra majúscula i una minúscula.',
'numbers' => 'El :attribute ha de contenir almenys un número.',
'symbols' => 'El :attribute ha de contenir almenys un símbol.',
'uncompromised' => 'El :attribute donat ha aparegut en una filtració de dades. Si us plau, trieu un :attribute diferent.',
],
'present' => 'El camp :attribute ha d\'existir.',
'present_if' => 'El camp :attribute ha d\'estar present quan :other és :value.',
'present_unless' => 'El camp :attribute ha d\'estar present tret que :other sigui :value.',
'present_with' => 'El camp :attribute ha d\'estar present quan n\'hi ha :values.',
'present_with_all' => 'El camp :attribute ha d\'estar present quan n\'hi ha :values.',
'prohibited' => 'La :attribute camp està prohibit.',
'prohibited_if' => 'La :attribute camp és prohibida quan :other és :value.',
'prohibited_if_accepted' => 'El camp :attribute està prohibit quan s’accepta :other.',
'prohibited_if_declined' => 'El camp :attribute està prohibit quan es declina :other.',
'prohibited_unless' => 'La :attribute camp és prohibida, tret que :other és en :values.',
'prohibits' => 'El camp :attribute prohibeix la presència de :other.',
'regex' => 'El format de :attribute és invàlid.',
'required' => 'El camp :attribute és obligatori.',
'required_array_keys' => 'El camp :attribute ha de contenir entrades per a: :values.',
'required_if' => 'El camp :attribute és obligatori quan :other és :value.',
'required_if_accepted' => 'El camp :attribute és obligatori quan s\'accepta :other.',
'required_if_declined' => 'El camp :attribute és obligatori quan es rebutja :other.',
'required_unless' => 'El camp :attribute és obligatori a no ser que :other sigui a :values.',
'required_with' => 'El camp :attribute és obligatori quan hi ha :values.',
'required_with_all' => 'El camp :attribute és obligatori quan hi ha :values.',
'required_without' => 'El camp :attribute és obligatori quan no hi ha :values.',
'required_without_all' => 'El camp :attribute és obligatori quan no hi ha cap valor dels següents: :values.',
'same' => ':Attribute i :other han de coincidir.',
'size' => [
'array' => ':Attribute ha de contenir :size ítems.',
'file' => 'La mida de :attribute ha de ser :size kilobytes.',
'numeric' => 'La mida de :attribute ha de ser :size.',
'string' => ':Attribute ha de contenir :size caràcters.',
],
'starts_with' => 'El :attribute ha de començar per un dels valors següents: :values',
'string' => 'El camp :attribute ha de ser una cadena.',
'timezone' => 'El camp :attribute ha de ser una zona vàlida.',
'ulid' => 'El :attribute ha de ser un ULID vàlid.',
'unique' => ':Attribute ja està registrat i no es pot repetir.',
'uploaded' => ':Attribute ha fallat al pujar.',
'uppercase' => 'El :attribute ha d\'anar en majúscula.',
'url' => ':Attribute no és una adreça web vàlida.',
'uuid' => 'El :attribute ha de ser un indentificador únic universal (UUID) vàlid.',
'attributes' => [
'address' => 'adreça',
'affiliate_url' => 'URL d\'afiliat',
'age' => 'edat',
'amount' => 'quantitat',
'announcement' => 'anunci',
'area' => 'zona',
'audience_prize' => 'premi del públic',
'audience_winner' => 'audience winner',
'available' => 'disponible',
'birthday' => 'aniversari',
'body' => 'cos',
'city' => 'ciutat',
'color' => 'color',
'company' => 'company',
'compilation' => 'compilació',
'concept' => 'concepte',
'conditions' => 'condicions',
'content' => 'contingut',
'contest' => 'contest',
'country' => 'país',
'cover' => 'coberta',
'created_at' => 'creat a',
'creator' => 'creador',
'currency' => 'moneda',
'current_password' => 'Contrasenya actual',
'customer' => 'client',
'date' => 'data',
'date_of_birth' => 'data de naixement',
'dates' => 'dates',
'day' => 'dia',
'deleted_at' => 'esborrat a les',
'description' => 'descripció',
'display_type' => 'tipus de visualització',
'district' => 'districte',
'duration' => 'durada',
'email' => 'adreça electrònica',
'excerpt' => 'extracte',
'filter' => 'filtre',
'finished_at' => 'acabat a les',
'first_name' => 'nom',
'gender' => 'gènere',
'grand_prize' => 'gran premi',
'group' => 'grup',
'hour' => 'hora',
'image' => 'imatge',
'image_desktop' => 'imatge d\'escriptori',
'image_main' => 'imatge principal',
'image_mobile' => 'imatge mòbil',
'images' => 'imatges',
'is_audience_winner' => 'és el guanyador del públic',
'is_hidden' => 'està amagat',
'is_subscribed' => 'està subscrit',
'is_visible' => 'és visible',
'is_winner' => 'és el guanyador',
'items' => 'elements',
'key' => 'clau',
'last_name' => 'cognom',
'lesson' => 'lliçó',
'line_address_1' => 'adreça de línia 1',
'line_address_2' => 'adreça de línia 2',
'login' => 'iniciar Sessió',
'message' => 'missatge',
'middle_name' => 'segon nom',
'minute' => 'minut',
'mobile' => 'mòbil',
'month' => 'mes',
'name' => 'nom',
'national_code' => 'codi nacional',
'number' => 'nombre',
'password' => 'contrasenya',
'password_confirmation' => 'confirmació de la contrasenya',
'phone' => 'telèfon',
'photo' => 'foto',
'portfolio' => 'cartera',
'postal_code' => 'Codi Postal',
'preview' => 'Vista prèvia',
'price' => 'preu',
'product_id' => 'ID del producte',
'product_uid' => 'UID del producte',
'product_uuid' => 'UUID del producte',
'promo_code' => 'codi promocional',
'province' => 'província',
'quantity' => 'quantitat',
'reason' => 'raó',
'recaptcha_response_field' => 'camp de resposta recaptcha',
'referee' => 'àrbitre',
'referees' => 'àrbitres',
'region' => 'region',
'reject_reason' => 'rebutjar la raó',
'remember' => 'recorda',
'restored_at' => 'restaurat a',
'result_text_under_image' => 'text del resultat sota la imatge',
'role' => 'paper',
'rule' => 'regla',
'rules' => 'regles',
'second' => 'segon',
'sex' => 'sexe',
'shipment' => 'enviament',
'short_text' => 'text breu',
'size' => 'mida',
'skills' => 'habilitats',
'slug' => 'llimac',
'specialization' => 'especialització',
'started_at' => 'va començar a',
'state' => 'estat',
'status' => 'estat',
'street' => 'carrer',
'student' => 'estudiant',
'subject' => 'assumpte',
'tag' => 'etiqueta',
'tags' => 'etiquetes',
'teacher' => 'professor',
'terms' => 'termes',
'test_description' => 'descripció de la prova',
'test_locale' => 'localització de prova',
'test_name' => 'nom de la prova',
'text' => 'text',
'time' => 'hora',
'title' => 'títol',
'type' => 'tipus',
'updated_at' => 'actualitzat a',
'user' => 'usuari',
'username' => 'usuari',
'value' => 'valor',
'winner' => 'winner',
'work' => 'work',
'year' => 'any',
],
];