PHPackages                             yezzmedia/laravel-ops-settings - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. yezzmedia/laravel-ops-settings

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

yezzmedia/laravel-ops-settings
==============================

Operator-managed global platform settings for the Yezz Media Laravel website platform.

00PHP

Since May 13Pushed 3w agoCompare

[ Source](https://github.com/yezzmedia/laravel-ops-settings)[ Packagist](https://packagist.org/packages/yezzmedia/laravel-ops-settings)[ RSS](/packages/yezzmedia-laravel-ops-settings/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependenciesVersions (2)Used By (0)

laravel-ops-settings
====================

[](#laravel-ops-settings)

Operator-managed global platform settings for the Yezz Media Laravel website platform.

Provides six structured settings groups (identity, contact, brand, social, legal, website defaults) backed by [`spatie/laravel-settings`](https://github.com/spatie/laravel-settings) v3, with a cache-aware manager, guarded mutations, audit events, a foundation-integrated install flow, and a Filament-powered operator workspace.

Requirements
------------

[](#requirements)

DependencyVersionPHP`^8.4`Laravel`^13.0`yezzmedia/laravel-foundation`^0.1`spatie/laravel-settings`^3.0`Optional:

- `spatie/laravel-activitylog ^5.0` for persisted ops-settings audit records

Installation
------------

[](#installation)

```
composer require yezzmedia/laravel-ops-settings
```

The service provider is registered automatically via Laravel's package discovery.

### Install flow

[](#install-flow)

Run the foundation install command to publish migrations, verify the settings store, and seed defaults:

```
php artisan website:install
```

Or step through manually:

```
# 1. Publish the settings migrations
php artisan vendor:publish --tag=laravel-ops-settings-migrations

# 2. Run migrations
php artisan migrate

# 3. Seed defaults (optional)
php artisan db:seed --class="YezzMedia\OpsSettings\Database\Seeders\OpsSettingsDefaultsSeeder"
```

### Audit persistence

[](#audit-persistence)

Persisted ops-settings audit is optional.

Manual setup:

```
composer require spatie/laravel-activitylog
php artisan vendor:publish --tag=ops-settings-config
```

Then set `ops-settings.audit.driver` to `activitylog`.

Central install flow:

```
php artisan website:install --configure-audit --audit-package=yezzmedia/laravel-ops-settings
php artisan website:install --configure-audit --audit-package=all
```

Operator workspace
------------------

[](#operator-workspace)

When the consuming application exposes the ops panel, the package registers a central `OpsSettingsPage` workspace.

The workspace includes:

- one visible tabbed workspace page for all six settings groups
- per-tab save boundaries through `UpdateOpsSettingsAction`
- readiness snapshot and grouped completion badges
- workspace overview cards with missing-required-field summaries
- recent-changes audit table sourced from persisted ops-settings activity when available
- curated region presets for `de`, `ch`, `at`, and `us`
- JSON export/import helpers for grouped snapshot review
- searchable selects for locale, timezone, currency, date format, time format, and country code

The page keeps the legacy single-group pages registered as hidden deep-link compatibility pages, while the visible navigation surface now points at the central workspace.

### Password confirmation workflow

[](#password-confirmation-workflow)

Destructive mutations inside the central workspace require explicit password confirmation.

The current protected paths include:

- group save actions through `saveIdentity()`, `saveContact()`, `saveBrand()`, `saveSocial()`, `saveLegal()`, and `saveWebsiteDefaults()`
- preset application through `applyPreset`
- snapshot import through `importSnapshot`

`confirmPassword()` stores a session-scoped confirmation timestamp and honors `ops-settings.security.password_confirmation.timeout`.

Configuration
-------------

[](#configuration)

Publish the config file:

```
php artisan vendor:publish --tag=ops-settings-config
```

`config/ops-settings.php`:

```
return [
    'cache' => [
        'enabled' => true,   // Toggle package-owned settings cache
        'store'   => null,   // Cache store to use (null = default)
    ],
    'audit' => [
        'driver' => null,    // null or 'activitylog'
    ],
    'defaults' => [
        'seed_on_install' => true, // Seed defaults during install flow
    ],

    'workspace' => [
        'history_limit' => 20,                 // Maximum recent audit rows shown in the workspace
        'presets' => ['de', 'ch', 'at', 'us'], // Curated region presets available in the workspace
    ],

    'security' => [
        'password_confirmation' => [
            'timeout' => 900, // Seconds that one password confirmation stays valid in the workspace session
        ],
    ],
];
```

When `audit.driver` is `null`, the package emits runtime audit events without persisting them. When `audit.driver` is `activitylog`, the package uses the activitylog-backed audit writer.

Settings Groups
---------------

[](#settings-groups)

GroupClass`::group()` keyDescriptionIdentity`OperatorIdentitySettings``identity`Operator name and platform labelContact`PlatformContactSettings``contact`Support channels, outbound email, URLs, and postal addressBrand`PlatformBrandSettings``brand`Brand copy, sender defaults, colors, and internal asset referencesSocial`PlatformSocialSettings``social`Official public social and community profile URLsLegal`PlatformLegalSettings``legal`Legal entity, registration, compliance URLs, and notice contentWebsite Defaults`PlatformWebsiteDefaultsSettings``website_defaults`Reusable locale, timezone, currency, formatting, and copy defaults### Properties

[](#properties)

**OperatorIdentitySettings**

PropertyTypeDescription`name``string`Operator display name`platform_label``?string`Sub-brand or multi-tenant label**PlatformContactSettings**

PropertyTypeDescription`support_email``?string`Primary support email address`noreply_email``?string`Outbound-only no-reply address`contact_phone``?string`Contact phone number`contact_whatsapp``?string`WhatsApp-compatible support number`support_url``?string`Canonical support or help-center URL`support_chat_url``?string`Canonical chat entry URL`support_hours``?string`Operator-authored support-hours copy`address_line_1``?string`Address line 1`address_line_2``?string`Address line 2`postal_code``?string`Postal code`city``?string`City`country_code``?string`ISO 3166-1 alpha-2 country code**PlatformBrandSettings**

PropertyTypeDescription`brand_name``?string`Brand display name`brand_tagline``?string`Short tagline`brand_claim``?string`Secondary brand claim or promise`default_email_from_name``?string`Default sender display name`primary_color``?string`Hex color (e.g. `#1a2b3c`)`secondary_color``?string`Hex color (e.g. `#1a2b3c`)`logo_reference``?string`Opaque internal asset reference`favicon_reference``?string`Internal favicon asset reference`icon_reference``?string`Internal icon-mark asset reference`email_logo_reference``?string`Internal email-logo asset reference**PlatformSocialSettings**

PropertyTypeDescription`facebook_url``?string`Absolute HTTPS URL`instagram_url``?string`Absolute HTTPS URL`linkedin_url``?string`Absolute HTTPS URL`x_url``?string`Absolute HTTPS URL`youtube_url``?string`Absolute HTTPS URL`tiktok_url``?string`Absolute HTTPS URL`threads_url``?string`Absolute HTTPS URL`github_url``?string`Absolute HTTPS URL`mastodon_url``?string`Absolute HTTPS URL`telegram_url``?string`Absolute HTTPS URL**PlatformLegalSettings**

PropertyTypeDescription`legal_entity_name``?string`Formal legal entity name`managing_director``?string`Responsible managing director or executive`registration_number``?string`Company registration number`registration_court``?string`Registration court or authority`vat_id``?string`VAT identification number`legal_notice_snippet``?string`Plaintext or Markdown (no raw HTML in V1)`privacy_contact_email``?string`Privacy / GDPR contact email`imprint_url``?string`Canonical imprint URL`privacy_policy_url``?string`Canonical privacy policy URL`terms_url``?string`Canonical terms URL`cookie_policy_url``?string`Canonical cookie policy URL**PlatformWebsiteDefaultsSettings**

PropertyTypeDescription`default_site_title_pattern``?string`Site title pattern for downstream packages`default_footer_label``?string`Global footer label fallback`default_support_label``?string`Global support label fallback`default_support_cta_label``?string`Global support CTA label fallback`default_reply_to_email``?string`Reply-to fallback for downstream mail usage`default_locale``?string`Default locale code`fallback_locale``?string`Fallback locale code`default_timezone``?string`Default timezone identifier`default_currency``?string`Default ISO 4217 currency code`default_date_format``?string`Default curated date format token`default_time_format``?string`Default curated time format tokenValidation and normalization
----------------------------

[](#validation-and-normalization)

`UpdateOpsSettingsAction` validates and normalizes approved group attributes before persistence.

Current validation highlights include:

- trimmed string input with empty-string-to-`null` normalization
- uppercase normalization for `country_code` and `default_currency`
- curated option validation for locale, currency, date format, and time format
- `timezone:all` validation for `default_timezone`
- URL validation for support, social, and legal page links
- hex color validation for `primary_color` and `secondary_color`
- enforcement that `noreply_email` must differ from `support_email`

Passing an approved key with an invalid value throws `InvalidArgumentException` with the first validation error message.

Reading Settings
----------------

[](#reading-settings)

Prefer `OpsSettingsManager` over direct storage access. It provides per-request memoization and optional cache-forever reads:

```
use YezzMedia\OpsSettings\Support\OpsSettingsManager;

$settings = app(OpsSettingsManager::class);

$settings->identity()->name;
$settings->contact()->support_email;
$settings->brand()->primary_color;
$settings->social()->instagram_url;
$settings->legal()->vat_id;
$settings->websiteDefaults()->default_site_title_pattern;

$settings->completionPercent();
$settings->groupStatuses();
$settings->identitySummary();
$settings->contactSummary();
$settings->websiteDefaultsSummary();
$settings->publicPayload();
$settings->internalPayload();
$settings->compliancePayload();
$settings->exportSnapshot();
$settings->presetValues('de');
$settings->recentHistory();
```

Additional grouped helpers include:

- `missingRequiredFields()` and `isComplete()` for workspace and ops readiness
- `groupStatuses()` for per-group completion metadata and latest audit entry lookup
- summary helpers for identity, contact, brand, legal, and website-default output
- `exportSnapshot()` for JSON-friendly grouped exports
- `recentHistory()` for normalized persisted audit rows when activity history is available

Updating Settings
-----------------

[](#updating-settings)

Use `UpdateOpsSettingsAction` for all mutations. It validates attributes against an approved property list, saves the settings, invalidates the cache, and dispatches `OpsSettingsUpdated`.

```
use YezzMedia\OpsSettings\Actions\UpdateOpsSettingsAction;
use YezzMedia\OpsSettings\Support\OpsSettingsGroup;

app(UpdateOpsSettingsAction::class)->execute(
    group: OpsSettingsGroup::Identity,
    attributes: ['name' => 'Acme Corp'],
    actorId: auth()->id(),
    context: [],
    source: 'admin-panel',
);
```

Passing an attribute that is not an approved property of the group throws `InvalidArgumentException`.

The action also backfills missing legacy keys before saving expanded settings groups, so older installations can safely adopt newer settings properties incrementally.

Authorization enforcement is the caller's responsibility.

Events
------

[](#events)

### `OpsSettingsUpdated`

[](#opssettingsupdated)

Dispatched after every successful `UpdateOpsSettingsAction::execute()` call.

PropertyTypeDescription`group``OpsSettingsGroup`The settings group that was updated`changedKeys``array`Attribute keys that were changed`actorId``int|string|null`ID of the actor who triggered the update`oldValues``array`Previous values for the changed keys`newValues``array`Persisted values after the update`context``array`Arbitrary caller-provided context`source``?string`String identifying the update sourceAudit integration
-----------------

[](#audit-integration)

The package defines the `ops.settings.updated` audit event through foundation metadata and writes persisted audit only when explicitly configured.

It also defines security-governance metadata through foundation:

- security request: `ops-settings.request.auth.password-confirmation`
- security requirement: `ops-settings.auth.password-confirmation`

The package keeps enforcement package-owned: `yezzmedia/laravel-ops-security` verifies that the confirmation workflow exists, but the actual confirmation UX remains on the ops-settings page.

Audit writer behavior:

- `ops-settings.audit.driver=null`: use `NullOpsSettingsAuditWriter`
- `ops-settings.audit.driver=activitylog`: use `ActivityLogOpsSettingsAuditWriter`

If `activitylog` is configured but `spatie/laravel-activitylog` is missing, the package fails explicitly during binding.

The foundation audit installer updates package config only. It does not run the ordinary ops-settings install flow, migrations, or default seeding.

Doctor checks
-------------

[](#doctor-checks)

The package registers four doctor checks through foundation:

- `audit_configured`
    - `skipped` when the host ops audit provider is not configured in the current environment
    - `passed` when `ops-settings.audit.driver=activitylog`
    - `warning` when persisted audit is intentionally disabled
    - `failed` when an unsupported audit driver is configured
- `settings_completeness`
    - `passed` when all required baseline ops settings fields are filled
    - `warning` when required fields are still missing
- `settings_consistency`
    - `passed` when core defaults are internally consistent
    - `warning` when conflicting defaults are detected, such as matching support/no-reply emails or identical default and fallback locales
- `settings_store_ready`
    - `passed` when the settings store is present and all published ops-settings migrations are applied
    - `failed` when the settings table or required migrations are missing
    - `warning` when the settings table exists but published ops-settings migrations are still pending

Permissions
-----------

[](#permissions)

NameDescription`ops.settings.view`Read operator-managed global platform settings`ops.settings.manage`Mutate operator-managed global platform settingsPermissions are registered via `OpsSettingsPlatformPackage` and synchronized by `yezzmedia/laravel-access`.

Operators can opt this package into persisted audit through `website:install --configure-audit --audit-package=yezzmedia/laravel-ops-settings`.

Runtime partitions
------------------

[](#runtime-partitions)

`OpsSettingsGroup` now classifies approved properties into runtime-friendly partitions so downstream consumers can choose the right payload surface:

- public properties for broadly reusable, safe presentation defaults
- internal properties for package-owned asset references and similar internal wiring
- compliance-sensitive properties for legal and regulated data handling

Use `publicPayload()`, `internalPayload()`, and `compliancePayload()` on `OpsSettingsManager` instead of building these partitions manually.

Testing
-------

[](#testing)

This package ships a `OpsSettingsTestCase` for use in consuming packages:

```
use YezzMedia\OpsSettings\Tests\OpsSettingsTestCase;

uses(OpsSettingsTestCase::class);
```

Run the package test suite:

```
composer test
```

License
-------

[](#license)

MIT — see [LICENSE](LICENSE) for details.

###  Health Score

20

—

LowBetter than 13% of packages

Maintenance62

Regular maintenance activity

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity13

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/107888802?v=4)[Yezz-Media](/maintainers/yezzmedia)[@yezzmedia](https://github.com/yezzmedia)

---

Top Contributors

[![yezzmedia](https://avatars.githubusercontent.com/u/107888802?v=4)](https://github.com/yezzmedia "yezzmedia (15 commits)")

### Embed Badge

![Health badge](/badges/yezzmedia-laravel-ops-settings/health.svg)

```
[![Health](https://phpackages.com/badges/yezzmedia-laravel-ops-settings/health.svg)](https://phpackages.com/packages/yezzmedia-laravel-ops-settings)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
