diff --git a/.env.example b/.env.example index 084f8e4..100e89c 100644 --- a/.env.example +++ b/.env.example @@ -67,6 +67,8 @@ VITE_APP_NAME="${APP_NAME}" # Demo Mode Configuration (set to true on demo server only) DEMO_MODE=false +# Optional host-only Packagist snapshots; requires Laravel's scheduler. +LARACOREKIT_COLLECT_STATS=false DEMO_RESET_INTERVAL=30 DEMO_ADMIN_EMAIL=admin@laracorekit.com DEMO_ADMIN_PASSWORD=Admin@123 diff --git a/.github/IMPLEMENTATION_CHECKLIST.md b/.github/IMPLEMENTATION_CHECKLIST.md index 8776db1..2ebf1df 100644 --- a/.github/IMPLEMENTATION_CHECKLIST.md +++ b/.github/IMPLEMENTATION_CHECKLIST.md @@ -1,5 +1,7 @@ # LaraCoreKit - Implementation Checklist +Historical checklist from the earlier host audit. For the current package extraction, validation evidence and external release blockers, see [implementation report](../docs/implementation-report.md). + This document tracks the implementation of improvements based on the comprehensive audit report. ## Must-Fix Priority Items diff --git a/.github/README_REPOSITORY.md b/.github/README_REPOSITORY.md index d418efa..36ea16e 100644 --- a/.github/README_REPOSITORY.md +++ b/.github/README_REPOSITORY.md @@ -3,7 +3,7 @@ Use this for the GitHub repository About/Description section: ``` -Modular Laravel 13 starter kit with Filament 5, Livewire 4, Tailwind 4, multilingual content, RTL support, auth, roles/permissions, blog, settings, media, and publishable add-on modules. +Modular Laravel foundation for public websites and Filament administration. Reusable Composer package, documentation, demo host and component examples. ``` ## Topics/Tags diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..5f470bd --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,22 @@ +version: 2 +updates: + - package-ecosystem: composer + directory: / + schedule: + interval: weekly + open-pull-requests-limit: 5 + - package-ecosystem: npm + directory: / + schedule: + interval: weekly + open-pull-requests-limit: 5 + - package-ecosystem: composer + directory: /packages/core + schedule: + interval: weekly + open-pull-requests-limit: 5 + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + open-pull-requests-limit: 5 diff --git a/.github/package-workflows/dependabot.yml b/.github/package-workflows/dependabot.yml new file mode 100644 index 0000000..77a41d2 --- /dev/null +++ b/.github/package-workflows/dependabot.yml @@ -0,0 +1,10 @@ +version: 2 +updates: + - package-ecosystem: composer + directory: / + schedule: + interval: weekly + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly diff --git a/.github/package-workflows/prepare-release.yml b/.github/package-workflows/prepare-release.yml new file mode 100644 index 0000000..a9d1826 --- /dev/null +++ b/.github/package-workflows/prepare-release.yml @@ -0,0 +1,62 @@ +name: Prepare Release PR +on: + workflow_dispatch: + inputs: + version: + description: 'Reviewed stable version without v (example: 0.1.0)' + required: true +permissions: + contents: read +jobs: + propose: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + - name: Validate version and prepare release notes + env: + RELEASE_VERSION: ${{ inputs.version }} + run: | + python3 - <<'PY' + import os, re, subprocess + from pathlib import Path + from datetime import date + version = os.environ['RELEASE_VERSION'] + if not re.fullmatch(r'(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)', version): + raise SystemExit('Use a stable semantic version, e.g. 0.1.0.') + if subprocess.run(['git', 'rev-parse', '--verify', 'refs/tags/v'+version], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode == 0: + raise SystemExit('That release tag already exists.') + path = Path('CHANGELOG.md') + text = path.read_text() + if '## Unreleased' not in text: + raise SystemExit('Missing Unreleased notes.') + text = text.replace('## Unreleased', '## Unreleased\n\n## '+version+' - '+date.today().isoformat(), 1) + path.write_text(text) + PY + - uses: shivammathur/setup-php@v2 + with: + php-version: '8.3' + extensions: dom, curl, mbstring, zip, pdo_sqlite, bcmath, intl, gd, exif + coverage: none + - run: composer validate --strict + - run: composer install --no-dev --prefer-dist --no-interaction + - run: composer audit + - name: Open draft release PR + env: + GH_TOKEN: ${{ github.token }} + GH_REPO: ${{ github.repository }} + RELEASE_VERSION: ${{ inputs.version }} + run: | + branch="codex/release-$RELEASE_VERSION" + git switch -c "$branch" + git config user.name 'github-actions[bot]' + git config user.email '41898282+github-actions[bot]@users.noreply.github.com' + git add CHANGELOG.md + git commit -m "Prepare v$RELEASE_VERSION release notes" + git push --set-upstream origin "$branch" + printf 'Prepare version %s.\n\nBefore publishing: verify monorepo regression/consumer checks and package export, review compatibility and these release notes. After merge, tag the reviewed package commit and publish the GitHub release; Packagist indexes the tag. This workflow creates no release tag and does not publish.\n' "$RELEASE_VERSION" > "$RUNNER_TEMP/release-body.md" + gh pr create --base main --head "$branch" --draft --title "Prepare v$RELEASE_VERSION" --body-file "$RUNNER_TEMP/release-body.md" diff --git a/.github/package-workflows/sync-source.yml b/.github/package-workflows/sync-source.yml new file mode 100644 index 0000000..27b1a28 --- /dev/null +++ b/.github/package-workflows/sync-source.yml @@ -0,0 +1,91 @@ +name: Sync Package Source +on: + workflow_dispatch: + schedule: + - cron: '17 8 * * *' +permissions: + contents: read +jobs: + propose: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - uses: actions/checkout@v6 + with: + path: distribution + - uses: actions/checkout@v6 + with: + repository: ProgrammerNomad/LaraCoreKit + ref: main + path: source + persist-credentials: false + - name: Check source availability and pending proposals + id: source + env: + GH_TOKEN: ${{ github.token }} + GH_REPO: ${{ github.repository }} + run: | + if [ ! -f source/packages/core/composer.json ]; then + echo 'Package extraction is not on the monorepo main branch yet.' + exit 0 + fi + pending=$(gh pr list --state open --label package-sync --json number --jq length) + if [ "$pending" != '0' ]; then + echo 'A package source proposal is already waiting for review.' + exit 0 + fi + echo 'ready=true' >> "$GITHUB_OUTPUT" + - if: steps.source.outputs.ready == 'true' + uses: shivammathur/setup-php@v2 + with: + php-version: '8.3' + extensions: dom, curl, mbstring, zip, pdo_sqlite, bcmath, intl, gd, exif + coverage: none + - if: steps.source.outputs.ready == 'true' + uses: actions/setup-node@v6 + with: + node-version: '24' + cache: npm + cache-dependency-path: source/package-lock.json + - name: Validate the monorepo source and prepare the package + if: steps.source.outputs.ready == 'true' + working-directory: source + run: | + composer install --prefer-dist --no-interaction + cp .env.example .env + php artisan key:generate + composer validate --strict + composer --working-dir=packages/core validate --strict + composer review + composer audit --locked + npm ci + npm audit + npm run build:core + python3 tools/consumer-smoke.py + python3 tools/package-release.py + - name: Propose a package-only source update + if: steps.source.outputs.ready == 'true' + working-directory: distribution + env: + GH_TOKEN: ${{ github.token }} + GH_REPO: ${{ github.repository }} + run: | + branch="codex/package-sync-$GITHUB_RUN_ID" + source_sha=$(git -C ../source rev-parse HEAD) + git switch -c "$branch" + # Preserve this repository's own maintenance workflow. + git rm -r --ignore-unmatch -- . ':!.github' + unzip -oq ../source/storage/app/releases/laracorekit-preview.zip + git add -A + if git diff --cached --quiet; then + echo 'Package source is already current.' + exit 0 + fi + git config user.name 'github-actions[bot]' + git config user.email '41898282+github-actions[bot]@users.noreply.github.com' + git commit -m "Sync package source from $source_sha" + git push --set-upstream origin "$branch" + printf 'Update package source from LaraCoreKit commit %s.\n\nMonorepo checks, dependency audits and clean-consumer installation passed. Review and merge before creating a release tag.\n' "$source_sha" > "$RUNNER_TEMP/package-sync-body.md" + gh pr create --base main --head "$branch" --draft --label package-sync --title 'Sync LaraCoreKit package source' --body-file "$RUNNER_TEMP/package-sync-body.md" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index dce8c51..43ae380 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,38 +1,28 @@ name: Build Assets - on: push: - branches: [ main, develop ] + branches: [main, develop] pull_request: - branches: [ main, develop ] - + branches: [main, develop] +permissions: + contents: read jobs: build: runs-on: ubuntu-latest - name: Build Frontend Assets - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 + - uses: actions/checkout@v6 + - uses: shivammathur/setup-php@v2 with: - node-version: '20' - cache: 'npm' - - - name: Install dependencies - run: npm ci - - - name: Build assets - run: npm run build - - - name: Check for build errors - run: | - if [ -d "public/build" ]; then - echo "Build directory created successfully" - ls -la public/build - else - echo "Build directory not found!" - exit 1 - fi + php-version: '8.3' + extensions: intl, gd, exif, zip + coverage: none + - run: composer install --prefer-dist --no-interaction + - uses: actions/setup-node@v6 + with: + node-version: '24' + cache: npm + - run: npm ci + - run: npm audit + - run: npm run build:core + - run: npm run build + - run: git diff --exit-code -- packages/core/resources/dist diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml index 5d6990f..d1b63ae 100644 --- a/.github/workflows/code-quality.yml +++ b/.github/workflows/code-quality.yml @@ -1,50 +1,23 @@ name: Code Quality - on: push: - branches: [ main, develop ] + branches: [main, develop] pull_request: - branches: [ main, develop ] - + branches: [main, develop] +permissions: + contents: read jobs: - pint: + quality: runs-on: ubuntu-latest - name: Laravel Pint - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup PHP - uses: shivammathur/setup-php@v2 + - uses: actions/checkout@v6 + - uses: shivammathur/setup-php@v2 with: - php-version: 8.3 - extensions: dom, curl, libxml, mbstring, zip + php-version: '8.3' + extensions: dom, curl, mbstring, zip, pdo_sqlite, bcmath, intl, gd, exif coverage: none - - - name: Install dependencies - run: composer install --prefer-dist --no-interaction - - - name: Run Pint - run: vendor/bin/pint --test - - phpstan: - runs-on: ubuntu-latest - name: PHPStan - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: 8.3 - extensions: dom, curl, libxml, mbstring, zip - coverage: none - - - name: Install dependencies - run: composer install --prefer-dist --no-interaction - - - name: Run PHPStan - run: vendor/bin/phpstan analyse --memory-limit=2G + - run: composer install --prefer-dist --no-interaction + - run: cp .env.example .env + - run: php artisan key:generate + - run: composer pint-test + - run: composer phpstan diff --git a/.github/workflows/consumer.yml b/.github/workflows/consumer.yml new file mode 100644 index 0000000..d618b24 --- /dev/null +++ b/.github/workflows/consumer.yml @@ -0,0 +1,24 @@ +name: Clean Package Consumer +on: + push: + branches: [main, develop] + pull_request: + branches: [main, develop] +permissions: + contents: read +jobs: + install: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + source: [path, packagist] + name: Install from ${{ matrix.source }} + steps: + - uses: actions/checkout@v6 + - uses: shivammathur/setup-php@v2 + with: + php-version: '8.3' + extensions: dom, curl, mbstring, zip, pdo_sqlite, bcmath, intl, gd, exif + coverage: none + - run: python3 tools/consumer-smoke.py --source ${{ matrix.source }} diff --git a/.github/workflows/package-preview.yml b/.github/workflows/package-preview.yml new file mode 100644 index 0000000..b0106f3 --- /dev/null +++ b/.github/workflows/package-preview.yml @@ -0,0 +1,37 @@ +name: Package Release Preview +on: + workflow_dispatch: +permissions: + contents: read +jobs: + package: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: shivammathur/setup-php@v2 + with: + php-version: '8.3' + extensions: dom, curl, mbstring, zip, pdo_sqlite, bcmath, intl, gd, exif + coverage: none + - uses: actions/setup-node@v6 + with: + node-version: '24' + cache: npm + - run: composer install --prefer-dist --no-interaction + - run: cp .env.example .env + - run: php artisan key:generate + - run: composer validate --strict + - run: composer --working-dir=packages/core validate --strict + - run: composer audit --locked + - run: composer review + - run: npm ci + - run: npm audit + - run: npm run build:core + - run: python3 tools/consumer-smoke.py + - run: python3 tools/package-release.py + - uses: actions/upload-artifact@v7 + with: + name: laracorekit-package-preview + path: storage/app/releases/ + if-no-files-found: error + retention-days: 14 diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml new file mode 100644 index 0000000..9409ffc --- /dev/null +++ b/.github/workflows/security.yml @@ -0,0 +1,21 @@ +name: Dependency Security +on: + schedule: + - cron: '23 7 * * 2' + workflow_dispatch: +permissions: + contents: read +jobs: + audit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: shivammathur/setup-php@v2 + with: + php-version: '8.3' + coverage: none + - uses: actions/setup-node@v6 + with: + node-version: '24' + - run: composer audit --locked + - run: npm audit --package-lock-only diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d649e63..811bfbe 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,57 +1,63 @@ name: Tests - on: push: - branches: [ main, develop ] + branches: [main, develop] pull_request: - branches: [ main, develop ] - + branches: [main, develop] +permissions: + contents: read jobs: tests: runs-on: ubuntu-latest - strategy: fail-fast: false matrix: - php: [8.3] - laravel: [13.*] - stability: [prefer-stable] - - name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }} - ${{ matrix.stability }} - + php: ['8.3', '8.5'] + dependencies: [locked, compatible] + name: PHP ${{ matrix.php }} / ${{ matrix.dependencies }} steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup PHP - uses: shivammathur/setup-php@v2 + - uses: actions/checkout@v6 + - uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} - extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv + extensions: dom, curl, mbstring, zip, pdo_sqlite, bcmath, intl, gd, exif + coverage: none + - run: composer validate --strict + - run: composer --working-dir=packages/core validate --strict + - if: matrix.dependencies == 'locked' + run: composer install --prefer-dist --no-interaction + - if: matrix.dependencies == 'compatible' + run: composer update --with-all-dependencies --prefer-dist --no-interaction + - run: cp .env.example .env + - run: php artisan key:generate + - run: composer audit --locked + - run: composer test + + mysql: + runs-on: ubuntu-latest + services: + mysql: + image: mysql:8.0 + env: + MYSQL_ROOT_PASSWORD: testing + MYSQL_DATABASE: laracorekit_test + ports: ['3306:3306'] + options: >- + --health-cmd="mysqladmin ping -ptesting" + --health-interval=10s + --health-timeout=5s + --health-retries=10 + env: + DB_PORT: '3306' + DB_PASSWORD: testing + steps: + - uses: actions/checkout@v6 + - uses: shivammathur/setup-php@v2 + with: + php-version: '8.3' + extensions: dom, curl, mbstring, zip, pdo_mysql, bcmath, intl, gd, exif coverage: none - - - name: Setup problem matchers - run: | - echo "::add-matcher::${{ runner.tool_cache }}/php.json" - echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" - - - name: Install dependencies - run: | - composer require "laravel/framework:${{ matrix.laravel }}" --no-interaction --no-update - composer update --${{ matrix.stability }} --prefer-dist --no-interaction - - - name: Create SQLite database - run: | - mkdir -p database - touch database/database.sqlite - - - name: Setup environment - run: | - cp .env.example .env - php artisan key:generate - - - name: Run migrations - run: php artisan migrate --force - - - name: Execute tests - run: vendor/bin/phpunit --testdox + - run: composer install --prefer-dist --no-interaction + - run: cp .env.example .env + - run: php artisan key:generate + - run: php vendor/bin/phpunit --configuration phpunit.mysql.xml diff --git a/.gitignore b/.gitignore index d99a643..ed579b1 100644 --- a/.gitignore +++ b/.gitignore @@ -48,5 +48,12 @@ Thumbs.db /storage/logs/*.log .github/copilot-instructions.md /package-files -/storage/framework/sessions -/storage/framework/views +/storage/framework/sessions/* +!/storage/framework/sessions/.gitignore +/storage/framework/views/* +!/storage/framework/views/.gitignore +/packages/**/vendor +/packages/**/node_modules +/packages/**/composer.lock +/storage/framework/cache/phpstan/ +/storage/app/releases/ diff --git a/CHANGELOG.md b/CHANGELOG.md index e79deb0..94ff184 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Package extraction and website refresh +- Extract `programmernomad/laracorekit` under `packages/core`, bundling both public frontend and admin modules with auto-discovery. +- Move marketing pages and sample seeders into the host; retain Docs/UIShowcase/demo integrations outside the package. +- Add an explicit installer, prebuilt public CSS, interactive administrator creation and clean-consumer smoke testing. +- Update compatible PHP dependencies and the Vite toolchain; separate showcase JavaScript from ordinary pages. +- Add authentication throttling, safe seed defaults, direct resource access checks, settings save authorization and public blog sanitization/publication checks. +- Redesign the website, add mobile navigation and real screenshots, and correct installation/features/upgrade documentation. +- Add machine-readable docs, page descriptions, full documentation sitemap coverage and accurate source-code metadata. +- Add dependency proposals, scheduled security checks and separate locked/compatible PHP CI lanes. + +This package release is prepared locally; registry publication and deployment are separate steps. Earlier entries below describe historical host changes. + + ### Added - Installed `bezhansalleh/filament-language-switch` plugin for a native Filament admin topbar language switcher - Configured `LanguageSwitch` in `AppServiceProvider` with locales `en`, `hi`, `ar`, native labels, and circular avatars diff --git a/CODEOWNERS b/CODEOWNERS index 27d7f7f..601d57d 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -4,14 +4,14 @@ * @ProgrammerNomad @shivsingh # Core modules -/modules/Core/ @ProgrammerNomad -/modules/Auth/ @ProgrammerNomad -/modules/User/ @ProgrammerNomad +/packages/core/modules/Core/ @ProgrammerNomad +/packages/core/modules/Auth/ @ProgrammerNomad +/packages/core/modules/User/ @ProgrammerNomad # Feature modules -/modules/Blog/ @ProgrammerNomad -/modules/Media/ @ProgrammerNomad -/modules/Settings/ @ProgrammerNomad +/packages/core/modules/Blog/ @ProgrammerNomad +/packages/core/modules/Media/ @ProgrammerNomad +/packages/core/modules/Settings/ @ProgrammerNomad # Documentation /docs/ @ProgrammerNomad @@ -30,3 +30,7 @@ package.json @ProgrammerNomad # Database migrations and seeders /database/migrations/ @ProgrammerNomad /database/seeders/ @ProgrammerNomad + +# Package registration, installer and release contract +/packages/core/ @ProgrammerNomad +/tools/ @ProgrammerNomad diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 14cca4a..cf91107 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -60,13 +60,19 @@ Feature suggestions are welcome! Please: 7. **Push to your branch** (`git push origin feature/amazing-feature`) 8. **Open a Pull Request** +## Package and host ownership + +The Composer package is `programmernomad/laracorekit`, with public and admin modules under `packages/core`. The repository root hosts the website, documentation viewer, component showcase and demo integrations. Keep the local path repository and package directory together when developing from GitHub. Read `docs/installation.md` and `docs/upgrade-guide.md` before changing registration or installation behavior. + +Run `python tools/consumer-smoke.py` for an independent package installation in a disposable Laravel application. Never use real data for smoke tests or screenshots. Registration/telemetry is not required for package users. + ## Development Setup ### Prerequisites - PHP 8.3+ - Composer -- Node.js & NPM +- Node.js 22.12+ and npm (CI uses Node 24) - MySQL, PostgreSQL, or SQLite ### Local Installation @@ -78,7 +84,7 @@ cd LaraCoreKit # Install dependencies composer install -npm install +npm ci # Setup environment cp .env.example .env @@ -90,7 +96,7 @@ php artisan migrate --seed php artisan storage:link # Create admin user -php artisan filament:user +php artisan laracorekit:admin # Start development servers npm run dev @@ -113,6 +119,7 @@ vendor/bin/phpstan analyse composer review # Build assets +npm run build:core npm run build ``` @@ -271,7 +278,7 @@ php artisan test --filter=test_user_can_create_blog_post Each module should follow this structure: ``` -modules/YourModule/ +packages/your-addon/ ├── src/ │ ├── YourModuleServiceProvider.php │ ├── Http/ diff --git a/README.md b/README.md index 3140252..1a0c47e 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,11 @@ This is the main LaraCoreKit project repository: source development, documentati Laravel 13 · Filament 5 · Livewire 4 · Tailwind CSS 4 · PHP 8.3+ · MIT -[Packagist](https://packagist.org/packages/programmernomad/laracorekit) · [Demo website](https://www.laracorekit.com) · [Documentation](https://www.laracorekit.com/docs) · [Installation](https://github.com/ProgrammerNomad/LaraCoreKit/blob/aeef46c567f7c54734b20581acee4cd0394cf3e7/docs/installation.md) · [Security policy](https://github.com/ProgrammerNomad/LaraCoreKit/blob/aeef46c567f7c54734b20581acee4cd0394cf3e7/SECURITY.md) +[Packagist](https://packagist.org/packages/programmernomad/laracorekit) · [Demo website](https://www.laracorekit.com) · [Documentation](https://www.laracorekit.com/docs) · [Installation](docs/installation.md) · [Security policy](SECURITY.md) ## See the public site and admin -![LaraCoreKit walkthrough: public site, blog, administration and documentation](https://raw.githubusercontent.com/ProgrammerNomad/LaraCoreKit/aeef46c567f7c54734b20581acee4cd0394cf3e7/docs/images/screenshots/walkthrough.gif) +![LaraCoreKit walkthrough: public site, blog, administration and documentation](docs/images/screenshots/walkthrough.gif) Real views from the disposable demonstration application. The documentation viewer, component showcase, sample content and demo controls are host features outside the core package. @@ -18,6 +18,8 @@ Real views from the disposable demonstration application. The documentation view Install the published public frontend and Filament admin bundle in a fresh Laravel 13 application: +The `create-project` command installs Laravel and initializes its `.env`, application key and default SQLite database. Run the remaining commands inside `my-app`. `composer require` and `laracorekit:install` alone assume Laravel already exists and do not create the complete demo website. + ```bash composer create-project laravel/laravel my-app "^13.0" cd my-app @@ -34,34 +36,34 @@ php artisan storage:link php artisan serve ``` -Visit `/blog`, `/login` and `/admin`. Prebuilt assets ship with the package; the default package UI does not require npm. [Full installation and customization guide](https://github.com/ProgrammerNomad/LaraCoreKit/blob/aeef46c567f7c54734b20581acee4cd0394cf3e7/docs/installation.md). +Visit `/blog`, `/login` and `/admin`. Prebuilt assets ship with the package; the default package UI does not require npm. [Full installation and customization guide](docs/installation.md). ## Package and demo are separate -The reusable package **`programmernomad/laracorekit`** is maintained in [`packages/core`](https://github.com/ProgrammerNomad/LaraCoreKit/tree/aeef46c567f7c54734b20581acee4cd0394cf3e7/packages/core) and exported to the supporting [Composer distribution repository, laracorekit-package](https://github.com/ProgrammerNomad/laracorekit-package). It includes public authentication/blog pages, Filament administration, users, permissions, settings and media. +The reusable package **`programmernomad/laracorekit`** is maintained in [`packages/core`](packages/core) and exported to the supporting [Composer distribution repository, laracorekit-package](https://github.com/ProgrammerNomad/laracorekit-package). It includes public authentication/blog pages, Filament administration, users, permissions, settings and media. The optional [demo module](https://packagist.org/packages/programmernomad/laracorekit-demo-module) stays separate. Clone this monorepo to explore the demo or contribute; use the Composer installation above for your own application. -## Run the refreshed demo / development preview - -The refreshed modular demo and documentation source is being integrated through [PR #2](https://github.com/ProgrammerNomad/LaraCoreKit/pull/2). To run the version pictured here before that application change is merged, use its development branch: +## Run the complete GitHub host Requires Composer 2, PHP 8.3+ and Node 22.12+ (CI uses Node 24). ```bash -git clone --branch codex/laracorekit-distribution https://github.com/ProgrammerNomad/LaraCoreKit.git my-app +git clone https://github.com/ProgrammerNomad/LaraCoreKit.git my-app cd my-app +php -r "copy('.env.example', '.env');" composer install -npm ci ``` -Copy `.env.example` to `.env`, configure your database, then: +Laravel is already included in this checkout; do not run `composer create-project` here. Set `APP_URL=http://127.0.0.1:8000` in `.env`. The following local setup uses the default SQLite connection; create its empty database file first. For MySQL, configure your database and credentials instead. ```bash php artisan key:generate +php -r "file_exists('database/database.sqlite') || touch('database/database.sqlite');" php artisan migrate --seed php artisan laracorekit:admin php artisan storage:link +npm ci npm run build:core npm run build php artisan serve @@ -79,17 +81,17 @@ Normal seeding creates roles, not public sample accounts. Only a disposable demo | English, Hindi and Arabic language switching | Settings and media attachments | | RTL-aware shared layout | Configurable modules and view overrides | -API tokens, enforced email verification, billing, tenancy and a marketplace are not bundled. Check [architecture](https://github.com/ProgrammerNomad/LaraCoreKit/blob/aeef46c567f7c54734b20581acee4cd0394cf3e7/docs/core/architecture.md) and [production setup](https://github.com/ProgrammerNomad/LaraCoreKit/blob/aeef46c567f7c54734b20581acee4cd0394cf3e7/docs/deployment/production.md) before adopting. +API tokens, enforced email verification, billing, tenancy and a marketplace are not bundled. Check [architecture](docs/core/architecture.md) and [production setup](docs/deployment/production.md) before adopting. ## Screenshots | Public website | Filament administration | | --- | --- | -| ![Public homepage](https://raw.githubusercontent.com/ProgrammerNomad/LaraCoreKit/aeef46c567f7c54734b20581acee4cd0394cf3e7/docs/images/screenshots/homepage.png) | ![Admin dashboard](https://raw.githubusercontent.com/ProgrammerNomad/LaraCoreKit/aeef46c567f7c54734b20581acee4cd0394cf3e7/docs/images/screenshots/admin-dashboard.png) | -| ![Public blog](https://raw.githubusercontent.com/ProgrammerNomad/LaraCoreKit/aeef46c567f7c54734b20581acee4cd0394cf3e7/docs/images/screenshots/blog.png) | ![Documentation](https://raw.githubusercontent.com/ProgrammerNomad/LaraCoreKit/aeef46c567f7c54734b20581acee4cd0394cf3e7/docs/images/screenshots/documentation.png) | -| ![Component showcase](https://raw.githubusercontent.com/ProgrammerNomad/LaraCoreKit/aeef46c567f7c54734b20581acee4cd0394cf3e7/docs/images/screenshots/ui-showcase.png) | ![Mobile navigation](https://raw.githubusercontent.com/ProgrammerNomad/LaraCoreKit/aeef46c567f7c54734b20581acee4cd0394cf3e7/docs/images/screenshots/mobile-navigation.png) | +| ![Public homepage](docs/images/screenshots/homepage.png) | ![Admin dashboard](docs/images/screenshots/admin-dashboard.png) | +| ![Public blog](docs/images/screenshots/blog.png) | ![Documentation](docs/images/screenshots/documentation.png) | +| ![Component showcase](docs/images/screenshots/ui-showcase.png) | ![Mobile navigation](docs/images/screenshots/mobile-navigation.png) | -Screenshots show the local demonstration application, including host-only features. Open any image for the full view. See [capture instructions](https://github.com/ProgrammerNomad/LaraCoreKit/blob/aeef46c567f7c54734b20581acee4cd0394cf3e7/docs/SCREENSHOT_GUIDE.md) to reproduce the screenshots and GIF. +Screenshots show the local demonstration application, including host-only features. Open any image for the full view. See [capture instructions](docs/SCREENSHOT_GUIDE.md) to reproduce the screenshots and GIF. ## Development and validation @@ -103,12 +105,12 @@ npm run build:core npm run build ``` -See [contribution guidelines](https://github.com/ProgrammerNomad/LaraCoreKit/blob/aeef46c567f7c54734b20581acee4cd0394cf3e7/CONTRIBUTING.md), [upgrade guide](https://github.com/ProgrammerNomad/LaraCoreKit/blob/aeef46c567f7c54734b20581acee4cd0394cf3e7/docs/upgrade-guide.md), and [package release checklist](https://github.com/ProgrammerNomad/LaraCoreKit/blob/aeef46c567f7c54734b20581acee4cd0394cf3e7/docs/package-release.md). Keep changes to package code in `packages/core`; site-specific changes belong in the host. Published assets must be rebuilt when their source changes. +See [contribution guidelines](CONTRIBUTING.md), [upgrade guide](docs/upgrade-guide.md), and [package release checklist](docs/package-release.md). Keep changes to package code in `packages/core`; site-specific changes belong in the host. Published assets must be rebuilt when their source changes. ## Adoption and privacy -No registration, activation or telemetry is required. Packagist downloads measure distribution activity, not unique developers or active projects. The host includes a validated daily snapshot command and optional scheduler configuration; see [release and metrics setup](https://github.com/ProgrammerNomad/LaraCoreKit/blob/aeef46c567f7c54734b20581acee4cd0394cf3e7/docs/package-release.md). Contributions, issues and voluntary showcase submissions are welcome. Search engines and AI tools can read server-rendered docs and `/llms.txt`; no ranking or recommendation is promised. +No registration, activation or telemetry is required. Packagist downloads measure distribution activity, not unique developers or active projects. The host includes a validated daily snapshot command and optional scheduler configuration; see [release and metrics setup](docs/package-release.md). Contributions, issues and voluntary showcase submissions are welcome. Search engines and AI tools can read server-rendered docs and `/llms.txt`; no ranking or recommendation is promised. ## License -[MIT](https://github.com/ProgrammerNomad/LaraCoreKit/blob/aeef46c567f7c54734b20581acee4cd0394cf3e7/LICENSE). Report sensitive vulnerabilities through the [security policy](https://github.com/ProgrammerNomad/LaraCoreKit/blob/aeef46c567f7c54734b20581acee4cd0394cf3e7/SECURITY.md). +[MIT](LICENSE). Report sensitive vulnerabilities through the [security policy](SECURITY.md). diff --git a/ROADMAP.md b/ROADMAP.md index a8e1ec0..3e89a64 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,175 +1,26 @@ -# LaraCoreKit Roadmap +# Roadmap -This document outlines the development roadmap for LaraCoreKit. Items are organized by release version and priority. +## First standalone package release -## Version 0.1.0 (Next Release) - Q2 2026 +- [x] Extract reusable public and admin modules into `programmernomad/laracorekit`. +- [x] Keep demo website, Docs, UIShowcase and sample accounts outside the package. +- [x] Add configuration/asset installation and interactive administrator creation. +- [x] Update website, installation docs and module guides around both installation paths. +- [x] Add independent consumer smoke tests, security regressions and dependency update proposals. +- [x] Refresh public/admin screenshots using disposable fixtures. +- [ ] Create/configure the dedicated package repository and export reviewed package source. +- [ ] Publish a reviewed semantic version tag and register it on Packagist. +- [ ] Verify a registry-based installation and enable repository branch protections/security settings. +- [x] Implement validated daily Packagist snapshot collection without install telemetry. +- [ ] Enable the statistics collector on persistent production storage after publication. -Focus: Trust, Documentation, and Distribution +## Next priorities -### High Priority -- [ ] Add production screenshots to README and homepage -- [ ] Create demo walkthrough GIFs -- [ ] Publish comprehensive module development guide -- [ ] Add per-page documentation metadata -- [ ] Publish to Packagist -- [ ] Submit for Laravel installer support -- [ ] Create first official GitHub release with release notes -- [ ] Add code coverage reporting +- Broader database coverage and additional upload/authorization regression tests. +- Document and test migration paths for custom existing user models. +- More complete translations of website marketing copy and accessibility testing of individual showcase examples. +- Release automation from the monorepo into the dedicated package repository. -### Medium Priority -- [ ] Create comparison documentation (vs Larament, vs official starter) -- [ ] Add FAQ page -- [ ] Implement structured data for SEO -- [ ] Add "view source" links in UI showcase -- [ ] Create video tutorials for installation and basic usage -- [ ] Enhance demo site with auto-reset banner +## Optional future work -### Low Priority -- [ ] Add more UI component examples -- [ ] Create example applications repository -- [ ] Write implementation blog posts - -## Version 0.2.0 - Q3 2026 - -Focus: Enhanced Features and Developer Experience - -### Core Improvements -- [ ] Enhanced test coverage (target: 80%+) -- [ ] Performance optimization and benchmarking -- [ ] Improved error handling and logging -- [ ] Database query optimization -- [ ] Cache strategy implementation - -### Module Enhancements -- [ ] Blog: Add categories and tags -- [ ] Blog: Add featured posts and pinning -- [ ] Blog: Implement reading time estimation -- [ ] Media: Add image editing capabilities -- [ ] Media: Bulk upload and management -- [ ] Settings: Add theme customization options -- [ ] User: Add user activity tracking - -### Developer Tools -- [ ] Laravel Telescope integration guide -- [ ] Debugging best practices documentation -- [ ] Module scaffolding CLI command -- [ ] Automated module installer command - -## Version 0.3.0 - Q4 2026 - -Focus: Search, Analytics, and Social Features - -### New Features -- [ ] Search module (Meilisearch/Scout integration) -- [ ] Analytics dashboard module -- [ ] Notification center module -- [ ] Social authentication (Google, GitHub, Facebook) -- [ ] Activity/Audit log module -- [ ] Email template management - -### Platform Improvements -- [ ] API versioning strategy -- [ ] Rate limiting configuration -- [ ] Webhook system -- [ ] Event sourcing support -- [ ] Queue optimization - -## Version 1.0.0 - Q1 2027 - -Focus: Production Stability and Module Ecosystem - -### Production Readiness -- [ ] Security audit and penetration testing -- [ ] Performance benchmarking -- [ ] Load testing and optimization -- [ ] Comprehensive upgrade guides -- [ ] Production deployment guide -- [ ] Backup and disaster recovery documentation - -### Module Marketplace -- [ ] Module registry/marketplace UI -- [ ] Module versioning and compatibility system -- [ ] Module discovery and installation flow -- [ ] Module review and rating system -- [ ] Module documentation standards - -### Optional Addon Modules -- [ ] E-commerce module -- [ ] Payment gateway integrations (Stripe, Razorpay, PayPal) -- [ ] Teams/multi-tenancy module -- [ ] Subscription/billing module -- [ ] Advanced permissions module - -## Version 2.0.0 - Future - -Focus: Advanced Features and Scalability - -### Advanced Features -- [ ] GraphQL API support -- [ ] Real-time features with WebSockets -- [ ] Advanced caching strategies -- [ ] Multi-database support -- [ ] Horizontal scaling guide -- [ ] Microservices architecture option - -### Enterprise Features -- [ ] Advanced audit logging -- [ ] Compliance tools (GDPR, CCPA) -- [ ] Advanced backup solutions -- [ ] High availability setup -- [ ] Enterprise support options - -## Ongoing Priorities - -These items are continuously maintained across all versions: - -### Documentation -- Keep all documentation up-to-date -- Add more examples and use cases -- Create video tutorials -- Translate documentation to more languages -- Improve search and discoverability - -### Quality Assurance -- Maintain high test coverage -- Regular security updates -- Performance monitoring -- Code quality improvements -- Dependency updates - -### Community -- Respond to issues and discussions -- Review and merge pull requests -- Engage with community feedback -- Highlight community contributions -- Foster module ecosystem - -### SEO & Marketing -- Regular blog posts and tutorials -- Social media presence -- Community showcases -- Conference presentations -- Open-source advocacy - -## How to Contribute - -Want to help with any of these roadmap items? - -1. Check the [Issues](https://github.com/ProgrammerNomad/LaraCoreKit/issues) page for tasks -2. Comment on an issue to express interest -3. Read the [Contributing Guide](../CONTRIBUTING.md) -4. Submit a pull request - -## Feature Requests - -Have an idea not on this roadmap? - -1. Check [Discussions](https://github.com/ProgrammerNomad/LaraCoreKit/discussions) -2. Open a [Feature Request](https://github.com/ProgrammerNomad/LaraCoreKit/issues/new?template=feature_request.md) -3. Participate in community voting - ---- - -**Last Updated:** April 22, 2026 - -**Note:** This roadmap is subject to change based on community feedback, priorities, and resources. Dates are approximate targets, not commitments. +Email-verification enforcement, API authentication, billing, tenancy and external search integrations require separate implementation and compatibility testing. These are not claims about current bundled features. No release dates are promised until scope and maintainers are assigned. diff --git a/SECURITY.md b/SECURITY.md index a7e5816..2b86909 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,105 +1,19 @@ -# Security Policy +# Security policy -## Supported Versions +The standalone `programmernomad/laracorekit` package is published on Packagist; report issues against the reviewed tag you deploy. Older demo tags do not imply that their dependency lockfiles remain secure; audit and upgrade before deploying. -We release patches for security vulnerabilities in the following versions: +## Reporting a vulnerability -| Version | Supported | -| ------- | ------------------ | -| 0.0.2 | :white_check_mark: | -| 0.0.1 | :x: | +Report sensitive issues through [GitHub private vulnerability reporting](https://github.com/ProgrammerNomad/LaraCoreKit/security/advisories/new). Include affected commit/version, impact and a minimal reproduction. Do not post secrets or exploitable details in public issues. Repository administrators must enable private reporting if the form is unavailable. -## Reporting a Vulnerability +Maintainers will assess reports and coordinate fixes and disclosure. Response and fix times depend on severity and maintainer availability; this project does not provide a guaranteed security-response SLA. -We take security seriously at LaraCoreKit. If you discover a security vulnerability, please follow these steps: +## Deployment expectations -### Where to Report +- Use reviewed lockfiles and run Composer/npm audits regularly. +- Set `APP_DEBUG=false`, use HTTPS and keep environment files and logs private. +- Keep demo mode disabled in customer applications. Never deploy sample credentials or the demo reset scheduler against real data. +- Create administrators with unique passwords. Review permissions on public Livewire actions and direct admin record routes. +- Test upload restrictions, mail recovery and data backups for your deployment. -**DO NOT** create a public GitHub issue for security vulnerabilities. - -Instead, please use one of these methods: - -**Option 1: GitHub Security Advisories (Recommended)** -- Go to https://github.com/ProgrammerNomad/LaraCoreKit/security/advisories/new -- This creates a private security advisory - -**Option 2: Private Email** -- **Email:** Contact the repository owner directly through GitHub -- **Subject:** [SECURITY] Brief description of the issue - -### What to Include - -Please provide the following information: - -1. **Description** - Clear description of the vulnerability -2. **Steps to Reproduce** - Detailed steps to reproduce the issue -3. **Impact** - Potential impact and severity assessment -4. **Affected Versions** - Which versions of LaraCoreKit are affected -5. **Suggested Fix** - If you have a fix or mitigation suggestion -6. **Disclosure Timeline** - Your preferred disclosure timeline - -### Response Timeline - -- **Initial Response:** Within 48 hours -- **Status Update:** Within 7 days -- **Fix Timeline:** Depends on severity - - Critical: 1-7 days - - High: 7-14 days - - Medium: 14-30 days - - Low: 30-60 days - -### Disclosure Policy - -We follow responsible disclosure practices: - -1. We will acknowledge your email within 48 hours -2. We will provide a detailed response within 7 days -3. We will work with you to understand and validate the issue -4. We will develop and test a fix -5. We will release a security patch -6. We will credit you in the release notes (unless you prefer to remain anonymous) - -### Security Updates - -Security updates will be: -- Released as patch versions -- Documented in CHANGELOG.md -- Announced on GitHub Releases -- Tagged with `security` label - -### Security Best Practices - -When using LaraCoreKit: - -1. **Keep Updated** - Always use the latest supported version -2. **Environment Files** - Never commit `.env` files to version control -3. **Credentials** - Use strong passwords and rotate API keys regularly -4. **Database** - Run migrations and seeders only in trusted environments -5. **File Permissions** - Ensure proper file and directory permissions -6. **Dependencies** - Keep all Composer and NPM dependencies updated -7. **HTTPS** - Always use HTTPS in production -8. **Demo Mode** - Never use demo credentials in production - -### Scope - -This security policy applies to: -- LaraCoreKit core framework -- Official modules (Auth, Blog, Core, Media, Settings, User) -- Official documentation -- Official demo site - -This policy does NOT apply to: -- Third-party modules -- Custom implementations -- Modified versions -- Development/staging environments - -## Hall of Fame - -We thank the following researchers for responsibly disclosing security issues: - -(No reports yet) - ---- - -**Last Updated:** April 22, 2026 +The package requires no activation, telemetry or user registration. The current automated tests are not an independent security audit. Read [production setup](docs/deployment/production.md) before deploying. diff --git a/app/Console/Commands/CollectPackageStats.php b/app/Console/Commands/CollectPackageStats.php new file mode 100644 index 0000000..8d7804b --- /dev/null +++ b/app/Console/Commands/CollectPackageStats.php @@ -0,0 +1,60 @@ +toDateString(); + $path = 'metrics/packagist/'.$day.'.json'; + $disk = Storage::disk('local'); + if ($disk->exists($path)) { + $this->info('A download snapshot already exists for '.$day.'.'); + + return self::SUCCESS; + } + + try { + $response = Http::timeout(15)->withUserAgent('LaraCoreKit statistics (+https://www.laracorekit.com)') + ->get('https://packagist.org/packages/programmernomad/laracorekit/stats.json'); + if ($response->status() === 404) { + $this->line('Package is not registered yet; no snapshot was recorded.'); + + return self::SUCCESS; + } + $response->throw(); + $downloads = $response->json('downloads'); + foreach (['total', 'monthly', 'daily'] as $field) { + if (! is_array($downloads) || ! isset($downloads[$field]) || ! is_int($downloads[$field]) || $downloads[$field] < 0) { + throw new \RuntimeException('Invalid Packagist statistics response.'); + } + } + $saved = $disk->put($path, json_encode([ + 'package' => 'programmernomad/laracorekit', + 'collected_at' => now('UTC')->toIso8601String(), + 'downloads' => $downloads, + 'metric' => 'downloads, not unique developers or installations', + ], JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR)); + if (! $saved) { + throw new \RuntimeException('Could not persist download statistics.'); + } + } catch (\Throwable $error) { + $this->error('Statistics collection failed; no zero-valued replacement was recorded. '.$error->getMessage()); + + return self::FAILURE; + } + + $this->info('Download snapshot saved for '.$day.'.'); + + return self::SUCCESS; + } +} diff --git a/app/Console/Commands/GenerateSitemap.php b/app/Console/Commands/GenerateSitemap.php index c965140..6ee45b1 100644 --- a/app/Console/Commands/GenerateSitemap.php +++ b/app/Console/Commands/GenerateSitemap.php @@ -2,130 +2,24 @@ namespace App\Console\Commands; +use App\Http\Controllers\SitemapController; use Illuminate\Console\Command; -use Spatie\Sitemap\SitemapGenerator; -use Spatie\Sitemap\Tags\Url; +use Illuminate\Support\Facades\File; class GenerateSitemap extends Command { - /** - * The name and signature of the console command. - * - * @var string - */ protected $signature = 'sitemap:generate'; - /** - * The console command description. - * - * @var string - */ - protected $description = 'Generate the XML sitemap for search engines.'; + protected $description = 'Export the dynamic website sitemap to private storage for inspection'; - /** - * Execute the console command. - */ - public function handle() + public function handle(): int { - // Use the configured app url or the local dev server - $appUrl = config('app.url') === 'http://localhost' ? 'http://127.0.0.1:8000' : config('app.url'); + $path = storage_path('app/exports/sitemap.xml'); + File::ensureDirectoryExists(dirname($path)); + File::put($path, app(SitemapController::class)->index()->getContent()); + $this->info('Sitemap exported to '.$path); + $this->line('Search engines should use the live /sitemap.xml route.'); - $this->info("Crawling {$appUrl} to generate sitemap..."); - - $sitemap = SitemapGenerator::create($appUrl) - ->hasCrawled(function (Url $url) { - // Ignore admin panel and livewire internal routes - if ($url->segment(1) === 'admin' || $url->segment(1) === 'livewire') { - return null; - } - - // Set priority and change frequency based on URL patterns - $path = $url->path(); - - // Homepage - highest priority - if ($path === '/') { - $url->setPriority(1.0) - ->setChangeFrequency(Url::CHANGE_FREQUENCY_DAILY) - ->setLastModificationDate(now()); - } - // Blog posts - high priority, updated frequently - elseif (str_starts_with($path, '/blog/')) { - $url->setPriority(0.8) - ->setChangeFrequency(Url::CHANGE_FREQUENCY_WEEKLY) - ->setLastModificationDate(now()); - } - // Main sections (blog, docs, ui-showcase) - elseif (in_array($path, ['/blog', '/docs', '/ui-showcase'])) { - $url->setPriority(0.9) - ->setChangeFrequency(Url::CHANGE_FREQUENCY_DAILY) - ->setLastModificationDate(now()); - } - // Documentation pages - elseif (str_starts_with($path, '/docs/')) { - $url->setPriority(0.7) - ->setChangeFrequency(Url::CHANGE_FREQUENCY_WEEKLY) - ->setLastModificationDate(now()); - } - // UI Showcase component pages - elseif (str_starts_with($path, '/ui-showcase/') && substr_count($path, '/') >= 2) { - $url->setPriority(0.7) - ->setChangeFrequency(Url::CHANGE_FREQUENCY_WEEKLY) - ->setLastModificationDate(now()); - } - // UI Showcase category pages - elseif (str_starts_with($path, '/ui-showcase/')) { - $url->setPriority(0.6) - ->setChangeFrequency(Url::CHANGE_FREQUENCY_MONTHLY) - ->setLastModificationDate(now()); - } - // Auth pages (login, register) - lower priority - elseif (in_array($path, ['/login', '/register', '/forgot-password'])) { - $url->setPriority(0.3) - ->setChangeFrequency(Url::CHANGE_FREQUENCY_MONTHLY) - ->setLastModificationDate(now()); - } - // Everything else - medium priority - else { - $url->setPriority(0.5) - ->setChangeFrequency(Url::CHANGE_FREQUENCY_MONTHLY) - ->setLastModificationDate(now()); - } - - return $url; - }) - ->getSitemap(); - - // Add component URLs from config that might not be crawled - $categories = config('showcase.components.categories', []); - foreach ($categories as $categorySlug => $category) { - if (isset($category['components'])) { - foreach ($category['components'] as $componentSlug => $component) { - $componentUrl = "{$appUrl}/ui-showcase/{$categorySlug}/{$componentSlug}"; - - // Check if URL already exists in sitemap - $exists = false; - foreach ($sitemap->getTags() as $tag) { - if ($tag->url === $componentUrl) { - $exists = true; - break; - } - } - - // Add if it doesn't exist - if (!$exists) { - $sitemap->add( - Url::create($componentUrl) - ->setPriority(0.7) - ->setChangeFrequency(Url::CHANGE_FREQUENCY_WEEKLY) - ->setLastModificationDate(now()) - ); - } - } - } - } - - $sitemap->writeToFile(public_path('sitemap.xml')); - - $this->info('Sitemap generated successfully in public/sitemap.xml!'); + return self::SUCCESS; } } diff --git a/app/Filament/Pages/Dashboard.php b/app/Filament/Pages/Dashboard.php index 444f12d..1892b4b 100644 --- a/app/Filament/Pages/Dashboard.php +++ b/app/Filament/Pages/Dashboard.php @@ -4,5 +4,4 @@ use Filament\Pages\Dashboard as BaseDashboard; -class Dashboard extends BaseDashboard -{} +class Dashboard extends BaseDashboard {} diff --git a/app/Http/Controllers/SitemapController.php b/app/Http/Controllers/SitemapController.php index 40e2fbb..d00029c 100644 --- a/app/Http/Controllers/SitemapController.php +++ b/app/Http/Controllers/SitemapController.php @@ -3,6 +3,8 @@ namespace App\Http\Controllers; use Illuminate\Http\Response; +use Modules\Blog\Models\Blog; +use Modules\Docs\Http\Controllers\DocsController; class SitemapController extends Controller { @@ -11,8 +13,8 @@ public function index(): Response $blogs = collect(); try { - $blogs = \Modules\Blog\Models\Blog::query() - ->where('status', 'published') + $blogs = Blog::query() + ->published() ->whereNotNull('published_at') ->orderByDesc('published_at') ->get(['slug', 'updated_at', 'published_at']); @@ -20,8 +22,10 @@ public function index(): Response // Table may not exist yet during install } + $docs = app(DocsController::class)->publishedPages(); + return response() - ->view('sitemap', compact('blogs')) + ->view('sitemap', compact('blogs', 'docs')) ->header('Content-Type', 'application/xml; charset=utf-8'); } } diff --git a/app/Http/Middleware/RedirectIfAuthenticated.php b/app/Http/Middleware/RedirectIfAuthenticated.php index 6ecdd92..bfbf7cf 100644 --- a/app/Http/Middleware/RedirectIfAuthenticated.php +++ b/app/Http/Middleware/RedirectIfAuthenticated.php @@ -12,7 +12,7 @@ class RedirectIfAuthenticated /** * Handle an incoming request. * - * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next + * @param Closure(Request): (Response) $next */ public function handle(Request $request, Closure $next, string ...$guards): Response { @@ -21,12 +21,12 @@ public function handle(Request $request, Closure $next, string ...$guards): Resp foreach ($guards as $guard) { if (Auth::guard($guard)->check()) { $user = Auth::guard($guard)->user(); - + // Redirect based on user role if ($user->hasRole(['Admin', 'Editor'])) { return redirect('/admin'); } - + // Regular users go to dashboard return redirect('/dashboard'); } diff --git a/modules/Core/src/Http/Livewire/Changelog.php b/app/Livewire/Changelog.php similarity index 84% rename from modules/Core/src/Http/Livewire/Changelog.php rename to app/Livewire/Changelog.php index 6b414ab..525d3b8 100644 --- a/modules/Core/src/Http/Livewire/Changelog.php +++ b/app/Livewire/Changelog.php @@ -1,10 +1,10 @@ changelog = File::get($changelogPath); } else { @@ -24,6 +24,6 @@ public function mount() public function render() { - return view('core::livewire.changelog'); + return view('site.changelog'); } } diff --git a/modules/Core/src/Http/Livewire/Home.php b/app/Livewire/Home.php similarity index 64% rename from modules/Core/src/Http/Livewire/Home.php rename to app/Livewire/Home.php index 64066ce..60bf33b 100644 --- a/modules/Core/src/Http/Livewire/Home.php +++ b/app/Livewire/Home.php @@ -1,9 +1,10 @@ latest('published_at') ->take(3) ->get(); @@ -19,8 +20,8 @@ public function render() $latestPosts = collect(); } - return view('core::livewire.home', [ - 'latestPosts' => $latestPosts + return view('site.home', [ + 'latestPosts' => $latestPosts, ]); } } diff --git a/app/Providers/Filament/AdminPanelProvider.php b/app/Providers/Filament/AdminPanelProvider.php index 4cc4b86..b4fe9ea 100644 --- a/app/Providers/Filament/AdminPanelProvider.php +++ b/app/Providers/Filament/AdminPanelProvider.php @@ -2,19 +2,27 @@ namespace App\Providers\Filament; +use App\Filament\Pages\Dashboard; use Filament\Http\Middleware\Authenticate; use Filament\Http\Middleware\AuthenticateSession; use Filament\Panel; use Filament\PanelProvider; use Filament\Support\Colors\Color; use Filament\Widgets\AccountWidget; -use Filament\Widgets\FilamentInfoWidget; use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse; use Illuminate\Cookie\Middleware\EncryptCookies; use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken; use Illuminate\Routing\Middleware\SubstituteBindings; use Illuminate\Session\Middleware\StartSession; use Illuminate\View\Middleware\ShareErrorsFromSession; +use LaraCoreKit\Core\Filament\LocalAvatarProvider; +use LaraCoreKit\Core\Filament\OverviewStats; +use LaraCoreKit\DemoModule\Filament\Widgets\DemoBannerWidget; +use Modules\Blog\Filament\Resources\BlogResource; +use Modules\Settings\Filament\Pages\Settings; +use Modules\User\Filament\Resources\Permissions\PermissionResource; +use Modules\User\Filament\Resources\Roles\RoleResource; +use Modules\User\Filament\Resources\UserResource; class AdminPanelProvider extends PanelProvider { @@ -28,29 +36,30 @@ public function panel(Panel $panel): Panel ->login() ->authGuard('web') ->brandName('LaraCoreKit') + ->defaultAvatarProvider(LocalAvatarProvider::class) ->brandLogo(asset('images/logo.svg')) + ->darkModeBrandLogo(asset('images/logo-dark.svg')) ->darkMode(true) - ->renderHook('panels::body.end', fn() => view('filament.login-placeholders')) ->colors([ 'primary' => Color::Red, 'danger' => Color::Red, ]) - ->font('Inter') ->resources([ - \Modules\Blog\Filament\Resources\BlogResource::class, - \Modules\User\Filament\Resources\UserResource::class, - \Modules\User\Filament\Resources\Roles\RoleResource::class, - \Modules\User\Filament\Resources\Permissions\PermissionResource::class, + BlogResource::class, + UserResource::class, + RoleResource::class, + PermissionResource::class, ]) ->pages([ - \App\Filament\Pages\Dashboard::class, - \Modules\Settings\Filament\Pages\Settings::class, + Dashboard::class, + Settings::class, ]) ->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\Filament\Widgets') ->widgets([ AccountWidget::class, - FilamentInfoWidget::class, - \LaraCoreKit\DemoModule\Filament\Widgets\DemoBannerWidget::class, + OverviewStats::class, + ...(config('demo.enabled') && class_exists(DemoBannerWidget::class) + ? [DemoBannerWidget::class] : []), ]) ->middleware([ EncryptCookies::class, diff --git a/app/Providers/ModuleServiceProvider.php b/app/Providers/ModuleServiceProvider.php deleted file mode 100644 index b892867..0000000 --- a/app/Providers/ModuleServiceProvider.php +++ /dev/null @@ -1,27 +0,0 @@ - $moduleConfig) { - if ($moduleConfig['enabled'] ?? false) { - $providerClass = $moduleConfig['provider'] ?? null; - if ($providerClass && class_exists($providerClass)) { - $this->app->register($providerClass); - } - } - } - } - - public function boot(): void - { - // - } -} diff --git a/bootstrap/app.php b/bootstrap/app.php index dc9585d..610542c 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -1,5 +1,6 @@ withMiddleware(function (Middleware $middleware) { - $middleware->web(append: [ - \Modules\Core\Http\Middleware\SetLocale::class, - ]); - + $middleware->alias([ - 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, + 'guest' => RedirectIfAuthenticated::class, ]); }) ->withExceptions(function (Exceptions $exceptions) { diff --git a/bootstrap/providers.php b/bootstrap/providers.php index fa67da1..365d3a3 100644 --- a/bootstrap/providers.php +++ b/bootstrap/providers.php @@ -1,13 +1,11 @@ =5.3.0" + "php": ">=7.4" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9" + "phpunit/phpunit": "^6 || ^7 || ^8 || ^9 || ^10" }, "type": "library", "extra": { @@ -3602,22 +3833,22 @@ ], "support": { "issues": "https://github.com/Masterminds/html5-php/issues", - "source": "https://github.com/Masterminds/html5-php/tree/2.10.0" + "source": "https://github.com/Masterminds/html5-php/tree/2.11.0" }, - "time": "2025-07-25T09:04:22+00:00" + "time": "2026-08-18T06:18:41+00:00" }, { "name": "monolog/monolog", - "version": "3.10.0", + "version": "3.12.1", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "b321dd6749f0bf7189444158a3ce785cc16d69b0" + "reference": "d7059e4c691d05ea1222b5124bed0f961be46e15" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/b321dd6749f0bf7189444158a3ce785cc16d69b0", - "reference": "b321dd6749f0bf7189444158a3ce785cc16d69b0", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/d7059e4c691d05ea1222b5124bed0f961be46e15", + "reference": "d7059e4c691d05ea1222b5124bed0f961be46e15", "shasum": "" }, "require": { @@ -3643,6 +3874,7 @@ "phpstan/phpstan-strict-rules": "^2", "phpunit/phpunit": "^10.5.17 || ^11.0.7", "predis/predis": "^1.1 || ^2", + "psr/clock": "^1.0", "rollbar/rollbar": "^4.0", "ruflin/elastica": "^7 || ^8", "symfony/mailer": "^5.4 || ^6", @@ -3661,6 +3893,7 @@ "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "psr/clock": "Required to pass a clock to the Logger and control the timestamp of log records", "rollbar/rollbar": "Allow sending log messages to Rollbar", "ruflin/elastica": "Allow sending log messages to an Elastic Search server" }, @@ -3695,7 +3928,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/3.10.0" + "source": "https://github.com/Seldaek/monolog/tree/3.12.1" }, "funding": [ { @@ -3707,20 +3940,20 @@ "type": "tidelift" } ], - "time": "2026-01-02T08:56:05+00:00" + "time": "2026-09-29T19:21:12+00:00" }, { "name": "nesbot/carbon", - "version": "3.11.4", + "version": "3.15.0", "source": { "type": "git", "url": "https://github.com/CarbonPHP/carbon.git", - "reference": "e890471a3494740f7d9326d72ce6a8c559ffee60" + "reference": "217d38553209bdb44e01590d9e9a2e4df8354cce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/e890471a3494740f7d9326d72ce6a8c559ffee60", - "reference": "e890471a3494740f7d9326d72ce6a8c559ffee60", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/217d38553209bdb44e01590d9e9a2e4df8354cce", + "reference": "217d38553209bdb44e01590d9e9a2e4df8354cce", "shasum": "" }, "require": { @@ -3730,6 +3963,7 @@ "psr/clock": "^1.0", "symfony/clock": "^6.3.12 || ^7.0 || ^8.0", "symfony/polyfill-mbstring": "^1.0", + "symfony/polyfill-time": "^1.0", "symfony/translation": "^4.4.18 || ^5.2.1 || ^6.0 || ^7.0 || ^8.0" }, "provide": { @@ -3740,7 +3974,7 @@ "doctrine/orm": "^2.15.2 || ^3.0", "friendsofphp/php-cs-fixer": "^v3.87.1", "kylekatarnls/multi-tester": "^2.5.3", - "phpmd/phpmd": "^2.15.0", + "phpmd/phpmd": "^3.0@dev", "phpstan/extension-installer": "^1.4.3", "phpstan/phpstan": "^2.1.22", "phpunit/phpunit": "^10.5.53", @@ -3812,7 +4046,7 @@ "type": "tidelift" } ], - "time": "2026-04-07T09:57:54+00:00" + "time": "2026-10-18T18:27:53+00:00" }, { "name": "nette/php-generator", @@ -3890,16 +4124,16 @@ }, { "name": "nette/schema", - "version": "v1.3.5", + "version": "v1.3.6", "source": { "type": "git", "url": "https://github.com/nette/schema.git", - "reference": "f0ab1a3cda782dbc5da270d28545236aa80c4002" + "reference": "c54350438cd6914616f790a49cb424605f421562" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/schema/zipball/f0ab1a3cda782dbc5da270d28545236aa80c4002", - "reference": "f0ab1a3cda782dbc5da270d28545236aa80c4002", + "url": "https://api.github.com/repos/nette/schema/zipball/c54350438cd6914616f790a49cb424605f421562", + "reference": "c54350438cd6914616f790a49cb424605f421562", "shasum": "" }, "require": { @@ -3951,22 +4185,22 @@ ], "support": { "issues": "https://github.com/nette/schema/issues", - "source": "https://github.com/nette/schema/tree/v1.3.5" + "source": "https://github.com/nette/schema/tree/v1.3.6" }, - "time": "2026-02-23T03:47:12+00:00" + "time": "2026-08-16T21:58:41+00:00" }, { "name": "nette/utils", - "version": "v4.1.3", + "version": "v4.1.5", "source": { "type": "git", "url": "https://github.com/nette/utils.git", - "reference": "bb3ea637e3d131d72acc033cfc2746ee893349fe" + "reference": "b043439dbdf954e6c28b5ea7e34b0100f83165e0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/bb3ea637e3d131d72acc033cfc2746ee893349fe", - "reference": "bb3ea637e3d131d72acc033cfc2746ee893349fe", + "url": "https://api.github.com/repos/nette/utils/zipball/b043439dbdf954e6c28b5ea7e34b0100f83165e0", + "reference": "b043439dbdf954e6c28b5ea7e34b0100f83165e0", "shasum": "" }, "require": { @@ -3986,7 +4220,7 @@ }, "suggest": { "ext-gd": "to use Image", - "ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()", + "ext-iconv": "to use Strings::chr(), ord() and reverse()", "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", "ext-json": "to use Nette\\Utils\\Json", "ext-mbstring": "to use Strings::lower() etc...", @@ -4042,80 +4276,25 @@ ], "support": { "issues": "https://github.com/nette/utils/issues", - "source": "https://github.com/nette/utils/tree/v4.1.3" - }, - "time": "2026-02-13T03:05:33+00:00" - }, - { - "name": "nicmart/tree", - "version": "0.10.1", - "source": { - "type": "git", - "url": "https://github.com/nicmart/Tree.git", - "reference": "2ef11e329d26005ef49dbacd0223bcfd2515b6cc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nicmart/Tree/zipball/2ef11e329d26005ef49dbacd0223bcfd2515b6cc", - "reference": "2ef11e329d26005ef49dbacd0223bcfd2515b6cc", - "shasum": "" - }, - "require": { - "php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" - }, - "require-dev": { - "ergebnis/composer-normalize": "^2.48.2", - "ergebnis/license": "^2.7.0", - "ergebnis/php-cs-fixer-config": "^6.28.1", - "fakerphp/faker": "^1.24.1", - "infection/infection": "~0.26.19", - "phpunit/phpunit": "^9.6.19", - "psalm/plugin-phpunit": "~0.19.0", - "vimeo/psalm": "^5.26.1" - }, - "type": "library", - "autoload": { - "psr-4": { - "Tree\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolò Martini", - "email": "nicmartnic@gmail.com" - }, - { - "name": "Andreas Möller", - "email": "am@localheinz.com" - } - ], - "description": "A basic but flexible php tree data structure and a fluent tree builder implementation.", - "support": { - "issues": "https://github.com/nicmart/Tree/issues", - "source": "https://github.com/nicmart/Tree/tree/0.10.1" + "source": "https://github.com/nette/utils/tree/v4.1.5" }, - "time": "2025-11-25T08:51:01+00:00" + "time": "2026-07-17T23:02:45+00:00" }, { "name": "nikic/php-parser", - "version": "v5.7.0", + "version": "v5.9.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82" + "reference": "9e33da9553fe7786f0962b35f4e4ecf01be89def" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82", - "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/9e33da9553fe7786f0962b35f4e4ecf01be89def", + "reference": "9e33da9553fe7786f0962b35f4e4ecf01be89def", "shasum": "" }, "require": { - "ext-ctype": "*", "ext-json": "*", "ext-tokenizer": "*", "php": ">=7.4" @@ -4154,9 +4333,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.9.0" }, - "time": "2025-12-06T11:56:16+00:00" + "time": "2026-09-13T18:51:52+00:00" }, { "name": "nunomaduro/termwind", @@ -4409,16 +4588,16 @@ }, { "name": "phpoption/phpoption", - "version": "1.9.5", + "version": "1.10.0", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "75365b91986c2405cf5e1e012c5595cd487a98be" + "reference": "67b192b6a42ec03944b972d6e633ddec78ad2c6d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/75365b91986c2405cf5e1e012c5595cd487a98be", - "reference": "75365b91986c2405cf5e1e012c5595cd487a98be", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/67b192b6a42ec03944b972d6e633ddec78ad2c6d", + "reference": "67b192b6a42ec03944b972d6e633ddec78ad2c6d", "shasum": "" }, "require": { @@ -4426,7 +4605,7 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.44 || ^9.6.25 || ^10.5.53 || ^11.5.34" + "phpunit/phpunit": "^8.5.54 || ^9.6.36 || ^10.5.64 || ^11.5.56 || ^12.5.33" }, "type": "library", "extra": { @@ -4468,7 +4647,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/php-option/issues", - "source": "https://github.com/schmittjoh/php-option/tree/1.9.5" + "source": "https://github.com/schmittjoh/php-option/tree/1.10.0" }, "funding": [ { @@ -4480,20 +4659,20 @@ "type": "tidelift" } ], - "time": "2025-12-27T19:41:33+00:00" + "time": "2026-08-24T00:54:40+00:00" }, { "name": "pragmarx/google2fa", - "version": "v9.0.0", + "version": "v9.1.0", "source": { "type": "git", "url": "https://github.com/antonioribeiro/google2fa.git", - "reference": "e6bc62dd6ae83acc475f57912e27466019a1f2cf" + "reference": "f00bc788c555adfb6765c437ff3538e59cd88af1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/antonioribeiro/google2fa/zipball/e6bc62dd6ae83acc475f57912e27466019a1f2cf", - "reference": "e6bc62dd6ae83acc475f57912e27466019a1f2cf", + "url": "https://api.github.com/repos/antonioribeiro/google2fa/zipball/f00bc788c555adfb6765c437ff3538e59cd88af1", + "reference": "f00bc788c555adfb6765c437ff3538e59cd88af1", "shasum": "" }, "require": { @@ -4501,8 +4680,11 @@ "php": "^7.1|^8.0" }, "require-dev": { - "phpstan/phpstan": "^1.9", - "phpunit/phpunit": "^7.5.15|^8.5|^9.0" + "phpstan/phpstan": "^1.0|^2.0", + "phpstan/phpstan-phpunit": "^1.0|^2.0", + "phpunit/phpunit": "~9|~10|~11|~12|~13", + "psalm/plugin-phpunit": "^0.19|^0.20", + "vimeo/psalm": "^5.26|^6.13" }, "type": "library", "autoload": { @@ -4525,38 +4707,48 @@ "keywords": [ "2fa", "Authentication", + "MFA", "Two Factor Authentication", - "google2fa" + "google-authenticator", + "google2fa", + "hotp", + "otp", + "rfc4226", + "rfc6238", + "totp" ], "support": { + "docs": "https://github.com/antonioribeiro/google2fa#readme", "issues": "https://github.com/antonioribeiro/google2fa/issues", - "source": "https://github.com/antonioribeiro/google2fa/tree/v9.0.0" + "security": "https://github.com/antonioribeiro/google2fa/security/policy", + "source": "https://github.com/antonioribeiro/google2fa" }, - "time": "2025-09-19T22:51:08+00:00" + "time": "2026-08-15T13:22:01+00:00" }, { "name": "pragmarx/google2fa-qrcode", - "version": "v3.0.0", + "version": "v4.0.0", "source": { "type": "git", "url": "https://github.com/antonioribeiro/google2fa-qrcode.git", - "reference": "ce4d8a729b6c93741c607cfb2217acfffb5bf76b" + "reference": "16159f84fa0838c276f35d46de57fd90dfbb385c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/antonioribeiro/google2fa-qrcode/zipball/ce4d8a729b6c93741c607cfb2217acfffb5bf76b", - "reference": "ce4d8a729b6c93741c607cfb2217acfffb5bf76b", + "url": "https://api.github.com/repos/antonioribeiro/google2fa-qrcode/zipball/16159f84fa0838c276f35d46de57fd90dfbb385c", + "reference": "16159f84fa0838c276f35d46de57fd90dfbb385c", "shasum": "" }, "require": { - "php": ">=7.1", - "pragmarx/google2fa": ">=4.0" + "php": "^8.1", + "pragmarx/google2fa": "^8.0|^9.0" }, "require-dev": { - "bacon/bacon-qr-code": "^2.0", - "chillerlan/php-qrcode": "^1.0|^2.0|^3.0|^4.0", + "bacon/bacon-qr-code": "^2.0|^3.0", + "chillerlan/php-qrcode": "^5.0|^6.0", "khanamiryan/qrcode-detector-decoder": "^1.0", - "phpunit/phpunit": "~4|~5|~6|~7|~8|~9" + "phpstan/phpstan": "^2.0", + "phpunit/phpunit": "~9|~10|~11|~12|~13" }, "suggest": { "bacon/bacon-qr-code": "For QR Code generation, requires imagick", @@ -4597,51 +4789,54 @@ ], "support": { "issues": "https://github.com/antonioribeiro/google2fa-qrcode/issues", - "source": "https://github.com/antonioribeiro/google2fa-qrcode/tree/v3.0.0" + "source": "https://github.com/antonioribeiro/google2fa-qrcode/tree/v4.0.0" }, - "time": "2021-08-15T12:53:48+00:00" + "time": "2026-05-08T19:24:44+00:00" }, { - "name": "programmernomad/laracorekit-demo-module", - "version": "v1.0.5", - "source": { - "type": "git", - "url": "https://github.com/ProgrammerNomad/laracorekit-demo-module.git", - "reference": "7237b3b79d8b5927ba17feed39fc030a40e0a34f" - }, + "name": "programmernomad/laracorekit", + "version": "dev-main", "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ProgrammerNomad/laracorekit-demo-module/zipball/7237b3b79d8b5927ba17feed39fc030a40e0a34f", - "reference": "7237b3b79d8b5927ba17feed39fc030a40e0a34f", - "shasum": "" + "type": "path", + "url": "packages/core", + "reference": "5ebe60c79a9ba823b081caa1516ba2462f354b9f" }, "require": { - "illuminate/console": "^11.0|^12.0|^13.0", - "illuminate/database": "^11.0|^12.0|^13.0", - "illuminate/filesystem": "^11.0|^12.0|^13.0", - "illuminate/support": "^11.0|^12.0|^13.0", - "php": "^8.2|^8.3" - }, - "require-dev": { - "filament/filament": "^3.0|^4.0|^5.0", - "laravel/pint": "^1.0", - "orchestra/testbench": "^9.0|^10.0", - "phpunit/phpunit": "^11.0" + "filament/filament": "^5.10", + "laravel/framework": "^13.37", + "livewire/livewire": "^4.4", + "php": "^8.3", + "spatie/laravel-medialibrary": "^11.23", + "spatie/laravel-permission": "^6.23" }, "type": "library", "extra": { "laravel": { "providers": [ - "LaraCoreKit\\DemoModule\\DemoServiceProvider" + "LaraCoreKit\\Core\\CoreServiceProvider" ] } }, "autoload": { "psr-4": { - "LaraCoreKit\\DemoModule\\": "src/" + "LaraCoreKit\\Core\\": "src/", + "Modules\\Core\\": "modules/Core/src/", + "Modules\\Auth\\": "modules/Auth/src/", + "Modules\\User\\Database\\Seeders\\": "modules/User/database/seeders/", + "Modules\\User\\Database\\Factories\\": "modules/User/database/factories/", + "Modules\\User\\": "modules/User/src/", + "Modules\\Settings\\": "modules/Settings/src/", + "Modules\\Media\\": "modules/Media/src/", + "Modules\\Blog\\": "modules/Blog/src/" } }, - "notification-url": "https://packagist.org/downloads/", + "archive": { + "exclude": [ + "/tests", + "/phpunit.xml", + "/.github" + ] + }, "license": [ "MIT" ], @@ -4651,15 +4846,84 @@ "homepage": "https://github.com/ProgrammerNomad" } ], - "description": "Auto-resetting demo environment for Laravel applications with Filament integration", - "homepage": "https://github.com/ProgrammerNomad/laracorekit-demo-module", + "description": "Modular Laravel application foundation with Filament administration, authentication, roles, settings, blog and media.", + "homepage": "https://www.laracorekit.com", "keywords": [ - "auto-reset", - "demo", "filament", "laracorekit", "laravel", - "module" + "livewire", + "modular", + "starter-kit" + ], + "support": { + "source": "https://github.com/ProgrammerNomad/laracorekit-package", + "issues": "https://github.com/ProgrammerNomad/LaraCoreKit/issues" + }, + "transport-options": { + "symlink": true, + "relative": true + } + }, + { + "name": "programmernomad/laracorekit-demo-module", + "version": "v1.0.5", + "source": { + "type": "git", + "url": "https://github.com/ProgrammerNomad/laracorekit-demo-module.git", + "reference": "7237b3b79d8b5927ba17feed39fc030a40e0a34f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ProgrammerNomad/laracorekit-demo-module/zipball/7237b3b79d8b5927ba17feed39fc030a40e0a34f", + "reference": "7237b3b79d8b5927ba17feed39fc030a40e0a34f", + "shasum": "" + }, + "require": { + "illuminate/console": "^11.0|^12.0|^13.0", + "illuminate/database": "^11.0|^12.0|^13.0", + "illuminate/filesystem": "^11.0|^12.0|^13.0", + "illuminate/support": "^11.0|^12.0|^13.0", + "php": "^8.2|^8.3" + }, + "require-dev": { + "filament/filament": "^3.0|^4.0|^5.0", + "laravel/pint": "^1.0", + "orchestra/testbench": "^9.0|^10.0", + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "LaraCoreKit\\DemoModule\\DemoServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "LaraCoreKit\\DemoModule\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "ProgrammerNomad", + "homepage": "https://github.com/ProgrammerNomad" + } + ], + "description": "Auto-resetting demo environment for Laravel applications with Filament integration", + "homepage": "https://github.com/ProgrammerNomad/laracorekit-demo-module", + "keywords": [ + "auto-reset", + "demo", + "filament", + "laracorekit", + "laravel", + "module" ], "support": { "issues": "https://github.com/ProgrammerNomad/laracorekit-demo-module/issues", @@ -5081,16 +5345,16 @@ }, { "name": "psy/psysh", - "version": "v0.12.22", + "version": "v0.12.24", "source": { "type": "git", "url": "https://github.com/bobthecow/psysh.git", - "reference": "3be75d5b9244936dd4ac62ade2bfb004d13acf0f" + "reference": "ca0fdcf8a7617afa3adfdf1b5fef573dffb69ca1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/psysh/zipball/3be75d5b9244936dd4ac62ade2bfb004d13acf0f", - "reference": "3be75d5b9244936dd4ac62ade2bfb004d13acf0f", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/ca0fdcf8a7617afa3adfdf1b5fef573dffb69ca1", + "reference": "ca0fdcf8a7617afa3adfdf1b5fef573dffb69ca1", "shasum": "" }, "require": { @@ -5154,53 +5418,9 @@ ], "support": { "issues": "https://github.com/bobthecow/psysh/issues", - "source": "https://github.com/bobthecow/psysh/tree/v0.12.22" - }, - "time": "2026-03-22T23:03:24+00:00" - }, - { - "name": "ralouphie/getallheaders", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/ralouphie/getallheaders.git", - "reference": "120b605dfeb996808c31b6477290a714d356e822" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", - "reference": "120b605dfeb996808c31b6477290a714d356e822", - "shasum": "" - }, - "require": { - "php": ">=5.6" - }, - "require-dev": { - "php-coveralls/php-coveralls": "^2.1", - "phpunit/phpunit": "^5 || ^6.5" - }, - "type": "library", - "autoload": { - "files": [ - "src/getallheaders.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ralph Khattar", - "email": "ralph.khattar@gmail.com" - } - ], - "description": "A polyfill for getallheaders.", - "support": { - "issues": "https://github.com/ralouphie/getallheaders/issues", - "source": "https://github.com/ralouphie/getallheaders/tree/develop" + "source": "https://github.com/bobthecow/psysh/tree/v0.12.24" }, - "time": "2019-03-08T08:55:37+00:00" + "time": "2026-06-29T15:41:09+00:00" }, { "name": "ramsey/collection", @@ -5280,20 +5500,20 @@ }, { "name": "ramsey/uuid", - "version": "4.9.2", + "version": "4.9.4", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "8429c78ca35a09f27565311b98101e2826affde0" + "reference": "75d73f48d02797c2c285a7e9f348fadc0102ffe2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/8429c78ca35a09f27565311b98101e2826affde0", - "reference": "8429c78ca35a09f27565311b98101e2826affde0", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/75d73f48d02797c2c285a7e9f348fadc0102ffe2", + "reference": "75d73f48d02797c2c285a7e9f348fadc0102ffe2", "shasum": "" }, "require": { - "brick/math": "^0.8.16 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13 || ^0.14", + "brick/math": "^0.8.16 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13 || ^0.14 || ^0.15 || ^0.16 || ^0.17 || ^0.18 || ^0.19 || ^0.20 || ^1.0", "php": "^8.0", "ramsey/collection": "^1.2 || ^2.0" }, @@ -5352,9 +5572,9 @@ ], "support": { "issues": "https://github.com/ramsey/uuid/issues", - "source": "https://github.com/ramsey/uuid/tree/4.9.2" + "source": "https://github.com/ramsey/uuid/tree/4.9.4" }, - "time": "2025-12-14T04:43:48+00:00" + "time": "2026-09-16T11:39:30+00:00" }, { "name": "ryangjchandler/blade-capture-directive", @@ -5512,154 +5732,18 @@ ], "time": "2022-12-17T21:53:22+00:00" }, - { - "name": "spatie/browsershot", - "version": "5.2.3", - "source": { - "type": "git", - "url": "https://github.com/spatie/browsershot.git", - "reference": "d2e4ac7c69162999940172a674bf83ddc5ac59ea" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/spatie/browsershot/zipball/d2e4ac7c69162999940172a674bf83ddc5ac59ea", - "reference": "d2e4ac7c69162999940172a674bf83ddc5ac59ea", - "shasum": "" - }, - "require": { - "ext-fileinfo": "*", - "ext-json": "*", - "php": "^8.2", - "spatie/temporary-directory": "^2.0", - "symfony/process": "^6.0|^7.0|^8.0" - }, - "require-dev": { - "pestphp/pest": "^3.0|^4.0", - "spatie/image": "^3.6", - "spatie/pdf-to-text": "^1.52", - "spatie/phpunit-snapshot-assertions": "^5.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Spatie\\Browsershot\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Freek Van der Herten", - "email": "freek@spatie.be", - "homepage": "https://github.com/freekmurze", - "role": "Developer" - } - ], - "description": "Convert a webpage to an image or pdf using headless Chrome", - "homepage": "https://github.com/spatie/browsershot", - "keywords": [ - "chrome", - "convert", - "headless", - "image", - "pdf", - "puppeteer", - "screenshot", - "webpage" - ], - "support": { - "source": "https://github.com/spatie/browsershot/tree/5.2.3" - }, - "funding": [ - { - "url": "https://github.com/spatie", - "type": "github" - } - ], - "time": "2026-02-18T16:10:58+00:00" - }, - { - "name": "spatie/crawler", - "version": "8.5.0", - "source": { - "type": "git", - "url": "https://github.com/spatie/crawler.git", - "reference": "18198a2198adff1637c0028cb60d2c9559721556" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/spatie/crawler/zipball/18198a2198adff1637c0028cb60d2c9559721556", - "reference": "18198a2198adff1637c0028cb60d2c9559721556", - "shasum": "" - }, - "require": { - "guzzlehttp/guzzle": "^7.3", - "guzzlehttp/psr7": "^2.0", - "illuminate/collections": "^10.0|^11.0|^12.0|^13.0", - "nicmart/tree": "^0.10", - "php": "^8.2", - "spatie/browsershot": "^5.0.5", - "spatie/robots-txt": "^2.0", - "symfony/dom-crawler": "^6.0|^7.0|^8.0" - }, - "require-dev": { - "pestphp/pest": "^2.0|^3.0|^4.0", - "spatie/ray": "^1.37" - }, - "type": "library", - "autoload": { - "psr-4": { - "Spatie\\Crawler\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Freek Van der Herten", - "email": "freek@spatie.be" - } - ], - "description": "Crawl all internal links found on a website", - "homepage": "https://github.com/spatie/crawler", - "keywords": [ - "crawler", - "link", - "spatie", - "website" - ], - "support": { - "issues": "https://github.com/spatie/crawler/issues", - "source": "https://github.com/spatie/crawler/tree/8.5.0" - }, - "funding": [ - { - "url": "https://spatie.be/open-source/support-us", - "type": "custom" - }, - { - "url": "https://github.com/spatie", - "type": "github" - } - ], - "time": "2026-02-21T22:52:37+00:00" - }, { "name": "spatie/image", - "version": "3.9.4", + "version": "3.9.7", "source": { "type": "git", "url": "https://github.com/spatie/image.git", - "reference": "6a322b5e9268e3903d4fb6e1ff08b7dcc3aa9429" + "reference": "5450a2f63f315d56453fbbf58f5dacaecbf48dd4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/image/zipball/6a322b5e9268e3903d4fb6e1ff08b7dcc3aa9429", - "reference": "6a322b5e9268e3903d4fb6e1ff08b7dcc3aa9429", + "url": "https://api.github.com/repos/spatie/image/zipball/5450a2f63f315d56453fbbf58f5dacaecbf48dd4", + "reference": "5450a2f63f315d56453fbbf58f5dacaecbf48dd4", "shasum": "" }, "require": { @@ -5672,8 +5756,10 @@ "symfony/process": "^6.4|^7.0|^8.0" }, "require-dev": { + "ext-ffi": "*", "ext-gd": "*", "ext-imagick": "*", + "jcupitt/vips": "^2.4", "laravel/sail": "^1.34", "pestphp/pest": "^3.0|^4.0", "phpstan/phpstan": "^1.10.50", @@ -5707,7 +5793,7 @@ "spatie" ], "support": { - "source": "https://github.com/spatie/image/tree/3.9.4" + "source": "https://github.com/spatie/image/tree/3.9.7" }, "funding": [ { @@ -5719,25 +5805,25 @@ "type": "github" } ], - "time": "2026-03-13T14:23:45+00:00" + "time": "2026-09-30T07:06:27+00:00" }, { "name": "spatie/image-optimizer", - "version": "1.8.1", + "version": "1.10.0", "source": { "type": "git", "url": "https://github.com/spatie/image-optimizer.git", - "reference": "2ad9ac7c19501739183359ae64ea6c15869c23d9" + "reference": "333c03952289dc2df0a91874636a0dffeb5b6aec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/image-optimizer/zipball/2ad9ac7c19501739183359ae64ea6c15869c23d9", - "reference": "2ad9ac7c19501739183359ae64ea6c15869c23d9", + "url": "https://api.github.com/repos/spatie/image-optimizer/zipball/333c03952289dc2df0a91874636a0dffeb5b6aec", + "reference": "333c03952289dc2df0a91874636a0dffeb5b6aec", "shasum": "" }, "require": { "ext-fileinfo": "*", - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "psr/log": "^1.0 | ^2.0 | ^3.0", "symfony/process": "^4.2|^5.0|^6.0|^7.0|^8.0" }, @@ -5772,22 +5858,22 @@ ], "support": { "issues": "https://github.com/spatie/image-optimizer/issues", - "source": "https://github.com/spatie/image-optimizer/tree/1.8.1" + "source": "https://github.com/spatie/image-optimizer/tree/1.10.0" }, - "time": "2025-11-26T10:57:19+00:00" + "time": "2026-06-29T08:28:30+00:00" }, { "name": "spatie/invade", - "version": "2.1.0", + "version": "2.1.1", "source": { "type": "git", "url": "https://github.com/spatie/invade.git", - "reference": "b920f6411d21df4e8610a138e2e87ae4957d7f63" + "reference": "f929c7b6e75fceeefa7b41a491e91274bafb17af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/invade/zipball/b920f6411d21df4e8610a138e2e87ae4957d7f63", - "reference": "b920f6411d21df4e8610a138e2e87ae4957d7f63", + "url": "https://api.github.com/repos/spatie/invade/zipball/f929c7b6e75fceeefa7b41a491e91274bafb17af", + "reference": "f929c7b6e75fceeefa7b41a491e91274bafb17af", "shasum": "" }, "require": { @@ -5825,7 +5911,7 @@ "spatie" ], "support": { - "source": "https://github.com/spatie/invade/tree/2.1.0" + "source": "https://github.com/spatie/invade/tree/2.1.1" }, "funding": [ { @@ -5833,20 +5919,20 @@ "type": "github" } ], - "time": "2024-05-17T09:06:10+00:00" + "time": "2026-08-24T12:39:05+00:00" }, { "name": "spatie/laravel-medialibrary", - "version": "11.21.0", + "version": "11.23.9", "source": { "type": "git", "url": "https://github.com/spatie/laravel-medialibrary.git", - "reference": "d6e2595033ffd130d4dd5d124510ab3304794c44" + "reference": "afe6e389994ada7f33b731a837ea79301a7ec6c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-medialibrary/zipball/d6e2595033ffd130d4dd5d124510ab3304794c44", - "reference": "d6e2595033ffd130d4dd5d124510ab3304794c44", + "url": "https://api.github.com/repos/spatie/laravel-medialibrary/zipball/afe6e389994ada7f33b731a837ea79301a7ec6c1", + "reference": "afe6e389994ada7f33b731a837ea79301a7ec6c1", "shasum": "" }, "require": { @@ -5931,7 +6017,7 @@ ], "support": { "issues": "https://github.com/spatie/laravel-medialibrary/issues", - "source": "https://github.com/spatie/laravel-medialibrary/tree/11.21.0" + "source": "https://github.com/spatie/laravel-medialibrary/tree/11.23.9" }, "funding": [ { @@ -5943,20 +6029,20 @@ "type": "github" } ], - "time": "2026-02-21T15:58:56+00:00" + "time": "2026-10-05T08:08:06+00:00" }, { "name": "spatie/laravel-package-tools", - "version": "1.93.0", + "version": "1.93.3", "source": { "type": "git", "url": "https://github.com/spatie/laravel-package-tools.git", - "reference": "0d097bce95b2bf6802fb1d83e1e753b0f5a948e7" + "reference": "7aeef26bd8d4909bec744dbf47aee7d1395588c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/0d097bce95b2bf6802fb1d83e1e753b0f5a948e7", - "reference": "0d097bce95b2bf6802fb1d83e1e753b0f5a948e7", + "url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/7aeef26bd8d4909bec744dbf47aee7d1395588c1", + "reference": "7aeef26bd8d4909bec744dbf47aee7d1395588c1", "shasum": "" }, "require": { @@ -5996,7 +6082,7 @@ ], "support": { "issues": "https://github.com/spatie/laravel-package-tools/issues", - "source": "https://github.com/spatie/laravel-package-tools/tree/1.93.0" + "source": "https://github.com/spatie/laravel-package-tools/tree/1.93.3" }, "funding": [ { @@ -6004,7 +6090,7 @@ "type": "github" } ], - "time": "2026-02-21T12:49:54+00:00" + "time": "2026-09-28T07:16:50+00:00" }, { "name": "spatie/laravel-permission", @@ -6091,47 +6177,35 @@ "time": "2026-03-17T22:46:46+00:00" }, { - "name": "spatie/laravel-sitemap", - "version": "8.0.0", + "name": "spatie/shiki-php", + "version": "2.4.0", "source": { "type": "git", - "url": "https://github.com/spatie/laravel-sitemap.git", - "reference": "8c79e1420a6f41405707ea7d00bb6cc10160c0ac" + "url": "https://github.com/spatie/shiki-php.git", + "reference": "b8b0ca32d3a82bc5c533e68ffab96c5d4ec1b9ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-sitemap/zipball/8c79e1420a6f41405707ea7d00bb6cc10160c0ac", - "reference": "8c79e1420a6f41405707ea7d00bb6cc10160c0ac", + "url": "https://api.github.com/repos/spatie/shiki-php/zipball/b8b0ca32d3a82bc5c533e68ffab96c5d4ec1b9ba", + "reference": "b8b0ca32d3a82bc5c533e68ffab96c5d4ec1b9ba", "shasum": "" }, "require": { - "guzzlehttp/guzzle": "^7.8", - "illuminate/support": "^11.0|^12.0||^13.0", - "nesbot/carbon": "^2.71|^3.0", - "php": "^8.2||^8.3||^8.4||^8.5", - "spatie/crawler": "^8.0.1", - "spatie/laravel-package-tools": "^1.16.1", - "symfony/dom-crawler": "^6.3.4|^7.0|^8.0" + "ext-json": "*", + "php": "^8.0", + "symfony/process": "^5.4|^6.4|^7.1|^8.0" }, "require-dev": { - "mockery/mockery": "^1.6.6", - "orchestra/testbench": "^9.0|^10.0||^11.0", - "pestphp/pest": "^3.7.4|^4.0", - "spatie/pest-plugin-snapshots": "^2.1", - "spatie/phpunit-snapshot-assertions": "^5.1.2", - "spatie/temporary-directory": "^2.2" + "friendsofphp/php-cs-fixer": "^v3.0", + "pestphp/pest": "^1.8", + "phpunit/phpunit": "^9.5", + "spatie/pest-plugin-snapshots": "^1.1", + "spatie/ray": "^1.10" }, "type": "library", - "extra": { - "laravel": { - "providers": [ - "Spatie\\Sitemap\\SitemapServiceProvider" - ] - } - }, "autoload": { "psr-4": { - "Spatie\\Sitemap\\": "src" + "Spatie\\ShikiPhp\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -6139,54 +6213,58 @@ "MIT" ], "authors": [ + { + "name": "Rias Van der Veken", + "email": "rias@spatie.be", + "role": "Developer" + }, { "name": "Freek Van der Herten", "email": "freek@spatie.be", - "homepage": "https://spatie.be", "role": "Developer" } ], - "description": "Create and generate sitemaps with ease", - "homepage": "https://github.com/spatie/laravel-sitemap", + "description": "Highlight code using Shiki in PHP", + "homepage": "https://github.com/spatie/shiki-php", "keywords": [ - "laravel-sitemap", + "shiki", "spatie" ], "support": { - "source": "https://github.com/spatie/laravel-sitemap/tree/8.0.0" + "source": "https://github.com/spatie/shiki-php/tree/2.4.0" }, "funding": [ { - "url": "https://spatie.be/open-source/support-us", - "type": "custom" + "url": "https://github.com/spatie", + "type": "github" } ], - "time": "2026-02-21T23:01:14+00:00" + "time": "2026-04-27T14:27:52+00:00" }, { - "name": "spatie/robots-txt", - "version": "2.5.4", + "name": "spatie/temporary-directory", + "version": "2.4.0", "source": { "type": "git", - "url": "https://github.com/spatie/robots-txt.git", - "reference": "a8dd35d0a94e863f52509a366a634978e9c1db03" + "url": "https://github.com/spatie/temporary-directory.git", + "reference": "32cbb9645b28839cf4f476708e99a2c70e6802c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/robots-txt/zipball/a8dd35d0a94e863f52509a366a634978e9c1db03", - "reference": "a8dd35d0a94e863f52509a366a634978e9c1db03", + "url": "https://api.github.com/repos/spatie/temporary-directory/zipball/32cbb9645b28839cf4f476708e99a2c70e6802c9", + "reference": "32cbb9645b28839cf4f476708e99a2c70e6802c9", "shasum": "" }, "require": { - "php": "^8.1" + "php": "^8.0" }, "require-dev": { - "phpunit/phpunit": "^11.5.2" + "phpunit/phpunit": "^9.5" }, "type": "library", "autoload": { "psr-4": { - "Spatie\\Robots\\": "src" + "Spatie\\TemporaryDirectory\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -6195,21 +6273,22 @@ ], "authors": [ { - "name": "Brent Roose", - "email": "brent@spatie.be", + "name": "Alex Vanderbist", + "email": "alex@spatie.be", "homepage": "https://spatie.be", "role": "Developer" } ], - "description": "Determine if a page may be crawled from robots.txt and robots meta tags", - "homepage": "https://github.com/spatie/robots-txt", + "description": "Easily create, use and destroy temporary directories", + "homepage": "https://github.com/spatie/temporary-directory", "keywords": [ - "robots-txt", - "spatie" + "php", + "spatie", + "temporary-directory" ], "support": { - "issues": "https://github.com/spatie/robots-txt/issues", - "source": "https://github.com/spatie/robots-txt/tree/2.5.4" + "issues": "https://github.com/spatie/temporary-directory/issues", + "source": "https://github.com/spatie/temporary-directory/tree/2.4.0" }, "funding": [ { @@ -6221,161 +6300,35 @@ "type": "github" } ], - "time": "2026-02-25T07:59:20+00:00" + "time": "2026-06-22T07:55:44+00:00" }, { - "name": "spatie/shiki-php", - "version": "2.3.3", + "name": "symfony/clock", + "version": "v7.4.21", "source": { "type": "git", - "url": "https://github.com/spatie/shiki-php.git", - "reference": "9d50ff4d9825d87d3283a6695c65ae9c3c3caa6b" + "url": "https://github.com/symfony/clock.git", + "reference": "07437f612dca89c1894c1db04491002b1e798f03" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/shiki-php/zipball/9d50ff4d9825d87d3283a6695c65ae9c3c3caa6b", - "reference": "9d50ff4d9825d87d3283a6695c65ae9c3c3caa6b", + "url": "https://api.github.com/repos/symfony/clock/zipball/07437f612dca89c1894c1db04491002b1e798f03", + "reference": "07437f612dca89c1894c1db04491002b1e798f03", "shasum": "" }, "require": { - "ext-json": "*", - "php": "^8.0", - "symfony/process": "^5.4|^6.4|^7.1|^8.0" + "php": ">=8.2", + "psr/clock": "^1.0", + "symfony/polyfill-php83": "^1.28" }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^v3.0", - "pestphp/pest": "^1.8", - "phpunit/phpunit": "^9.5", - "spatie/pest-plugin-snapshots": "^1.1", - "spatie/ray": "^1.10" + "provide": { + "psr/clock-implementation": "1.0" }, "type": "library", "autoload": { - "psr-4": { - "Spatie\\ShikiPhp\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Rias Van der Veken", - "email": "rias@spatie.be", - "role": "Developer" - }, - { - "name": "Freek Van der Herten", - "email": "freek@spatie.be", - "role": "Developer" - } - ], - "description": "Highlight code using Shiki in PHP", - "homepage": "https://github.com/spatie/shiki-php", - "keywords": [ - "shiki", - "spatie" - ], - "support": { - "source": "https://github.com/spatie/shiki-php/tree/2.3.3" - }, - "funding": [ - { - "url": "https://github.com/spatie", - "type": "github" - } - ], - "time": "2026-02-01T09:30:04+00:00" - }, - { - "name": "spatie/temporary-directory", - "version": "2.3.1", - "source": { - "type": "git", - "url": "https://github.com/spatie/temporary-directory.git", - "reference": "662e481d6ec07ef29fd05010433428851a42cd07" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/spatie/temporary-directory/zipball/662e481d6ec07ef29fd05010433428851a42cd07", - "reference": "662e481d6ec07ef29fd05010433428851a42cd07", - "shasum": "" - }, - "require": { - "php": "^8.0" - }, - "require-dev": { - "phpunit/phpunit": "^9.5" - }, - "type": "library", - "autoload": { - "psr-4": { - "Spatie\\TemporaryDirectory\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Alex Vanderbist", - "email": "alex@spatie.be", - "homepage": "https://spatie.be", - "role": "Developer" - } - ], - "description": "Easily create, use and destroy temporary directories", - "homepage": "https://github.com/spatie/temporary-directory", - "keywords": [ - "php", - "spatie", - "temporary-directory" - ], - "support": { - "issues": "https://github.com/spatie/temporary-directory/issues", - "source": "https://github.com/spatie/temporary-directory/tree/2.3.1" - }, - "funding": [ - { - "url": "https://spatie.be/open-source/support-us", - "type": "custom" - }, - { - "url": "https://github.com/spatie", - "type": "github" - } - ], - "time": "2026-01-12T07:42:22+00:00" - }, - { - "name": "symfony/clock", - "version": "v7.4.8", - "source": { - "type": "git", - "url": "https://github.com/symfony/clock.git", - "reference": "674fa3b98e21531dd040e613479f5f6fa8f32111" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/clock/zipball/674fa3b98e21531dd040e613479f5f6fa8f32111", - "reference": "674fa3b98e21531dd040e613479f5f6fa8f32111", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "psr/clock": "^1.0", - "symfony/polyfill-php83": "^1.28" - }, - "provide": { - "psr/clock-implementation": "1.0" - }, - "type": "library", - "autoload": { - "files": [ - "Resources/now.php" - ], + "files": [ + "Resources/now.php" + ], "psr-4": { "Symfony\\Component\\Clock\\": "" }, @@ -6405,7 +6358,7 @@ "time" ], "support": { - "source": "https://github.com/symfony/clock/tree/v7.4.8" + "source": "https://github.com/symfony/clock/tree/v7.4.21" }, "funding": [ { @@ -6425,20 +6378,20 @@ "type": "tidelift" } ], - "time": "2026-03-24T13:12:05+00:00" + "time": "2026-10-12T14:31:36+00:00" }, { "name": "symfony/console", - "version": "v7.4.8", + "version": "v7.4.21", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "1e92e39c51f95b88e3d66fa2d9f06d1fb45dd707" + "reference": "21f1bc2296f7ff6043241a8dcbc09559b3732820" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/1e92e39c51f95b88e3d66fa2d9f06d1fb45dd707", - "reference": "1e92e39c51f95b88e3d66fa2d9f06d1fb45dd707", + "url": "https://api.github.com/repos/symfony/console/zipball/21f1bc2296f7ff6043241a8dcbc09559b3732820", + "reference": "21f1bc2296f7ff6043241a8dcbc09559b3732820", "shasum": "" }, "require": { @@ -6503,7 +6456,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.4.8" + "source": "https://github.com/symfony/console/tree/v7.4.21" }, "funding": [ { @@ -6523,20 +6476,20 @@ "type": "tidelift" } ], - "time": "2026-03-30T13:54:39+00:00" + "time": "2026-10-12T18:45:38+00:00" }, { "name": "symfony/css-selector", - "version": "v7.4.8", + "version": "v7.4.18", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "b055f228a4178a1d6774909903905e3475f3eac8" + "reference": "fecf40067fc8d8880ea87b8ac227600b9aadd1d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/b055f228a4178a1d6774909903905e3475f3eac8", - "reference": "b055f228a4178a1d6774909903905e3475f3eac8", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/fecf40067fc8d8880ea87b8ac227600b9aadd1d0", + "reference": "fecf40067fc8d8880ea87b8ac227600b9aadd1d0", "shasum": "" }, "require": { @@ -6572,7 +6525,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v7.4.8" + "source": "https://github.com/symfony/css-selector/tree/v7.4.18" }, "funding": [ { @@ -6592,20 +6545,20 @@ "type": "tidelift" } ], - "time": "2026-03-24T13:12:05+00:00" + "time": "2026-08-23T10:03:40+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.6.0", + "version": "v3.7.1", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" + "reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", - "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/f3202fa1b5097b0af062dc978b32ecf63404e31d", + "reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d", "shasum": "" }, "require": { @@ -6618,7 +6571,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.6-dev" + "dev-main": "3.7-dev" } }, "autoload": { @@ -6643,75 +6596,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-09-25T14:21:43+00:00" - }, - { - "name": "symfony/dom-crawler", - "version": "v7.4.8", - "source": { - "type": "git", - "url": "https://github.com/symfony/dom-crawler.git", - "reference": "2918e7c2ba964defca1f5b69c6f74886529e2dc8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/2918e7c2ba964defca1f5b69c6f74886529e2dc8", - "reference": "2918e7c2ba964defca1f5b69c6f74886529e2dc8", - "shasum": "" - }, - "require": { - "masterminds/html5": "^2.6", - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.0" - }, - "require-dev": { - "symfony/css-selector": "^6.4|^7.0|^8.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\DomCrawler\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Eases DOM navigation for HTML and XML documents", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/dom-crawler/tree/v7.4.8" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.7.1" }, "funding": [ { @@ -6731,20 +6616,20 @@ "type": "tidelift" } ], - "time": "2026-03-24T13:12:05+00:00" + "time": "2026-06-05T06:23:12+00:00" }, { "name": "symfony/error-handler", - "version": "v7.4.8", + "version": "v7.4.20", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "8dd79d8af777ee6cba2fd4d98da6ffb839f3c0fa" + "reference": "82239fe00f7cdc9f17c4166fff4ebdc22bd26ec0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/8dd79d8af777ee6cba2fd4d98da6ffb839f3c0fa", - "reference": "8dd79d8af777ee6cba2fd4d98da6ffb839f3c0fa", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/82239fe00f7cdc9f17c4166fff4ebdc22bd26ec0", + "reference": "82239fe00f7cdc9f17c4166fff4ebdc22bd26ec0", "shasum": "" }, "require": { @@ -6793,7 +6678,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v7.4.8" + "source": "https://github.com/symfony/error-handler/tree/v7.4.20" }, "funding": [ { @@ -6813,20 +6698,20 @@ "type": "tidelift" } ], - "time": "2026-03-24T13:12:05+00:00" + "time": "2026-09-22T18:56:40+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v7.4.8", + "version": "v7.4.17", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "f57b899fa736fd71121168ef268f23c206083f0a" + "reference": "d269974ee93c61d03620ffee358355bfdb471d66" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/f57b899fa736fd71121168ef268f23c206083f0a", - "reference": "f57b899fa736fd71121168ef268f23c206083f0a", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/d269974ee93c61d03620ffee358355bfdb471d66", + "reference": "d269974ee93c61d03620ffee358355bfdb471d66", "shasum": "" }, "require": { @@ -6878,7 +6763,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v7.4.8" + "source": "https://github.com/symfony/event-dispatcher/tree/v7.4.17" }, "funding": [ { @@ -6898,20 +6783,20 @@ "type": "tidelift" } ], - "time": "2026-03-30T13:54:39+00:00" + "time": "2026-08-21T17:40:08+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v3.6.0", + "version": "v3.7.1", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "59eb412e93815df44f05f342958efa9f46b1e586" + "reference": "c7de7a00ffb67842132da02ea92988a39ccd9f4e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586", - "reference": "59eb412e93815df44f05f342958efa9f46b1e586", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/c7de7a00ffb67842132da02ea92988a39ccd9f4e", + "reference": "c7de7a00ffb67842132da02ea92988a39ccd9f4e", "shasum": "" }, "require": { @@ -6925,7 +6810,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.6-dev" + "dev-main": "3.7-dev" } }, "autoload": { @@ -6958,7 +6843,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.6.0" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.7.1" }, "funding": [ { @@ -6969,25 +6854,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-25T14:21:43+00:00" + "time": "2026-06-05T06:23:12+00:00" }, { "name": "symfony/finder", - "version": "v7.4.8", + "version": "v7.4.20", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "e0be088d22278583a82da281886e8c3592fbf149" + "reference": "2dd31e5208db7a0fda7bfc998ad727b79c2e4d1e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/e0be088d22278583a82da281886e8c3592fbf149", - "reference": "e0be088d22278583a82da281886e8c3592fbf149", + "url": "https://api.github.com/repos/symfony/finder/zipball/2dd31e5208db7a0fda7bfc998ad727b79c2e4d1e", + "reference": "2dd31e5208db7a0fda7bfc998ad727b79c2e4d1e", "shasum": "" }, "require": { @@ -7022,7 +6911,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.4.8" + "source": "https://github.com/symfony/finder/tree/v7.4.20" }, "funding": [ { @@ -7042,20 +6931,20 @@ "type": "tidelift" } ], - "time": "2026-03-24T13:12:05+00:00" + "time": "2026-09-26T06:31:10+00:00" }, { "name": "symfony/html-sanitizer", - "version": "v7.4.8", + "version": "v7.4.20", "source": { "type": "git", "url": "https://github.com/symfony/html-sanitizer.git", - "reference": "9a79c53c4bf0a8a7b0d3d917fe03eda605ea6438" + "reference": "0b7605debddc90c7c9d4e9c1b6eb520a248f26dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/html-sanitizer/zipball/9a79c53c4bf0a8a7b0d3d917fe03eda605ea6438", - "reference": "9a79c53c4bf0a8a7b0d3d917fe03eda605ea6438", + "url": "https://api.github.com/repos/symfony/html-sanitizer/zipball/0b7605debddc90c7c9d4e9c1b6eb520a248f26dc", + "reference": "0b7605debddc90c7c9d4e9c1b6eb520a248f26dc", "shasum": "" }, "require": { @@ -7096,7 +6985,7 @@ "sanitizer" ], "support": { - "source": "https://github.com/symfony/html-sanitizer/tree/v7.4.8" + "source": "https://github.com/symfony/html-sanitizer/tree/v7.4.20" }, "funding": [ { @@ -7116,20 +7005,20 @@ "type": "tidelift" } ], - "time": "2026-03-24T13:12:05+00:00" + "time": "2026-09-28T05:21:23+00:00" }, { "name": "symfony/http-foundation", - "version": "v7.4.8", + "version": "v7.4.21", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "9381209597ec66c25be154cbf2289076e64d1eab" + "reference": "58c89144c7a36dd89c3d01917e9fa3a72d8aaf31" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/9381209597ec66c25be154cbf2289076e64d1eab", - "reference": "9381209597ec66c25be154cbf2289076e64d1eab", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/58c89144c7a36dd89c3d01917e9fa3a72d8aaf31", + "reference": "58c89144c7a36dd89c3d01917e9fa3a72d8aaf31", "shasum": "" }, "require": { @@ -7178,7 +7067,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v7.4.8" + "source": "https://github.com/symfony/http-foundation/tree/v7.4.21" }, "funding": [ { @@ -7198,20 +7087,20 @@ "type": "tidelift" } ], - "time": "2026-03-24T13:12:05+00:00" + "time": "2026-10-08T16:56:12+00:00" }, { "name": "symfony/http-kernel", - "version": "v7.4.8", + "version": "v7.4.21", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "017e76ad089bac281553389269e259e155935e1a" + "reference": "4779fce7dedacb8801b2b61c703ef99159502331" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/017e76ad089bac281553389269e259e155935e1a", - "reference": "017e76ad089bac281553389269e259e155935e1a", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/4779fce7dedacb8801b2b61c703ef99159502331", + "reference": "4779fce7dedacb8801b2b61c703ef99159502331", "shasum": "" }, "require": { @@ -7269,7 +7158,7 @@ "symfony/validator": "^6.4|^7.0|^8.0", "symfony/var-dumper": "^6.4|^7.0|^8.0", "symfony/var-exporter": "^6.4|^7.0|^8.0", - "twig/twig": "^3.12" + "twig/twig": "^3.12|^4.0" }, "type": "library", "autoload": { @@ -7297,7 +7186,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v7.4.8" + "source": "https://github.com/symfony/http-kernel/tree/v7.4.21" }, "funding": [ { @@ -7317,20 +7206,20 @@ "type": "tidelift" } ], - "time": "2026-03-31T20:57:01+00:00" + "time": "2026-10-14T06:44:08+00:00" }, { "name": "symfony/mailer", - "version": "v7.4.8", + "version": "v7.4.19", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "f6ea532250b476bfc1b56699b388a1bdbf168f62" + "reference": "6f6f2441bef07a42d2617b9b3aadf04a321aa514" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/f6ea532250b476bfc1b56699b388a1bdbf168f62", - "reference": "f6ea532250b476bfc1b56699b388a1bdbf168f62", + "url": "https://api.github.com/repos/symfony/mailer/zipball/6f6f2441bef07a42d2617b9b3aadf04a321aa514", + "reference": "6f6f2441bef07a42d2617b9b3aadf04a321aa514", "shasum": "" }, "require": { @@ -7381,7 +7270,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v7.4.8" + "source": "https://github.com/symfony/mailer/tree/v7.4.19" }, "funding": [ { @@ -7401,20 +7290,20 @@ "type": "tidelift" } ], - "time": "2026-03-24T13:12:05+00:00" + "time": "2026-09-15T06:01:15+00:00" }, { "name": "symfony/mime", - "version": "v7.4.8", + "version": "v7.4.19", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "6df02f99998081032da3407a8d6c4e1dcb5d4379" + "reference": "f8ac7d0a800bcabbcd1f7de56594cf05e6cd5693" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/6df02f99998081032da3407a8d6c4e1dcb5d4379", - "reference": "6df02f99998081032da3407a8d6c4e1dcb5d4379", + "url": "https://api.github.com/repos/symfony/mime/zipball/f8ac7d0a800bcabbcd1f7de56594cf05e6cd5693", + "reference": "f8ac7d0a800bcabbcd1f7de56594cf05e6cd5693", "shasum": "" }, "require": { @@ -7438,7 +7327,7 @@ "symfony/process": "^6.4|^7.0|^8.0", "symfony/property-access": "^6.4|^7.0|^8.0", "symfony/property-info": "^6.4|^7.0|^8.0", - "symfony/serializer": "^6.4.3|^7.0.3|^8.0" + "symfony/serializer": "^6.4.44|^7.4.17|^8.1.5" }, "type": "library", "autoload": { @@ -7470,7 +7359,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v7.4.8" + "source": "https://github.com/symfony/mime/tree/v7.4.19" }, "funding": [ { @@ -7490,11 +7379,11 @@ "type": "tidelift" } ], - "time": "2026-03-30T14:11:46+00:00" + "time": "2026-09-04T10:45:44+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.36.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", @@ -7553,7 +7442,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.36.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.37.0" }, "funding": [ { @@ -7577,16 +7466,16 @@ }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.36.0", + "version": "v1.43.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "ad1b7b9092976d6c948b8a187cec9faaea9ec1df" + "reference": "5cac8f4db97208823aa353f59a01faad2da52c75" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/ad1b7b9092976d6c948b8a187cec9faaea9ec1df", - "reference": "ad1b7b9092976d6c948b8a187cec9faaea9ec1df", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/5cac8f4db97208823aa353f59a01faad2da52c75", + "reference": "5cac8f4db97208823aa353f59a01faad2da52c75", "shasum": "" }, "require": { @@ -7635,7 +7524,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.36.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.43.0" }, "funding": [ { @@ -7655,28 +7544,281 @@ "type": "tidelift" } ], - "time": "2026-04-10T16:19:22+00:00" + "time": "2026-09-25T15:46:47+00:00" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.43.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "533d68cf99c8f8ee2e8893c59ed59192e92cfd74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/533d68cf99c8f8ee2e8893c59ed59192e92cfd74", + "reference": "533d68cf99c8f8ee2e8893c59ed59192e92cfd74", + "shasum": "" + }, + "require": { + "php": ">=7.2", + "symfony/polyfill-intl-normalizer": "^1.10" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.43.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-09-23T14:40:04+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.43.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "ebd57ccc7edb93d632e184efbe7693d2517bab3b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/ebd57ccc7edb93d632e184efbe7693d2517bab3b", + "reference": "ebd57ccc7edb93d632e184efbe7693d2517bab3b", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.43.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-09-23T22:02:09+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.43.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "4d5d331bf731e0aedbc6b2f5e61135b7b7996a72" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/4d5d331bf731e0aedbc6b2f5e61135b7b7996a72", + "reference": "4d5d331bf731e0aedbc6b2f5e61135b7b7996a72", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "php": ">=7.2" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.43.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-09-24T15:19:04+00:00" }, { - "name": "symfony/polyfill-intl-idn", - "version": "v1.36.0", + "name": "symfony/polyfill-php80", + "version": "v1.43.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3" + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "9c6a5d6b01ca51d486c813e9a9c0ed55f208bb74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/9614ac4d8061dc257ecc64cba1b140873dce8ad3", - "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/9c6a5d6b01ca51d486c813e9a9c0ed55f208bb74", + "reference": "9c6a5d6b01ca51d486c813e9a9c0ed55f208bb74", "shasum": "" }, "require": { - "php": ">=7.2", - "symfony/polyfill-intl-normalizer": "^1.10" - }, - "suggest": { - "ext-intl": "For best performance" + "php": ">=7.2" }, "type": "library", "extra": { @@ -7690,8 +7832,11 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Intl\\Idn\\": "" - } + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -7699,30 +7844,28 @@ ], "authors": [ { - "name": "Laurent Bassin", - "email": "laurent@bassin.info" + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" }, { - "name": "Trevor Rowbotham", - "email": "trevor.rowbotham@pm.me" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", - "idn", - "intl", "polyfill", "portable", "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.36.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.43.0" }, "funding": [ { @@ -7742,28 +7885,25 @@ "type": "tidelift" } ], - "time": "2024-09-10T14:38:51+00:00" + "time": "2026-09-25T15:50:05+00:00" }, { - "name": "symfony/polyfill-intl-normalizer", - "version": "v1.36.0", + "name": "symfony/polyfill-php82", + "version": "v1.43.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "3833d7255cc303546435cb650316bff708a1c75c" + "url": "https://github.com/symfony/polyfill-php82.git", + "reference": "843bbe8b2a7934307b749751eede0f111f5d1cfc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", - "reference": "3833d7255cc303546435cb650316bff708a1c75c", + "url": "https://api.github.com/repos/symfony/polyfill-php82/zipball/843bbe8b2a7934307b749751eede0f111f5d1cfc", + "reference": "843bbe8b2a7934307b749751eede0f111f5d1cfc", "shasum": "" }, "require": { "php": ">=7.2" }, - "suggest": { - "ext-intl": "For best performance" - }, "type": "library", "extra": { "thanks": { @@ -7776,7 +7916,7 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + "Symfony\\Polyfill\\Php82\\": "" }, "classmap": [ "Resources/stubs" @@ -7796,18 +7936,16 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for intl's Normalizer class and related functions", + "description": "Symfony polyfill backporting some PHP 8.2+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", - "intl", - "normalizer", "polyfill", "portable", "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.36.0" + "source": "https://github.com/symfony/polyfill-php82/tree/v1.43.0" }, "funding": [ { @@ -7827,32 +7965,25 @@ "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2026-09-25T15:50:05+00:00" }, { - "name": "symfony/polyfill-mbstring", - "version": "v1.36.0", + "name": "symfony/polyfill-php83", + "version": "v1.43.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "6a21eb99c6973357967f6ce3708cd55a6bec6315" + "url": "https://github.com/symfony/polyfill-php83.git", + "reference": "80ccff923a8d61f73ebe9da0aa94e25232f004ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6a21eb99c6973357967f6ce3708cd55a6bec6315", - "reference": "6a21eb99c6973357967f6ce3708cd55a6bec6315", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/80ccff923a8d61f73ebe9da0aa94e25232f004ce", + "reference": "80ccff923a8d61f73ebe9da0aa94e25232f004ce", "shasum": "" }, "require": { - "ext-iconv": "*", "php": ">=7.2" }, - "provide": { - "ext-mbstring": "*" - }, - "suggest": { - "ext-mbstring": "For best performance" - }, "type": "library", "extra": { "thanks": { @@ -7865,8 +7996,11 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - } + "Symfony\\Polyfill\\Php83\\": "" + }, + "classmap": [ + "Resources/stubs" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -7882,17 +8016,16 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for the Mbstring extension", + "description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", - "mbstring", "polyfill", "portable", "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.36.0" + "source": "https://github.com/symfony/polyfill-php83/tree/v1.43.0" }, "funding": [ { @@ -7912,20 +8045,20 @@ "type": "tidelift" } ], - "time": "2026-04-10T17:25:58+00:00" + "time": "2026-09-25T15:50:05+00:00" }, { - "name": "symfony/polyfill-php80", - "version": "v1.36.0", + "name": "symfony/polyfill-php84", + "version": "v1.43.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411" + "url": "https://github.com/symfony/polyfill-php84.git", + "reference": "22c6548499cbe5c5bb072fc0c42312dff062a015" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dfb55726c3a76ea3b6459fcfda1ec2d80a682411", - "reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411", + "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/22c6548499cbe5c5bb072fc0c42312dff062a015", + "reference": "22c6548499cbe5c5bb072fc0c42312dff062a015", "shasum": "" }, "require": { @@ -7943,7 +8076,7 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" + "Symfony\\Polyfill\\Php84\\": "" }, "classmap": [ "Resources/stubs" @@ -7954,10 +8087,6 @@ "MIT" ], "authors": [ - { - "name": "Ion Bazan", - "email": "ion.bazan@gmail.com" - }, { "name": "Nicolas Grekas", "email": "p@tchwork.com" @@ -7967,7 +8096,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "description": "Symfony polyfill backporting some PHP 8.4+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", @@ -7976,7 +8105,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.36.0" + "source": "https://github.com/symfony/polyfill-php84/tree/v1.43.0" }, "funding": [ { @@ -7996,20 +8125,20 @@ "type": "tidelift" } ], - "time": "2026-04-10T16:19:22+00:00" + "time": "2026-09-23T22:01:09+00:00" }, { - "name": "symfony/polyfill-php83", - "version": "v1.36.0", + "name": "symfony/polyfill-php85", + "version": "v1.43.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php83.git", - "reference": "3600c2cb22399e25bb226e4a135ce91eeb2a6149" + "url": "https://github.com/symfony/polyfill-php85.git", + "reference": "86a42cbcc07adc331481a5ab310a4024bfc227f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/3600c2cb22399e25bb226e4a135ce91eeb2a6149", - "reference": "3600c2cb22399e25bb226e4a135ce91eeb2a6149", + "url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/86a42cbcc07adc331481a5ab310a4024bfc227f6", + "reference": "86a42cbcc07adc331481a5ab310a4024bfc227f6", "shasum": "" }, "require": { @@ -8027,7 +8156,7 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Php83\\": "" + "Symfony\\Polyfill\\Php85\\": "" }, "classmap": [ "Resources/stubs" @@ -8047,7 +8176,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions", + "description": "Symfony polyfill backporting some PHP 8.5+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", @@ -8056,7 +8185,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php83/tree/v1.36.0" + "source": "https://github.com/symfony/polyfill-php85/tree/v1.43.0" }, "funding": [ { @@ -8076,20 +8205,20 @@ "type": "tidelift" } ], - "time": "2026-04-10T17:25:58+00:00" + "time": "2026-09-25T15:46:47+00:00" }, { - "name": "symfony/polyfill-php84", - "version": "v1.36.0", + "name": "symfony/polyfill-php86", + "version": "v1.43.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php84.git", - "reference": "88486db2c389b290bf87ff1de7ebc1e13e42bb06" + "url": "https://github.com/symfony/polyfill-php86.git", + "reference": "8840df45b24f33a49dc419fa18dc0057231ae1d8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/88486db2c389b290bf87ff1de7ebc1e13e42bb06", - "reference": "88486db2c389b290bf87ff1de7ebc1e13e42bb06", + "url": "https://api.github.com/repos/symfony/polyfill-php86/zipball/8840df45b24f33a49dc419fa18dc0057231ae1d8", + "reference": "8840df45b24f33a49dc419fa18dc0057231ae1d8", "shasum": "" }, "require": { @@ -8107,7 +8236,7 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Php84\\": "" + "Symfony\\Polyfill\\Php86\\": "" }, "classmap": [ "Resources/stubs" @@ -8127,7 +8256,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 8.4+ features to lower PHP versions", + "description": "Symfony polyfill backporting some PHP 8.6+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", @@ -8136,7 +8265,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php84/tree/v1.36.0" + "source": "https://github.com/symfony/polyfill-php86/tree/v1.43.0" }, "funding": [ { @@ -8156,24 +8285,24 @@ "type": "tidelift" } ], - "time": "2026-04-10T18:47:49+00:00" + "time": "2026-09-25T15:46:47+00:00" }, { - "name": "symfony/polyfill-php85", - "version": "v1.36.0", + "name": "symfony/polyfill-time", + "version": "v1.42.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php85.git", - "reference": "2c408a6bb0313e6001a83628dc5506100474254e" + "url": "https://github.com/symfony/polyfill-time.git", + "reference": "ac9f1ed802dd58f37e720388130c088434aa09fc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/2c408a6bb0313e6001a83628dc5506100474254e", - "reference": "2c408a6bb0313e6001a83628dc5506100474254e", + "url": "https://api.github.com/repos/symfony/polyfill-time/zipball/ac9f1ed802dd58f37e720388130c088434aa09fc", + "reference": "ac9f1ed802dd58f37e720388130c088434aa09fc", "shasum": "" }, "require": { - "php": ">=7.2" + "php": ">=8.1" }, "type": "library", "extra": { @@ -8183,11 +8312,8 @@ } }, "autoload": { - "files": [ - "bootstrap.php" - ], "psr-4": { - "Symfony\\Polyfill\\Php85\\": "" + "Symfony\\Polyfill\\Time\\": "" }, "classmap": [ "Resources/stubs" @@ -8199,24 +8325,30 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Ignace Philippe Nyamagana Butera", + "email": "nyamsprod@gmail.com" + }, + { + "name": "Tim Düsterhus", + "email": "tim@tideways-gmbh.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 8.5+ features to lower PHP versions", + "description": "Symfony polyfill for the Time API added to PHP 8.6", "homepage": "https://symfony.com", "keywords": [ "compatibility", + "duration", "polyfill", "portable", - "shim" + "shim", + "time" ], "support": { - "source": "https://github.com/symfony/polyfill-php85/tree/v1.36.0" + "source": "https://github.com/symfony/polyfill-time/tree/v1.42.0" }, "funding": [ { @@ -8236,20 +8368,20 @@ "type": "tidelift" } ], - "time": "2026-04-10T16:50:15+00:00" + "time": "2026-08-07T13:08:13+00:00" }, { "name": "symfony/polyfill-uuid", - "version": "v1.36.0", + "version": "v1.43.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-uuid.git", - "reference": "26dfec253c4cf3e51b541b52ddf7e42cb0908e94" + "reference": "b23ff8245cc5c4479ea2be3d0132d2e6dd433993" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-uuid/zipball/26dfec253c4cf3e51b541b52ddf7e42cb0908e94", - "reference": "26dfec253c4cf3e51b541b52ddf7e42cb0908e94", + "url": "https://api.github.com/repos/symfony/polyfill-uuid/zipball/b23ff8245cc5c4479ea2be3d0132d2e6dd433993", + "reference": "b23ff8245cc5c4479ea2be3d0132d2e6dd433993", "shasum": "" }, "require": { @@ -8299,7 +8431,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/polyfill-uuid/tree/v1.36.0" + "source": "https://github.com/symfony/polyfill-uuid/tree/v1.43.0" }, "funding": [ { @@ -8319,20 +8451,20 @@ "type": "tidelift" } ], - "time": "2026-04-10T16:19:22+00:00" + "time": "2026-09-24T05:20:52+00:00" }, { "name": "symfony/process", - "version": "v7.4.8", + "version": "v7.4.21", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "60f19cd3badc8de688421e21e4305eba50f8089a" + "reference": "e5247f4a5e0797d232ad8e8e6803aeb341843c83" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/60f19cd3badc8de688421e21e4305eba50f8089a", - "reference": "60f19cd3badc8de688421e21e4305eba50f8089a", + "url": "https://api.github.com/repos/symfony/process/zipball/e5247f4a5e0797d232ad8e8e6803aeb341843c83", + "reference": "e5247f4a5e0797d232ad8e8e6803aeb341843c83", "shasum": "" }, "require": { @@ -8364,7 +8496,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.4.8" + "source": "https://github.com/symfony/process/tree/v7.4.21" }, "funding": [ { @@ -8384,20 +8516,20 @@ "type": "tidelift" } ], - "time": "2026-03-24T13:12:05+00:00" + "time": "2026-10-08T16:56:12+00:00" }, { "name": "symfony/routing", - "version": "v7.4.8", + "version": "v7.4.21", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "9608de9873ec86e754fb6c0a0fa7e5f1a960eb6b" + "reference": "7a344cf871532d081875bfdd18f3dff8dca36c5b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/9608de9873ec86e754fb6c0a0fa7e5f1a960eb6b", - "reference": "9608de9873ec86e754fb6c0a0fa7e5f1a960eb6b", + "url": "https://api.github.com/repos/symfony/routing/zipball/7a344cf871532d081875bfdd18f3dff8dca36c5b", + "reference": "7a344cf871532d081875bfdd18f3dff8dca36c5b", "shasum": "" }, "require": { @@ -8449,7 +8581,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v7.4.8" + "source": "https://github.com/symfony/routing/tree/v7.4.21" }, "funding": [ { @@ -8469,20 +8601,20 @@ "type": "tidelift" } ], - "time": "2026-03-24T13:12:05+00:00" + "time": "2026-10-11T18:40:59+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.6.1", + "version": "v3.7.3", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43" + "reference": "15e6a07ec2a2c75ceb1b21dd98105ee8456d2257" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43", - "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/15e6a07ec2a2c75ceb1b21dd98105ee8456d2257", + "reference": "15e6a07ec2a2c75ceb1b21dd98105ee8456d2257", "shasum": "" }, "require": { @@ -8500,7 +8632,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.6-dev" + "dev-main": "3.7-dev" } }, "autoload": { @@ -8536,7 +8668,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.6.1" + "source": "https://github.com/symfony/service-contracts/tree/v3.7.3" }, "funding": [ { @@ -8556,20 +8688,20 @@ "type": "tidelift" } ], - "time": "2025-07-15T11:30:57+00:00" + "time": "2026-07-27T15:39:01+00:00" }, { "name": "symfony/string", - "version": "v7.4.8", + "version": "v7.4.21", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "114ac57257d75df748eda23dd003878080b8e688" + "reference": "9bc35d074ad16a58c21cd52b18c5cacc4f4c3981" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/114ac57257d75df748eda23dd003878080b8e688", - "reference": "114ac57257d75df748eda23dd003878080b8e688", + "url": "https://api.github.com/repos/symfony/string/zipball/9bc35d074ad16a58c21cd52b18c5cacc4f4c3981", + "reference": "9bc35d074ad16a58c21cd52b18c5cacc4f4c3981", "shasum": "" }, "require": { @@ -8627,7 +8759,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.4.8" + "source": "https://github.com/symfony/string/tree/v7.4.21" }, "funding": [ { @@ -8647,20 +8779,20 @@ "type": "tidelift" } ], - "time": "2026-03-24T13:12:05+00:00" + "time": "2026-10-03T15:15:30+00:00" }, { "name": "symfony/translation", - "version": "v7.4.8", + "version": "v7.4.17", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "33600f8489485425bfcddd0d983391038d3422e7" + "reference": "2ee1e4a3b32a528a642babe041ff7c440b213b4b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/33600f8489485425bfcddd0d983391038d3422e7", - "reference": "33600f8489485425bfcddd0d983391038d3422e7", + "url": "https://api.github.com/repos/symfony/translation/zipball/2ee1e4a3b32a528a642babe041ff7c440b213b4b", + "reference": "2ee1e4a3b32a528a642babe041ff7c440b213b4b", "shasum": "" }, "require": { @@ -8727,7 +8859,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v7.4.8" + "source": "https://github.com/symfony/translation/tree/v7.4.17" }, "funding": [ { @@ -8747,20 +8879,20 @@ "type": "tidelift" } ], - "time": "2026-03-24T13:12:05+00:00" + "time": "2026-08-21T17:40:08+00:00" }, { "name": "symfony/translation-contracts", - "version": "v3.6.1", + "version": "v3.7.1", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "65a8bc82080447fae78373aa10f8d13b38338977" + "reference": "ccb206b98faccc511ebae8e5fad50f2dc0b30621" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/65a8bc82080447fae78373aa10f8d13b38338977", - "reference": "65a8bc82080447fae78373aa10f8d13b38338977", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/ccb206b98faccc511ebae8e5fad50f2dc0b30621", + "reference": "ccb206b98faccc511ebae8e5fad50f2dc0b30621", "shasum": "" }, "require": { @@ -8773,7 +8905,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.6-dev" + "dev-main": "3.7-dev" } }, "autoload": { @@ -8809,7 +8941,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.6.1" + "source": "https://github.com/symfony/translation-contracts/tree/v3.7.1" }, "funding": [ { @@ -8829,20 +8961,20 @@ "type": "tidelift" } ], - "time": "2025-07-15T13:41:35+00:00" + "time": "2026-06-05T06:23:12+00:00" }, { "name": "symfony/uid", - "version": "v7.4.8", + "version": "v7.4.21", "source": { "type": "git", "url": "https://github.com/symfony/uid.git", - "reference": "6883ebdf7bf6a12b37519dbc0df62b0222401b56" + "reference": "3e706a245b5343ea93be9cafe84525bfb54e60fc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/uid/zipball/6883ebdf7bf6a12b37519dbc0df62b0222401b56", - "reference": "6883ebdf7bf6a12b37519dbc0df62b0222401b56", + "url": "https://api.github.com/repos/symfony/uid/zipball/3e706a245b5343ea93be9cafe84525bfb54e60fc", + "reference": "3e706a245b5343ea93be9cafe84525bfb54e60fc", "shasum": "" }, "require": { @@ -8887,7 +9019,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/uid/tree/v7.4.8" + "source": "https://github.com/symfony/uid/tree/v7.4.21" }, "funding": [ { @@ -8907,20 +9039,20 @@ "type": "tidelift" } ], - "time": "2026-03-24T13:12:05+00:00" + "time": "2026-10-12T14:31:36+00:00" }, { "name": "symfony/var-dumper", - "version": "v7.4.8", + "version": "v7.4.21", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "9510c3966f749a1d1ff0059e1eabef6cc621e7fd" + "reference": "55d06b02f49eca9bff61828548988e6f8763e8a6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/9510c3966f749a1d1ff0059e1eabef6cc621e7fd", - "reference": "9510c3966f749a1d1ff0059e1eabef6cc621e7fd", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/55d06b02f49eca9bff61828548988e6f8763e8a6", + "reference": "55d06b02f49eca9bff61828548988e6f8763e8a6", "shasum": "" }, "require": { @@ -8936,7 +9068,7 @@ "symfony/http-kernel": "^6.4|^7.0|^8.0", "symfony/process": "^6.4|^7.0|^8.0", "symfony/uid": "^6.4|^7.0|^8.0", - "twig/twig": "^3.12" + "twig/twig": "^3.12|^4.0" }, "bin": [ "Resources/bin/var-dump-server" @@ -8974,7 +9106,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.4.8" + "source": "https://github.com/symfony/var-dumper/tree/v7.4.21" }, "funding": [ { @@ -8994,7 +9126,7 @@ "type": "tidelift" } ], - "time": "2026-03-30T13:44:50+00:00" + "time": "2026-10-13T05:48:33+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", @@ -9053,16 +9185,16 @@ }, { "name": "ueberdosis/tiptap-php", - "version": "2.1.0", + "version": "2.2.0", "source": { "type": "git", "url": "https://github.com/ueberdosis/tiptap-php.git", - "reference": "6ea321fa665080e1a72ac5f52dfab19f6a292e2d" + "reference": "5a2e8155c5b09c9ad4efd480550270a6924865b9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ueberdosis/tiptap-php/zipball/6ea321fa665080e1a72ac5f52dfab19f6a292e2d", - "reference": "6ea321fa665080e1a72ac5f52dfab19f6a292e2d", + "url": "https://api.github.com/repos/ueberdosis/tiptap-php/zipball/5a2e8155c5b09c9ad4efd480550270a6924865b9", + "reference": "5a2e8155c5b09c9ad4efd480550270a6924865b9", "shasum": "" }, "require": { @@ -9102,7 +9234,7 @@ ], "support": { "issues": "https://github.com/ueberdosis/tiptap-php/issues", - "source": "https://github.com/ueberdosis/tiptap-php/tree/2.1.0" + "source": "https://github.com/ueberdosis/tiptap-php/tree/2.2.0" }, "funding": [ { @@ -9118,27 +9250,27 @@ "type": "open_collective" } ], - "time": "2026-01-10T16:40:02+00:00" + "time": "2026-08-31T07:00:09+00:00" }, { "name": "vlucas/phpdotenv", - "version": "v5.6.3", + "version": "v5.7.0", "source": { "type": "git", - "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "955e7815d677a3eaa7075231212f2110983adecc" + "url": "https://github.com/phpdotenv/phpdotenv.git", + "reference": "301c07936b16d88628b126b01d082ba153cf4c40" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/955e7815d677a3eaa7075231212f2110983adecc", - "reference": "955e7815d677a3eaa7075231212f2110983adecc", + "url": "https://api.github.com/repos/phpdotenv/phpdotenv/zipball/301c07936b16d88628b126b01d082ba153cf4c40", + "reference": "301c07936b16d88628b126b01d082ba153cf4c40", "shasum": "" }, "require": { "ext-pcre": "*", - "graham-campbell/result-type": "^1.1.4", + "graham-campbell/result-type": "^1.2", "php": "^7.2.5 || ^8.0", - "phpoption/phpoption": "^1.9.5", + "phpoption/phpoption": "^1.10", "symfony/polyfill-ctype": "^1.26", "symfony/polyfill-mbstring": "^1.26", "symfony/polyfill-php80": "^1.26" @@ -9182,7 +9314,7 @@ "homepage": "https://github.com/vlucas" } ], - "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", + "description": "Loads environment variables from `.env` to `$_ENV` and `$_SERVER` automagically, and optionally to `getenv()`.", "keywords": [ "dotenv", "env", @@ -9190,7 +9322,7 @@ ], "support": { "issues": "https://github.com/vlucas/phpdotenv/issues", - "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.3" + "source": "https://github.com/vlucas/phpdotenv/tree/v5.7.0" }, "funding": [ { @@ -9202,20 +9334,20 @@ "type": "tidelift" } ], - "time": "2025-12-27T19:49:13+00:00" + "time": "2026-08-24T18:07:49+00:00" }, { "name": "voku/portable-ascii", - "version": "2.1.0", + "version": "2.1.1", "source": { "type": "git", "url": "https://github.com/voku/portable-ascii.git", - "reference": "d870a33f0f79d2b4579740b0620200221ee44aeb" + "reference": "8e1051fe39379367aecf014f41744ce7539a856f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/voku/portable-ascii/zipball/d870a33f0f79d2b4579740b0620200221ee44aeb", - "reference": "d870a33f0f79d2b4579740b0620200221ee44aeb", + "url": "https://api.github.com/repos/voku/portable-ascii/zipball/8e1051fe39379367aecf014f41744ce7539a856f", + "reference": "8e1051fe39379367aecf014f41744ce7539a856f", "shasum": "" }, "require": { @@ -9252,7 +9384,7 @@ ], "support": { "issues": "https://github.com/voku/portable-ascii/issues", - "source": "https://github.com/voku/portable-ascii/tree/2.1.0" + "source": "https://github.com/voku/portable-ascii/tree/2.1.1" }, "funding": [ { @@ -9276,7 +9408,7 @@ "type": "tidelift" } ], - "time": "2026-04-16T23:10:39+00:00" + "time": "2026-04-26T05:33:54+00:00" } ], "packages-dev": [ @@ -9345,16 +9477,16 @@ }, { "name": "filp/whoops", - "version": "2.18.4", + "version": "2.18.7", "source": { "type": "git", "url": "https://github.com/filp/whoops.git", - "reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d" + "reference": "50670ba239926c50f2073e868f6672f775cd57ec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/d2102955e48b9fd9ab24280a7ad12ed552752c4d", - "reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d", + "url": "https://api.github.com/repos/filp/whoops/zipball/50670ba239926c50f2073e868f6672f775cd57ec", + "reference": "50670ba239926c50f2073e868f6672f775cd57ec", "shasum": "" }, "require": { @@ -9363,8 +9495,8 @@ }, "require-dev": { "mockery/mockery": "^1.0", - "phpunit/phpunit": "^7.5.20 || ^8.5.8 || ^9.3.3", - "symfony/var-dumper": "^4.0 || ^5.0" + "phpunit/phpunit": "^7.5.20 || ^8.5.8 || ^9.3.3 || ^10.5.58", + "symfony/var-dumper": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0" }, "suggest": { "symfony/var-dumper": "Pretty print complex values better with var-dumper available", @@ -9404,7 +9536,7 @@ ], "support": { "issues": "https://github.com/filp/whoops/issues", - "source": "https://github.com/filp/whoops/tree/2.18.4" + "source": "https://github.com/filp/whoops/tree/2.18.7" }, "funding": [ { @@ -9412,23 +9544,25 @@ "type": "github" } ], - "time": "2025-08-08T12:00:00+00:00" + "time": "2026-10-18T13:17:38+00:00" }, { "name": "hamcrest/hamcrest-php", - "version": "v2.1.1", + "version": "v3.0.0", "source": { "type": "git", "url": "https://github.com/hamcrest/hamcrest-php.git", - "reference": "f8b1c0173b22fa6ec77a81fe63e5b01eba7e6487" + "reference": "b61cd040da1a4925bc90a51c074f5297e7c0fa52" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/f8b1c0173b22fa6ec77a81fe63e5b01eba7e6487", - "reference": "f8b1c0173b22fa6ec77a81fe63e5b01eba7e6487", + "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/b61cd040da1a4925bc90a51c074f5297e7c0fa52", + "reference": "b61cd040da1a4925bc90a51c074f5297e7c0fa52", "shasum": "" }, "require": { + "ext-ctype": "*", + "ext-dom": "*", "php": "^7.4|^8.0" }, "replace": { @@ -9437,13 +9571,15 @@ "kodova/hamcrest-php": "*" }, "require-dev": { + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-phpunit": "^2.0", "phpunit/php-file-iterator": "^1.4 || ^2.0 || ^3.0", "phpunit/phpunit": "^4.8.36 || ^5.7 || ^6.5 || ^7.0 || ^8.0 || ^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.1-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -9461,22 +9597,152 @@ ], "support": { "issues": "https://github.com/hamcrest/hamcrest-php/issues", - "source": "https://github.com/hamcrest/hamcrest-php/tree/v2.1.1" + "source": "https://github.com/hamcrest/hamcrest-php/tree/v3.0.0" + }, + "time": "2026-03-17T11:56:53+00:00" + }, + { + "name": "iamcal/sql-parser", + "version": "v0.7", + "source": { + "type": "git", + "url": "https://github.com/iamcal/SQLParser.git", + "reference": "610392f38de49a44dab08dc1659960a29874c4b8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/iamcal/SQLParser/zipball/610392f38de49a44dab08dc1659960a29874c4b8", + "reference": "610392f38de49a44dab08dc1659960a29874c4b8", + "shasum": "" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^1.0", + "phpunit/phpunit": "^5|^6|^7|^8|^9" + }, + "type": "library", + "autoload": { + "psr-4": { + "iamcal\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Cal Henderson", + "email": "cal@iamcal.com" + } + ], + "description": "MySQL schema parser", + "support": { + "issues": "https://github.com/iamcal/SQLParser/issues", + "source": "https://github.com/iamcal/SQLParser/tree/v0.7" + }, + "time": "2026-01-28T22:20:33+00:00" + }, + { + "name": "larastan/larastan", + "version": "v3.13.0", + "source": { + "type": "git", + "url": "https://github.com/larastan/larastan.git", + "reference": "24ee69a7705ffc7c2cd8a3c96a5f498a4c2de5e3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/larastan/larastan/zipball/24ee69a7705ffc7c2cd8a3c96a5f498a4c2de5e3", + "reference": "24ee69a7705ffc7c2cd8a3c96a5f498a4c2de5e3", + "shasum": "" + }, + "require": { + "iamcal/sql-parser": "^0.7.0", + "illuminate/console": "^11.44.2 || ^12.4.1 || ^13", + "illuminate/container": "^11.44.2 || ^12.4.1 || ^13", + "illuminate/contracts": "^11.44.2 || ^12.4.1 || ^13", + "illuminate/database": "^11.44.2 || ^12.4.1 || ^13", + "illuminate/http": "^11.44.2 || ^12.4.1 || ^13", + "illuminate/pipeline": "^11.44.2 || ^12.4.1 || ^13", + "illuminate/support": "^11.44.2 || ^12.4.1 || ^13", + "php": "^8.2", + "phpstan/phpstan": "^2.3.0" + }, + "require-dev": { + "doctrine/coding-standard": "^14", + "laravel/framework": "^11.44.2 || ^12.7.2 || ^13", + "mockery/mockery": "^1.6.12", + "nikic/php-parser": "^5.4", + "orchestra/canvas": "^v9.2.2 || ^10.0.1 || ^11", + "orchestra/testbench-core": "^9.12.0 || ^10.1 || ^11", + "phpstan/phpstan-deprecation-rules": "^2.0.1", + "phpunit/phpunit": "^10.5.35 || ^11.5.15 || ^12.5.8 || ^13.3.0" + }, + "suggest": { + "orchestra/testbench": "Using Larastan for analysing a package needs Testbench", + "phpmyadmin/sql-parser": "Install to enable Larastan's optional phpMyAdmin-based SQL parser automatically" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + }, + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Larastan\\Larastan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Can Vural", + "email": "can9119@gmail.com" + } + ], + "description": "Larastan - Discover bugs in your code without running it. A phpstan/phpstan extension for Laravel", + "keywords": [ + "PHPStan", + "code analyse", + "code analysis", + "larastan", + "laravel", + "package", + "php", + "static analysis" + ], + "support": { + "issues": "https://github.com/larastan/larastan/issues", + "source": "https://github.com/larastan/larastan/tree/v3.13.0" }, - "time": "2025-04-30T06:54:44+00:00" + "funding": [ + { + "url": "https://github.com/canvural", + "type": "github" + } + ], + "time": "2026-10-07T14:14:28+00:00" }, { "name": "laravel/pail", - "version": "v1.2.6", + "version": "v1.2.7", "source": { "type": "git", "url": "https://github.com/laravel/pail.git", - "reference": "aa71a01c309e7f66bc2ec4fb1a59291b82eb4abf" + "reference": "2f7d27dada8effc48b8c424445a69cca7007daaa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/pail/zipball/aa71a01c309e7f66bc2ec4fb1a59291b82eb4abf", - "reference": "aa71a01c309e7f66bc2ec4fb1a59291b82eb4abf", + "url": "https://api.github.com/repos/laravel/pail/zipball/2f7d27dada8effc48b8c424445a69cca7007daaa", + "reference": "2f7d27dada8effc48b8c424445a69cca7007daaa", "shasum": "" }, "require": { @@ -9543,20 +9809,20 @@ "issues": "https://github.com/laravel/pail/issues", "source": "https://github.com/laravel/pail" }, - "time": "2026-02-09T13:44:54+00:00" + "time": "2026-05-20T22:24:57+00:00" }, { "name": "laravel/pint", - "version": "v1.29.1", + "version": "v1.32.1", "source": { "type": "git", "url": "https://github.com/laravel/pint.git", - "reference": "0770e9b7fafd50d4586881d456d6eb41c9247a80" + "reference": "006bd7825eb01daf92959d060b89cd9514fe4253" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/pint/zipball/0770e9b7fafd50d4586881d456d6eb41c9247a80", - "reference": "0770e9b7fafd50d4586881d456d6eb41c9247a80", + "url": "https://api.github.com/repos/laravel/pint/zipball/006bd7825eb01daf92959d060b89cd9514fe4253", + "reference": "006bd7825eb01daf92959d060b89cd9514fe4253", "shasum": "" }, "require": { @@ -9564,17 +9830,19 @@ "ext-mbstring": "*", "ext-tokenizer": "*", "ext-xml": "*", - "php": "^8.2.0" + "php": "^8.3.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.95.1", - "illuminate/view": "^12.56.0", - "larastan/larastan": "^3.9.6", - "laravel-zero/framework": "^12.1.0", - "mockery/mockery": "^1.6.12", + "composer/semver": "^3.4.4", + "friendsofphp/php-cs-fixer": "^3.95.25", + "illuminate/view": "^13.31.0", + "larastan/larastan": "^3.11.0", + "laravel-zero/framework": "^13.0.0", + "laravel/agent-detector": "^2.0.2", + "laravel/prompts": "^0.3.24", + "mockery/mockery": "^1.6.15", "nunomaduro/termwind": "^2.4.0", - "pestphp/pest": "^3.8.6", - "shipfastlabs/agent-detector": "^1.1.3" + "pestphp/pest": "^4.7.8" }, "bin": [ "builds/pint" @@ -9611,20 +9879,20 @@ "issues": "https://github.com/laravel/pint/issues", "source": "https://github.com/laravel/pint" }, - "time": "2026-04-20T15:26:14+00:00" + "time": "2026-09-10T10:47:55+00:00" }, { "name": "laravel/sail", - "version": "v1.57.0", + "version": "v1.69.0", "source": { "type": "git", "url": "https://github.com/laravel/sail.git", - "reference": "fa8d057b6e9310380ccbc3a209ed7f927d54f648" + "reference": "3587ac9d68e8f2eaf36bd9fb003a4555861dca9d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/sail/zipball/fa8d057b6e9310380ccbc3a209ed7f927d54f648", - "reference": "fa8d057b6e9310380ccbc3a209ed7f927d54f648", + "url": "https://api.github.com/repos/laravel/sail/zipball/3587ac9d68e8f2eaf36bd9fb003a4555861dca9d", + "reference": "3587ac9d68e8f2eaf36bd9fb003a4555861dca9d", "shasum": "" }, "require": { @@ -9674,33 +9942,32 @@ "issues": "https://github.com/laravel/sail/issues", "source": "https://github.com/laravel/sail" }, - "time": "2026-04-14T13:32:04+00:00" + "time": "2026-10-08T20:06:52+00:00" }, { "name": "mockery/mockery", - "version": "1.6.12", + "version": "1.6.15", "source": { "type": "git", "url": "https://github.com/mockery/mockery.git", - "reference": "1f4efdd7d3beafe9807b08156dfcb176d18f1699" + "reference": "967a801bd188989a5669bd280f252d51c0fdc9ee" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mockery/mockery/zipball/1f4efdd7d3beafe9807b08156dfcb176d18f1699", - "reference": "1f4efdd7d3beafe9807b08156dfcb176d18f1699", + "url": "https://api.github.com/repos/mockery/mockery/zipball/967a801bd188989a5669bd280f252d51c0fdc9ee", + "reference": "967a801bd188989a5669bd280f252d51c0fdc9ee", "shasum": "" }, "require": { - "hamcrest/hamcrest-php": "^2.0.1", - "lib-pcre": ">=7.0", + "hamcrest/hamcrest-php": "^2.0 || ^3.0", "php": ">=7.3" }, "conflict": { "phpunit/phpunit": "<8.0" }, "require-dev": { - "phpunit/phpunit": "^8.5 || ^9.6.17", - "symplify/easy-coding-standard": "^12.1.14" + "phpunit/phpunit": "^9.6.36", + "symplify/easy-coding-standard": "^13.2.17" }, "type": "library", "autoload": { @@ -9757,24 +10024,24 @@ "security": "https://github.com/mockery/mockery/security/advisories", "source": "https://github.com/mockery/mockery" }, - "time": "2024-05-16T03:13:13+00:00" + "time": "2026-08-19T19:37:52+00:00" }, { "name": "myclabs/deep-copy", - "version": "1.13.4", + "version": "1.14.0", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a" + "reference": "8680aa248f8e07bc8fb43f56f0f5fc77a0c96aae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a", - "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/8680aa248f8e07bc8fb43f56f0f5fc77a0c96aae", + "reference": "8680aa248f8e07bc8fb43f56f0f5fc77a0c96aae", "shasum": "" }, "require": { - "php": "^7.1 || ^8.0" + "php": "^8.0" }, "conflict": { "doctrine/collections": "<1.6.8", @@ -9809,35 +10076,35 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4" + "source": "https://github.com/myclabs/DeepCopy/tree/1.14.0" }, "funding": [ { - "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", - "type": "tidelift" + "url": "https://github.com/mnapoli", + "type": "github" } ], - "time": "2025-08-01T08:46:24+00:00" + "time": "2026-08-11T10:17:44+00:00" }, { "name": "nunomaduro/collision", - "version": "v8.9.3", + "version": "v8.9.5", "source": { "type": "git", "url": "https://github.com/nunomaduro/collision.git", - "reference": "b0d8ab95b29c3189aeeb902d81215231df4c1b64" + "reference": "fb53eacd509a1d303858e2d20cfebf2d630254ec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/collision/zipball/b0d8ab95b29c3189aeeb902d81215231df4c1b64", - "reference": "b0d8ab95b29c3189aeeb902d81215231df4c1b64", + "url": "https://api.github.com/repos/nunomaduro/collision/zipball/fb53eacd509a1d303858e2d20cfebf2d630254ec", + "reference": "fb53eacd509a1d303858e2d20cfebf2d630254ec", "shasum": "" }, "require": { "filp/whoops": "^2.18.4", "nunomaduro/termwind": "^2.4.0", "php": "^8.2.0", - "symfony/console": "^7.4.8 || ^8.0.4" + "symfony/console": "^7.4.14 || ^8.1.1" }, "conflict": { "laravel/framework": "<11.48.0 || >=14.0.0", @@ -9845,12 +10112,12 @@ }, "require-dev": { "brianium/paratest": "^7.8.5", - "larastan/larastan": "^3.9.3", - "laravel/framework": "^11.48.0 || ^12.56.0 || ^13.2.0", - "laravel/pint": "^1.29.0", - "orchestra/testbench-core": "^9.12.0 || ^10.12.1 || ^11.0.0", - "pestphp/pest": "^3.8.5 || ^4.4.3 || ^5.0.0", - "sebastian/environment": "^7.2.1 || ^8.0.4 || ^9.0.0" + "larastan/larastan": "^3.10.0", + "laravel/framework": "^11.48.0 || ^12.56.0 || ^13.20.0", + "laravel/pint": "^1.29.3", + "orchestra/testbench-core": "^9.12.0 || ^10.12.1 || ^11.3.5", + "pestphp/pest": "^3.8.5 || ^4.7.5 || ^5.0.0", + "sebastian/environment": "^7.2.1 || ^8.1.2 || ^9.3.2" }, "type": "library", "extra": { @@ -9913,7 +10180,7 @@ "type": "patreon" } ], - "time": "2026-04-06T19:25:53+00:00" + "time": "2026-07-15T19:09:14+00:00" }, { "name": "phar-io/manifest", @@ -10033,6 +10300,70 @@ }, "time": "2022-02-21T01:04:05+00:00" }, + { + "name": "phpstan/phpstan", + "version": "2.3.1", + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/6155239b488e95d26d1ebd95c6b4bb294d7f09db", + "reference": "6155239b488e95d26d1ebd95c6b4bb294d7f09db", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ondřej Mirtes" + }, + { + "name": "Markus Staab" + }, + { + "name": "Vincent Langlet" + } + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2026-10-08T21:09:11+00:00" + }, { "name": "phpunit/php-code-coverage", "version": "11.0.12", @@ -10382,26 +10713,26 @@ }, { "name": "phpunit/phpunit", - "version": "11.5.55", + "version": "11.5.57", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "adc7262fccc12de2b30f12a8aa0b33775d814f00" + "reference": "36b75bf56a8535623f5b3e24b27ea1823759da1a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/adc7262fccc12de2b30f12a8aa0b33775d814f00", - "reference": "adc7262fccc12de2b30f12a8aa0b33775d814f00", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/36b75bf56a8535623f5b3e24b27ea1823759da1a", + "reference": "36b75bf56a8535623f5b3e24b27ea1823759da1a", "shasum": "" }, "require": { "ext-dom": "*", + "ext-filter": "*", "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", - "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.13.4", + "myclabs/deep-copy": "^1.14.0", "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=8.2", @@ -10464,31 +10795,15 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.55" + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.57" }, "funding": [ { - "url": "https://phpunit.de/sponsors.html", - "type": "custom" - }, - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - }, - { - "url": "https://liberapay.com/sebastianbergmann", - "type": "liberapay" - }, - { - "url": "https://thanks.dev/u/gh/sebastianbergmann", - "type": "thanks_dev" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", - "type": "tidelift" + "url": "https://phpunit.de/sponsoring.html", + "type": "other" } ], - "time": "2026-02-18T12:37:06+00:00" + "time": "2026-10-05T05:47:54+00:00" }, { "name": "sebastian/cli-parser", @@ -11530,16 +11845,16 @@ }, { "name": "symfony/yaml", - "version": "v7.4.8", + "version": "v7.4.21", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "c58fdf7b3d6c2995368264c49e4e8b05bcff2883" + "reference": "044907929c7999814378be22da34722c7a86bad4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/c58fdf7b3d6c2995368264c49e4e8b05bcff2883", - "reference": "c58fdf7b3d6c2995368264c49e4e8b05bcff2883", + "url": "https://api.github.com/repos/symfony/yaml/zipball/044907929c7999814378be22da34722c7a86bad4", + "reference": "044907929c7999814378be22da34722c7a86bad4", "shasum": "" }, "require": { @@ -11582,7 +11897,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v7.4.8" + "source": "https://github.com/symfony/yaml/tree/v7.4.21" }, "funding": [ { @@ -11602,7 +11917,7 @@ "type": "tidelift" } ], - "time": "2026-03-24T13:12:05+00:00" + "time": "2026-10-12T12:34:30+00:00" }, { "name": "theseer/tokenizer", @@ -11656,8 +11971,10 @@ } ], "aliases": [], - "minimum-stability": "dev", - "stability-flags": {}, + "minimum-stability": "stable", + "stability-flags": { + "programmernomad/laracorekit": 20 + }, "prefer-stable": true, "prefer-lowest": false, "platform": { diff --git a/config/auth.php b/config/auth.php index d56848e..4830175 100644 --- a/config/auth.php +++ b/config/auth.php @@ -1,5 +1,7 @@ [ 'users' => [ 'driver' => 'eloquent', - 'model' => env('AUTH_MODEL', Modules\User\Models\User::class), + 'model' => env('AUTH_MODEL', User::class), ], // 'users' => [ diff --git a/config/laracorekit.php b/config/laracorekit.php new file mode 100644 index 0000000..07a86cb --- /dev/null +++ b/config/laracorekit.php @@ -0,0 +1,10 @@ + true, + // This host demonstrates a custom panel; the package supplies its own in fresh apps. + 'panel' => ['enabled' => false, 'id' => 'admin', 'path' => 'admin'], + 'modules' => ['Auth' => true, 'User' => true, 'Settings' => true, 'Media' => true, 'Blog' => true], + 'registration' => true, + 'locales' => ['en', 'hi', 'ar'], +]; diff --git a/config/modules.php b/config/modules.php deleted file mode 100644 index d99187a..0000000 --- a/config/modules.php +++ /dev/null @@ -1,41 +0,0 @@ - [ - 'Core' => [ - 'enabled' => true, - 'namespace' => 'Modules\Core', - 'provider' => 'Modules\Core\CoreServiceProvider', - ], - 'Auth' => [ - 'enabled' => true, - 'namespace' => 'Modules\Auth', - 'provider' => 'Modules\Auth\AuthServiceProvider', - ], - 'User' => [ - 'enabled' => true, - 'namespace' => 'Modules\User', - 'provider' => 'Modules\User\UserServiceProvider', - ], - 'Blog' => [ - 'enabled' => true, - 'namespace' => 'Modules\Blog', - 'provider' => 'Modules\Blog\BlogServiceProvider', - ], - 'Settings' => [ - 'enabled' => true, - 'namespace' => 'Modules\Settings', - 'provider' => 'Modules\Settings\SettingsServiceProvider', - ], - 'Media' => [ - 'enabled' => true, - 'namespace' => 'Modules\Media', - 'provider' => 'Modules\Media\MediaServiceProvider', - ], - 'Docs' => [ - 'enabled' => true, - 'namespace' => 'Modules\Docs', - 'provider' => 'Modules\Docs\DocsServiceProvider', - ], - ], -]; diff --git a/config/permission.php b/config/permission.php index f39f6b5..85b8832 100644 --- a/config/permission.php +++ b/config/permission.php @@ -1,5 +1,9 @@ [ @@ -13,7 +17,7 @@ * `Spatie\Permission\Contracts\Permission` contract. */ - 'permission' => Spatie\Permission\Models\Permission::class, + 'permission' => Permission::class, /* * When using the "HasRoles" trait from this package, we need to know which @@ -24,7 +28,7 @@ * `Spatie\Permission\Contracts\Role` contract. */ - 'role' => Spatie\Permission\Models\Role::class, + 'role' => Role::class, ], @@ -136,7 +140,7 @@ /* * The class to use to resolve the permissions team id */ - 'team_resolver' => \Spatie\Permission\DefaultTeamResolver::class, + 'team_resolver' => DefaultTeamResolver::class, /* * Passport Client Credentials Grant @@ -183,7 +187,7 @@ * When permissions or roles are updated the cache is flushed automatically. */ - 'expiration_time' => \DateInterval::createFromDateString('24 hours'), + 'expiration_time' => DateInterval::createFromDateString('24 hours'), /* * The cache key used to store all permissions. diff --git a/config/site.php b/config/site.php new file mode 100644 index 0000000..9f31cae --- /dev/null +++ b/config/site.php @@ -0,0 +1,6 @@ + env('LARACOREKIT_COLLECT_STATS', false), +]; diff --git a/modules/Blog/database/seeders/BlogSeeder.php b/database/seeders/BlogSeeder.php similarity index 99% rename from modules/Blog/database/seeders/BlogSeeder.php rename to database/seeders/BlogSeeder.php index 7edd608..6af3f07 100644 --- a/modules/Blog/database/seeders/BlogSeeder.php +++ b/database/seeders/BlogSeeder.php @@ -1,10 +1,10 @@ first(); - if (!$admin) { + if (! $admin) { $admin = User::first(); } diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index ed9bd96..9cffe0c 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -2,22 +2,17 @@ namespace Database\Seeders; -use Modules\User\Models\User; -// use Illuminate\Database\Console\Seeds\WithoutModelEvents; use Illuminate\Database\Seeder; +use Modules\User\Database\Seeders\RolePermissionSeeder; class DatabaseSeeder extends Seeder { - /** - * Seed the application's database. - */ public function run(): void { - $this->call([ - \Modules\User\Database\Seeders\RolePermissionSeeder::class, - \Modules\User\Database\Seeders\UserSeeder::class, - \Modules\Settings\Database\Seeders\SettingSeeder::class, - \Modules\Blog\Database\Seeders\BlogSeeder::class, - ]); + // Safe defaults: roles only. Demo content requires an explicit DemoSeeder invocation. + $this->call(RolePermissionSeeder::class); + if (config('demo.enabled')) { + $this->call(DemoSeeder::class); + } } } diff --git a/database/seeders/DemoSeeder.php b/database/seeders/DemoSeeder.php new file mode 100644 index 0000000..fcda371 --- /dev/null +++ b/database/seeders/DemoSeeder.php @@ -0,0 +1,23 @@ +call([ + RolePermissionSeeder::class, + UserSeeder::class, + SettingSeeder::class, + BlogSeeder::class, + ]); + } +} diff --git a/modules/Settings/database/seeders/SettingSeeder.php b/database/seeders/SettingSeeder.php similarity index 98% rename from modules/Settings/database/seeders/SettingSeeder.php rename to database/seeders/SettingSeeder.php index 3824124..196dd77 100644 --- a/modules/Settings/database/seeders/SettingSeeder.php +++ b/database/seeders/SettingSeeder.php @@ -1,9 +1,9 @@ config('demo.credentials.admin.email', 'admin@laracorekit.com')], @@ -21,9 +25,9 @@ public function run(): void ); // Assign Admin role if it exists - if (class_exists(\Spatie\Permission\Models\Role::class)) { - $adminRole = \Spatie\Permission\Models\Role::where('name', 'Admin')->first(); - if ($adminRole && !$admin->hasRole('Admin')) { + if (class_exists(Role::class)) { + $adminRole = Role::where('name', 'Admin')->first(); + if ($adminRole && ! $admin->hasRole('Admin')) { $admin->assignRole('Admin'); } } @@ -33,14 +37,14 @@ public function run(): void ['email' => 'editor@laracorekit.com'], [ 'name' => 'Editor User', - 'password' => Hash::make('password'), + 'password' => Hash::make(config('demo.credentials.admin.password', 'Admin@123')), 'email_verified_at' => now(), ] ); - if (class_exists(\Spatie\Permission\Models\Role::class)) { - $editorRole = \Spatie\Permission\Models\Role::where('name', 'Editor')->first(); - if ($editorRole && !$editor->hasRole('Editor')) { + if (class_exists(Role::class)) { + $editorRole = Role::where('name', 'Editor')->first(); + if ($editorRole && ! $editor->hasRole('Editor')) { $editor->assignRole('Editor'); } } @@ -55,9 +59,9 @@ public function run(): void ] ); - if (class_exists(\Spatie\Permission\Models\Role::class)) { - $userRole = \Spatie\Permission\Models\Role::where('name', 'User')->first(); - if ($userRole && !$user->hasRole('User')) { + if (class_exists(Role::class)) { + $userRole = Role::where('name', 'User')->first(); + if ($userRole && ! $user->hasRole('User')) { $user->assignRole('User'); } } diff --git a/docs/SCREENSHOT_GUIDE.md b/docs/SCREENSHOT_GUIDE.md index 9a458d7..a1a20f0 100644 --- a/docs/SCREENSHOT_GUIDE.md +++ b/docs/SCREENSHOT_GUIDE.md @@ -1,309 +1,19 @@ -# Screenshot and Media Guide for LaraCoreKit +# Real application screenshots -This guide explains exactly which screenshots and GIF animations you need to create and where to place them. +Screenshots are generated from a disposable local SQLite application, never customer data. Files are stored in `docs/images/screenshots` for the README and `public/images/screenshots` for the website. They show the host application, including optional showcase features. -## Directory Structure +## Reproduce -Create this directory structure for all images: +Install the project dependencies and build assets. Configure an isolated test process with `APP_ENV=testing`, `DB_CONNECTION=sqlite`, `DB_DATABASE` pointing to a disposable file named `laracorekit-preview.sqlite`, `DEMO_MODE=false`, `CACHE_STORE=array`, `SESSION_DRIVER=file` and a localhost APP_URL. Create the empty file, run migrations, then `php tools/preview-seed.php`. The fixture refuses to run outside this setup. -``` -docs/ - images/ - screenshots/ - admin-dashboard.png - blog-editor.png - ui-showcase.png - rtl-support.png - create-blog-post.gif - language-switching.gif -``` +Start `php artisan serve --host=127.0.0.1 --port=8765 --no-reload` with the same environment. With Playwright available, run `node tools/browser-smoke.cjs`. The script uses Edge by default; set PLAYWRIGHT_CHANNEL for a supported installed browser. Set LARACOREKIT_PREVIEW_URL if using a different local server URL. -## Required Screenshots +The fixture's preview account is test-only and its password appears only in local test tooling. Do not deploy the fixture or reuse its credentials. No Packagist/GitHub account tokens are used in screenshots. -### 1. Admin Dashboard (admin-dashboard.png) +Captured pages include homepage, documentation, public blog, admin dashboard, blog management/editor, mobile navigation and UI showcase. Inspect images after capture; passing HTTP checks does not guarantee good layout. The README walkthrough GIF uses these actual views, with no placeholder UI. -**What to capture:** -- Navigate to: http://localhost:8000/admin or https://www.laracorekit.com/admin -- Login as admin user -- Capture the main dashboard view showing: - - Filament admin navigation sidebar - - Dashboard widgets (if any) - - Dark mode toggle visible - - User menu in top-right - - At least 2-3 resources visible in sidebar (Users, Blog Posts, etc.) +Set `LARACOREKIT_CRAWL_SHOWCASE=true` when running the browser script to additionally validate every linked showcase URL. Theme and Arabic RTL checks capture additional real views. -**Technical requirements:** -- Resolution: 1920x1080 or higher -- Format: PNG -- Show full browser window or crop to just the admin panel area -- Include visible data (users, blog posts, etc.) from seeded data -- Optional: Take both light and dark mode versions +## README animation -**Recommended tool:** -- Windows: Snipping Tool (Win + Shift + S) -- Browser: Full page screenshot extension -- Professional: ShareX, Greenshot - ---- - -### 2. Blog Editor (blog-editor.png) - -**What to capture:** -- Navigate to: http://localhost:8000/admin/blog-posts/create or edit an existing post -- Show the Filament form for creating/editing a blog post with: - - Rich text editor visible with content - - SEO fields section visible (slug, meta description) - - Language selector showing multilingual support - - Status selector (Draft/Published) - - Featured image upload area - - Save/Cancel buttons - -**Technical requirements:** -- Resolution: 1920x1080 or higher -- Format: PNG -- Capture the full form or most important sections -- Show actual content in the editor, not empty fields -- Make sure multilingual tabs/selector is visible - -**Example content to show:** -Use one of the seeded blog posts or create a new one titled "Getting Started with LaraCoreKit" - ---- - -### 3. UI Component Showcase (ui-showcase.png) - -**What to capture:** -- Navigate to: http://localhost:8000/ui-showcase or https://www.laracorekit.com/ui-showcase -- Capture a view showing: - - Multiple component categories visible - - At least 6-8 different components rendered - - Variety of components (buttons, forms, cards, tables, etc.) - - Clean, organized layout - - Navigation showing component categories - -**Technical requirements:** -- Resolution: 1920x1080 or higher -- Format: PNG -- Capture a scrolled view showing component variety -- Ensure text is readable -- Show colorful, visually appealing components - -**Alternative:** -Create a collage showing 4-6 individual component categories in a grid layout - ---- - -### 4. RTL Support (rtl-support.png) - -**What to capture:** -- Navigate to homepage or blog page -- Switch language to Arabic using language switcher -- Capture a page showing: - - Right-to-left text direction - - Navigation aligned to right - - Content properly flowing RTL - - Arabic text visible and readable - - UI elements mirrored correctly - -**Technical requirements:** -- Resolution: 1920x1080 or higher -- Format: PNG -- Show clear before/after or side-by-side comparison if possible -- Ensure Arabic text is properly displayed -- Show both navigation and content areas - -**Recommended approach:** -Take two screenshots (LTR English and RTL Arabic) and combine them side-by-side using image editor, OR take a single screenshot showing the RTL layout prominently - ---- - -## Required GIF Animations - -### 5. Creating a Blog Post (create-blog-post.gif) - -**What to record:** -A short workflow showing: -1. Navigate to admin panel -2. Click "Blog Posts" in sidebar -3. Click "Create" button -4. Fill in title field (type: "My First Blog Post") -5. Add some content to the rich text editor -6. Select "Published" status -7. Click "Save" button -8. Show success notification -9. See the new post in the list - -**Technical requirements:** -- Duration: 15-30 seconds -- Resolution: 1920x1080 or 1280x720 -- Format: GIF (optimized, max 5MB) or MP4 -- Frame rate: 10-15 fps for GIF, 30 fps for MP4 -- Show cursor movements clearly -- Smooth transitions - -**Recommended tools:** -- Windows: ScreenToGif (free, excellent) -- Cross-platform: OBS Studio + GIF converter -- Online: Recordit, Gifox -- Browser extension: Chrome Capture, Loom - -**Tips:** -- Record at normal speed, then speed up 1.5x -- Pause briefly on important steps -- Crop to focus on relevant area -- Optimize GIF size (use fewer colors, lower fps if needed) - ---- - -### 6. Language Switching (language-switching.gif) - -**What to record:** -A short workflow showing: -1. Start on homepage in English -2. Show language switcher in navigation -3. Click language dropdown -4. Select "Arabic" or "Hindi" -5. Show page content changing language -6. Show RTL layout shift (if switching to Arabic) -7. Navigate to one more page (like Blog or About) -8. Show consistent language across site - -**Technical requirements:** -- Duration: 10-20 seconds -- Resolution: 1920x1080 or 1280x720 -- Format: GIF (optimized, max 5MB) or MP4 -- Frame rate: 10-15 fps for GIF -- Show smooth transition -- Visible UI changes - -**Tips:** -- Show clear before/after state -- Highlight the language switcher -- Show multiple pages if possible (homepage + blog) -- For Arabic, emphasize the RTL layout change - ---- - -## File Placement - -After creating all screenshots and GIFs: - -1. Create the directory structure: -```bash -mkdir -p docs/images/screenshots -``` - -2. Place files with exact names: -``` -docs/images/screenshots/admin-dashboard.png -docs/images/screenshots/blog-editor.png -docs/images/screenshots/ui-showcase.png -docs/images/screenshots/rtl-support.png -docs/images/screenshots/create-blog-post.gif -docs/images/screenshots/language-switching.gif -``` - -3. Verify files: - - All files exist - - File names match exactly (lowercase, hyphens, correct extensions) - - PNG files are not too large (compress if over 1MB each) - - GIF files are optimized (max 5MB each, preferably under 3MB) - -## Image Optimization - -### PNG Optimization -Use one of these tools to compress PNG files without losing quality: -- **TinyPNG** - https://tinypng.com (online, drag and drop) -- **ImageOptim** - https://imageoptim.com (Mac) -- **PNGGauntlet** - https://pnggauntlet.com (Windows) -- **squoosh.app** - https://squoosh.app (online, advanced) - -Target: Keep each PNG under 500KB if possible, max 1MB - -### GIF Optimization -Use these tools to reduce GIF file size: -- **ScreenToGif** - Has built-in optimizer (Windows) -- **ezgif.com** - https://ezgif.com/optimize (online) -- **gifsicle** - Command line tool for advanced optimization -- Convert to MP4 if GIF is too large, then use video tag in docs - -Target: Keep each GIF under 3MB, ideally under 2MB - -**GIF optimization tips:** -- Reduce colors to 64-128 instead of 256 -- Lower frame rate to 10-12 fps -- Resize to 1280x720 or 1024x768 if needed -- Crop to focus area only -- Remove unnecessary frames - -## Alternative: Video Format - -If GIF files are too large even after optimization, you can use MP4 format instead: - -1. Record as MP4 using OBS Studio or similar -2. Place in same directory with .mp4 extension -3. Update README.md to use HTML5 video tag: - -```html - -``` - -MP4 files are usually 10-20x smaller than GIFs for the same quality. - -## Checklist - -Before committing, verify: - -- [ ] All 6 files created and placed in correct directory -- [ ] File names match exactly (lowercase, hyphens, correct extensions) -- [ ] PNG files are clear and readable (1920x1080 or higher) -- [ ] PNG files are optimized (under 1MB each) -- [ ] GIF files show smooth animations (15-30 seconds) -- [ ] GIF files are optimized (under 3MB each) -- [ ] All screenshots show seeded demo data, not empty screens -- [ ] RTL screenshot clearly shows right-to-left layout -- [ ] Images look professional (no personal info, clean browser, etc.) -- [ ] Test that images display correctly in README.md - -## After Adding Images - -Once all images are added: - -1. Commit the images: -```bash -git add docs/images/screenshots/ -git commit -m "Add product screenshots and demo GIFs" -``` - -2. Push to GitHub: -```bash -git push origin main -``` - -3. Verify images display on GitHub README -4. Update website homepage with same images -5. Consider adding to docs pages as well - -## Additional Screenshots (Optional) - -Consider adding these for documentation and marketing: - -- **Login page** - show auth UI (login-page.png) -- **User profile** - show profile editing (user-profile.png) -- **Settings page** - show admin settings (settings-page.png) -- **Media library** - show file management (media-library.png) -- **Mobile view** - show responsive design (mobile-view.png) -- **Dark mode** - show dark mode UI (dark-mode.png) - -Place these in docs/images/additional/ directory. - ---- - -**Questions or need help?** - -If you encounter issues capturing screenshots or creating GIFs, you can: -1. Use the live demo site at https://www.laracorekit.com -2. Seed your local database with demo data: `php artisan db:seed` -3. Ask for help: https://github.com/ProgrammerNomad/LaraCoreKit/discussions +After browser capture succeeds, run `python tools/build-demo-gif.py` (requires Pillow). It creates `docs/images/screenshots/walkthrough.gif`, a 960x720 four-view, 12-second loop covering the public homepage, blog, admin and documentation. Static screenshots remain available. Inspect each frame and keep the GIF below 1 MB; regenerate it when branding or primary screens change. diff --git a/docs/admin/custom-pages.md b/docs/admin/custom-pages.md index d8946f4..9cb2c6d 100644 --- a/docs/admin/custom-pages.md +++ b/docs/admin/custom-pages.md @@ -1,119 +1,7 @@ -# Custom Admin Pages +# Custom admin pages ---- -**Supported Stack:** Laravel 13 / Filament 5 / Livewire 4 / Tailwind 4 -**Last Updated:** April 22, 2026 -**Source Files:** [Settings Page example](../../modules/Settings/views/filament/pages/settings.blade.php) ---- +The package Settings page lives under `packages/core/modules/Settings/src/Filament/Pages`. Its view namespace is `settings`. The demo Dashboard lives under `app/Filament/Pages` and is host-only. -Filament Custom Pages let you build completely custom screens in the admin panel - dashboards, reports, settings forms, and more - without being tied to a specific Eloquent model. +Use Filament 5's page APIs for your own application pages and register them in a custom panel. Enforce permissions again inside public Livewire mutation methods; navigation visibility alone is insufficient. Settings provides an example by checking edit permission in `save()`. ---- - -## Creating a Custom Page - -```bash -php artisan make:filament-page DashboardStats -``` - -Move to your module: -``` -modules/Core/src/Filament/Pages/DashboardStats.php -``` - ---- - -## Custom Dashboard Page - -```php -stats = [ - 'users' => User::count(), - 'posts' => Post::where('status', 'published')->count(), - 'drafts' => Post::where('status', 'draft')->count(), - 'new_today' => User::whereDate('created_at', today())->count(), - ]; - } -} -``` - ---- - -## Custom Page View - -```blade -{{-- modules/Core/views/filament/pages/dashboard-stats.blade.php --}} - - -
- @foreach($stats as $key => $value) -
-

{{ str_replace('_', ' ', $key) }}

-

{{ number_format($value) }}

-
- @endforeach -
-
-``` - ---- - -## Settings Page (Form-based) - -```php -use Filament\Forms\Components\TextInput; -use Filament\Forms\Concerns\InteractsWithForms; -use Filament\Pages\Page; - -class SiteSettings extends Page -{ - use InteractsWithForms; - - protected static ?string $navigationIcon = 'heroicon-o-cog'; - protected static string $view = 'core::filament.pages.site-settings'; - - public string $site_name = ''; - - public function mount(): void - { - $this->site_name = Setting::get('site_name', ''); - } - - public function save(): void - { - Setting::set('site_name', $this->site_name); - $this->notify('success', 'Settings saved!'); - } - - protected function getFormSchema(): array - { - return [ - TextInput::make('site_name')->required(), - ]; - } -} -``` - ---- - -## Next Steps - -**[Forms & Tables →](forms-tables)** +See [installation](/docs/installation) and [package architecture](/docs/core/architecture). diff --git a/docs/admin/filament-overview.md b/docs/admin/filament-overview.md index 8462ece..2cfb317 100644 --- a/docs/admin/filament-overview.md +++ b/docs/admin/filament-overview.md @@ -1,109 +1,11 @@ -# Admin Panel Overview (Filament) +# Filament administration ---- -**Supported Stack:** Laravel 13 / Filament 5 / Livewire 4 / Tailwind 4 -**Last Updated:** April 22, 2026 -**Source Files:** [AdminPanelProvider](../../app/Providers/Filament/AdminPanelProvider.php) ---- +The reusable package provides its own panel at `/admin`, with public frontend features available alongside it. Create an administrator with `php artisan laracorekit:admin`; a generic Filament user without the required role cannot access the panel. -LaraCoreKit includes a **Filament 5** admin panel - a beautiful, powerful TALL-stack admin interface built for Laravel. +Registered resources include users, roles, permissions and blogs, plus the settings page. There is no separate media-library resource. Use `php artisan route:list --path=admin` for exact resource URLs. ---- +The package panel uses Filament's default theme. The website host disables that panel and registers a custom panel provider, theme, dashboard and optional demo widget. Demo banners are not part of the package. -## Access the Admin Panel +Set `panel.enabled=false` to build your own panel and register the resources you need. Preserve authorization methods when customizing resources. -``` -URL: /admin -Login: your Filament admin credentials -``` - -Create your first admin user: - -```bash -php artisan filament:user -``` - ---- - -## What's Included - -| Section | Route | Description | -|---------|-------|-------------| -| Dashboard | `/admin` | Overview stats and activity | -| Users | `/admin/users` | Manage registered users | -| Roles | `/admin/roles` | Roles & permissions | -| Permissions | `/admin/permissions` | Fine-grained permission management | -| Posts | `/admin/posts` | Blog content management | -| Media | `/admin/media` | File and image library | -| Settings | `/admin/settings` | Site configuration form | - ---- - -## Admin Panel Architecture - -``` -app/Providers/Filament/AdminPanelProvider.php ← Panel config -modules/*/src/Filament/ -├── Resources/ ← CRUD resources (one per model) -├── Pages/ ← Custom admin pages -└── Widgets/ ← Dashboard widgets -``` - ---- - -## AdminPanelProvider - -The admin panel is configured in `app/Providers/Filament/AdminPanelProvider.php`: - -```php -use Filament\Panel; -use Filament\PanelProvider; - -class AdminPanelProvider extends PanelProvider -{ - public function panel(Panel $panel): Panel - { - return $panel - ->default() - ->id('admin') - ->path('admin') - ->login() - ->colors(['primary' => Color::Violet]) - ->discoverResources(in: app_path('Filament/Resources'), for: 'App\\Filament\\Resources') - ->discoverPages(in: app_path('Filament/Pages'), for: 'App\\Filament\\Pages'); - } -} -``` - ---- - -## Navigation Groups - -Resources are grouped in the sidebar using `$navigationGroup`: - -```php -class PostResource extends Resource -{ - protected static ?string $navigationGroup = 'Blog'; - protected static ?string $navigationIcon = 'heroicon-o-document-text'; - protected static ?int $navigationSort = 1; -} -``` - ---- - -## Authorization - -Users accessing `/admin` must pass the `canAccessFilament()` check. By default, any user with `is_admin = true` or the `admin` role can access it. - ---- - -## Dark Mode - -Filament's dark mode is enabled by default and follows system preference. - ---- - -## Next Steps - -**[Resources →](resources)** +See [installation](/docs/installation) and [package architecture](/docs/core/architecture). diff --git a/docs/admin/forms-tables.md b/docs/admin/forms-tables.md index 007dcab..67638ad 100644 --- a/docs/admin/forms-tables.md +++ b/docs/admin/forms-tables.md @@ -1,147 +1,9 @@ -# Forms & Tables in Filament +# Forms and tables ---- -**Supported Stack:** Laravel 13 / Filament 5 / Livewire 4 / Tailwind 4 -**Last Updated:** April 22, 2026 -**Source Files:** [Filament Forms Docs](https://filamentphp.com/docs/5.x/forms) | [Example Resource](../../modules/User/src/Filament/Resources/UserResource.php) ---- +The package uses Filament 5 schema and table APIs. Forms are organized under resource `Schemas` directories; table definitions live under `Tables`. -Filament provides rich declarative builders for forms and tables that power all admin resources in LaraCoreKit. +User forms contain identity fields, hashed password handling and role assignments. Blog forms contain translations, status, author and metadata fields. Table definitions provide search, filters and record actions. ---- +Validate permissions on the server for role assignment, publication and destructive actions. Use Laravel's JSON query syntax for database portability rather than concatenating SQL for a specific database. Consult the official Filament 5 documentation when extending components. -## Form Fields Reference - -```php -use Filament\Forms\Components\*; - -$form->schema([ - // Text inputs - TextInput::make('title')->required()->maxLength(255), - TextInput::make('slug')->unique(ignoreRecord: true), - TextInput::make('email')->email()->required(), - TextInput::make('password')->password()->minLength(8), - - // Select & multi-select - Select::make('status') - ->options(['draft' => 'Draft', 'published' => 'Published']) - ->default('draft'), - - Select::make('tags') - ->multiple() - ->relationship('tags', 'name'), - - // Rich text - RichEditor::make('content')->columnSpanFull(), - MarkdownEditor::make('notes'), - - // Dates - DatePicker::make('published_at'), - DateTimePicker::make('scheduled_at'), - - // Toggle / Checkbox - Toggle::make('is_featured')->inline(false), - Checkbox::make('agree_terms')->required(), - - // File uploads - FileUpload::make('attachment'), - FileUpload::make('avatar')->image()->avatar()->circular(), - - // Layout helpers - Grid::make(2)->schema([...]), - Section::make('SEO')->schema([...]), - Tabs::make()->tabs([ - Tabs\Tab::make('Content')->schema([...]), - Tabs\Tab::make('SEO')->schema([...]), - ]), -]); -``` - ---- - -## Table Columns Reference - -```php -use Filament\Tables\Columns\*; - -$table->columns([ - TextColumn::make('title')->searchable()->sortable()->limit(50), - TextColumn::make('author.name')->label('Author'), - BadgeColumn::make('status') - ->colors(['success' => 'published', 'warning' => 'draft', 'danger' => 'archived']), - ImageColumn::make('avatar')->circular(), - IconColumn::make('is_featured')->boolean(), - TextColumn::make('created_at')->dateTime()->since()->sortable(), - TextColumn::make('published_at')->date(), -]); -``` - ---- - -## Table Filters - -```php -use Filament\Tables\Filters\*; - -$table->filters([ - SelectFilter::make('status')->options(['draft' => 'Draft', 'published' => 'Published']), - SelectFilter::make('locale')->options(['en' => 'English', 'hi' => 'Hindi', 'ar' => 'Arabic']), - - Filter::make('featured') - ->label('Featured only') - ->query(fn ($query) => $query->where('is_featured', true)), - - Filter::make('published_this_month') - ->query(fn ($query) => $query->whereMonth('published_at', now()->month)), -]); -``` - ---- - -## Table Actions - -```php -use Filament\Tables\Actions\*; - -$table - ->actions([ - EditAction::make(), - DeleteAction::make(), - Action::make('publish') - ->label('Publish') - ->icon('heroicon-o-check') - ->visible(fn ($record) => $record->status === 'draft') - ->action(fn ($record) => $record->update(['status' => 'published'])), - ]) - ->bulkActions([ - DeleteBulkAction::make(), - BulkAction::make('publish_selected') - ->label('Publish Selected') - ->action(fn ($records) => $records->each->update(['status' => 'published'])), - ]); -``` - ---- - -## Validation - -All form fields support Laravel validation rules: - -```php -TextInput::make('email') - ->email() - ->required() - ->unique('users', 'email', ignoreRecord: true) - ->maxLength(255), - -TextInput::make('price') - ->numeric() - ->minValue(0) - ->maxValue(99999), -``` - ---- - -## Next Steps - -**[Livewire Basics →](../frontend/livewire)** +See [installation](/docs/installation) and [package architecture](/docs/core/architecture). diff --git a/docs/admin/resources.md b/docs/admin/resources.md index e30df03..59658b6 100644 --- a/docs/admin/resources.md +++ b/docs/admin/resources.md @@ -1,155 +1,9 @@ -# Filament Resources +# Admin resources ---- -**Supported Stack:** Laravel 13 / Filament 5 / Livewire 4 / Tailwind 4 -**Last Updated:** April 22, 2026 -**Source Files:** [PostResource example](../../modules/Blog/src/Filament/Resources/PostResource.php) ---- +Resources live under the package module's `src/Filament/Resources` directory. They compose schema classes, table classes and list/create/view/edit pages. User resources manage User, Role and Permission models; BlogResource manages Blog. -Filament Resources are the primary way to manage Eloquent models in the LaraCoreKit admin panel. LaraCoreKit places each module's resources inside the module directory. +Each resource checks permissions for record access and mutations. Bulk delete/restore/force-delete paths must remain consistent with record permissions. Test direct record URLs, not only resource navigation. ---- +Add application-specific resources to your application's own panel. Editing files in vendor will be lost during updates. -## Resource Location - -``` -modules/{Module}/src/Filament/Resources/ -└── {Model}Resource.php -``` - -Example: -``` -modules/Blog/src/Filament/Resources/PostResource.php -``` - ---- - -## Creating a Resource - -```bash -php artisan make:filament-resource Post --model="Modules\Blog\Models\Post" -``` - -Move the generated file to your module and update the namespace. - ---- - -## Full Resource Example - -```php -schema([ - Forms\Components\Grid::make(2)->schema([ - Forms\Components\TextInput::make('title') - ->required() - ->maxLength(255) - ->live(onBlur: true) - ->afterStateUpdated(fn ($state, $set) => - $set('slug', \Str::slug($state)) - ), - - Forms\Components\TextInput::make('slug') - ->required() - ->unique(ignoreRecord: true), - ]), - - Forms\Components\Select::make('status') - ->options(['draft' => 'Draft', 'published' => 'Published']) - ->default('draft') - ->required(), - - Forms\Components\Select::make('locale') - ->options(['en' => 'English', 'hi' => 'Hindi', 'ar' => 'Arabic']) - ->default('en') - ->required(), - - Forms\Components\Textarea::make('excerpt') - ->rows(2) - ->maxLength(500), - - Forms\Components\RichEditor::make('content') - ->columnSpanFull() - ->required(), - - Forms\Components\SpatieMediaLibraryFileUpload::make('cover') - ->collection('cover') - ->image() - ->imageResizeMode('cover'), - - Forms\Components\DateTimePicker::make('published_at'), - ]); - } - - public static function table(Table $table): Table - { - return $table - ->columns([ - Tables\Columns\TextColumn::make('title')->searchable()->sortable(), - Tables\Columns\BadgeColumn::make('status') - ->colors(['warning' => 'draft', 'success' => 'published']), - Tables\Columns\TextColumn::make('locale')->label('Lang'), - Tables\Columns\TextColumn::make('published_at')->since()->sortable(), - ]) - ->filters([ - Tables\Filters\SelectFilter::make('status') - ->options(['draft' => 'Draft', 'published' => 'Published']), - Tables\Filters\SelectFilter::make('locale') - ->options(['en' => 'English', 'hi' => 'Hindi', 'ar' => 'Arabic']), - ]) - ->actions([ - Tables\Actions\EditAction::make(), - Tables\Actions\DeleteAction::make(), - ]) - ->bulkActions([ - Tables\Actions\DeleteBulkAction::make(), - ]); - } - - public static function getPages(): array - { - return [ - 'index' => Pages\ListPosts::route('/'), - 'create' => Pages\CreatePost::route('/create'), - 'edit' => Pages\EditPost::route('/{record}/edit'), - ]; - } -} -``` - ---- - -## Registering Resources - -Filament auto-discovers resources. If you need manual registration, add to `AdminPanelProvider`: - -```php -->resources([ - PostResource::class, -]) -``` - ---- - -## Next Steps - -**[Custom Pages →](custom-pages)** +See [installation](/docs/installation) and [package architecture](/docs/core/architecture). diff --git a/docs/advanced/caching.md b/docs/advanced/caching.md index ea93acb..1279ac5 100644 --- a/docs/advanced/caching.md +++ b/docs/advanced/caching.md @@ -1,171 +1,9 @@ -# Caching +# Caching -**Estimated time:** 8 minutes -**Difficulty:** Intermediate +Choose a cache store appropriate to deployment. Settings-page reads cache individual keys and saves invalidate those keys. Blog category caching includes the locale in its key. ---- +Authentication throttles use Laravel's cache-backed rate limiter. Use shared storage across servers so limits cannot be bypassed by switching application instances. Avoid broad cache flushes in ordinary content actions. -Effective caching can make your application 10-100x faster. LaraCoreKit supports multiple cache drivers out of the box. +Deploy using reviewed configuration/route/view caching and clear stale caches when changing providers or package settings. Application-specific content caching and invalidation need their own tests. ---- - -## Cache Drivers - -| Driver | Config value | Best For | -|--------|-------------|----------| -| File | `file` | Development / small apps | -| Redis | `redis` | Production (recommended) | -| Memcached | `memcached` | High-traffic alternative | -| DynamoDB | `dynamodb` | AWS serverless deployments | -| Array | `array` | Testing only | - -Set in `.env`: - -```env -CACHE_DRIVER=redis -``` - ---- - -## Basic Cache Operations - -```php -use Illuminate\Support\Facades\Cache; - -// Store a value (seconds TTL) -Cache::put('key', $value, 3600); - -// Store with Carbon TTL -Cache::put('key', $value, now()->addHours(6)); - -// Store forever -Cache::forever('key', $value); - -// Retrieve -$value = Cache::get('key'); -$value = Cache::get('key', 'default_value'); - -// Check existence -Cache::has('key'); - -// Remove -Cache::forget('key'); - -// Clear all cache -Cache::flush(); -``` - ---- - -## The Remember Pattern (Most Common) - -```php -// Only queries DB if cache misses -$posts = Cache::remember('home_posts', 3600, function () { - return Post::published()->latest()->take(6)->get(); -}); - -// Remember forever -$settings = Cache::rememberForever('app_settings', function () { - return Setting::all()->pluck('value', 'key'); -}); -``` - ---- - -## Cache in Livewire Components - -```php -use Illuminate\Support\Facades\Cache; -use Livewire\Attributes\Computed; - -class BlogList extends Component -{ - #[Computed] - public function posts() - { - return Cache::remember('blog_list_' . $this->page, 300, function () { - return Post::published() - ->locale(app()->getLocale()) - ->latest() - ->paginate(12); - }); - } -} -``` - ---- - -## Cache Tags - -Group related cache items for easy invalidation: - -```php -// Store with tags -Cache::tags(['posts', 'homepage'])->put('featured_posts', $posts, 3600); - -// Retrieve with tags -$posts = Cache::tags(['posts'])->get('featured_posts'); - -// Invalidate all 'posts' tagged caches at once -Cache::tags(['posts'])->flush(); -``` - -> **Note:** Cache tags require Redis or Memcached driver. - ---- - -## Model Cache Events - -Auto-clear cache when model changes: - -```php -class Post extends Model -{ - protected static function booted(): void - { - static::saved(function () { - Cache::tags(['posts'])->flush(); - }); - - static::deleted(function () { - Cache::tags(['posts'])->flush(); - }); - } -} -``` - ---- - -## HTTP Response Caching - -Cache entire HTTP responses: - -```php -// In a controller -return response() - ->view('blog.index', compact('posts')) - ->header('Cache-Control', 'public, max-age=3600') - ->header('ETag', md5($posts->toJson())); -``` - ---- - -## Artisan Cache Commands - -```bash -# Clear application cache -php artisan cache:clear - -# Clear config cache -php artisan config:clear - -# Clear all compiled/cached files -php artisan optimize:clear -``` - ---- - -## Next Steps - -**[Queues →](queues)** +See [installation](/docs/installation) and [package architecture](/docs/core/architecture). diff --git a/docs/advanced/queues.md b/docs/advanced/queues.md index 6059c5f..9ee2b2a 100644 --- a/docs/advanced/queues.md +++ b/docs/advanced/queues.md @@ -1,195 +1,7 @@ -# Queues +# Queues -**Estimated time:** 8 minutes -**Difficulty:** Intermediate +Queue configuration remains standard Laravel configuration. Select a backend, run workers under a process supervisor and monitor failed jobs. Media conversions or notifications that you add may require workers. ---- +The demo reset scheduler belongs only to the disposable demo host. Installing the reusable package does not configure a worker service or deployment scheduler automatically. Test retry and failure behavior for your application's jobs. -Queues offload time-consuming tasks (sending emails, image processing, API calls) out of the web request, keeping your app fast and responsive. - ---- - -## Configuration - -Set the queue connection in `.env`: - -```env -QUEUE_CONNECTION=redis # Production (recommended) -QUEUE_CONNECTION=database # Simple fallback -QUEUE_CONNECTION=sync # Development (no workers needed) -``` - -For database driver, create the jobs table: - -```bash -php artisan queue:table -php artisan migrate -``` - ---- - -## Creating a Job - -```bash -php artisan make:job SendWelcomeEmail -``` - -```php -onQueue('emails'); - } - - public function handle(): void - { - Mail::to($this->user->email)->send(new WelcomeMail($this->user)); - } - - public function failed(\Throwable $exception): void - { - // Log failure, notify admin, etc. - \Log::error('Welcome email failed', [ - 'user_id' => $this->user->id, - 'error' => $exception->getMessage(), - ]); - } -} -``` - ---- - -## Dispatching Jobs - -```php -// Dispatch immediately -SendWelcomeEmail::dispatch($user); - -// Dispatch after delay -SendWelcomeEmail::dispatch($user)->delay(now()->addMinutes(5)); - -// Dispatch to a specific queue -SendWelcomeEmail::dispatch($user)->onQueue('emails'); - -// Dispatch on specific connection -SendWelcomeEmail::dispatch($user)->onConnection('redis'); - -// Dispatch synchronously (ignore queue) -SendWelcomeEmail::dispatchSync($user); -``` - ---- - -## Running Workers - -```bash -# Basic worker -php artisan queue:work - -# Worker with specifics -php artisan queue:work redis --queue=emails,default --sleep=3 --tries=3 - -# Process only one job then stop -php artisan queue:work --once - -# Graceful shutdown after current job -php artisan queue:restart -``` - ---- - -## Queues in Livewire - -Dispatch jobs from Livewire components: - -```php -class RegisterForm extends Component -{ - public function register(): void - { - $user = User::create($this->validated()); - - // Dispatch to queue - don't block the response - SendWelcomeEmail::dispatch($user); - SendVerificationEmail::dispatch($user); - - $this->redirect(route('home')); - } -} -``` - ---- - -## Chaining Jobs - -```php -use Illuminate\Support\Facades\Bus; - -Bus::chain([ - new ProcessPayment($order), - new SendReceiptEmail($order), - new UpdateInventory($order), -])->dispatch(); -``` - ---- - -## Failed Jobs - -```bash -# View failed jobs -php artisan queue:failed - -# Retry a single failed job -php artisan queue:retry {id} - -# Retry all failed jobs -php artisan queue:retry all - -# Delete all failed jobs -php artisan queue:flush -``` - ---- - -## Supervisor Configuration - -For production, run workers with Supervisor: - -```ini -[program:laracorekit-worker] -process_name=%(program_name)s_%(process_num)02d -command=php /var/www/html/artisan queue:work redis --sleep=3 --tries=3 --max-time=3600 -autostart=true -autorestart=true -user=www-data -numprocs=2 -redirect_stderr=true -stdout_logfile=/var/log/laracorekit-worker.log -stopwaitsecs=3600 -``` - ---- - -## Next Steps - -**[Search →](search)** +See [installation](/docs/installation) and [package architecture](/docs/core/architecture). diff --git a/docs/advanced/search.md b/docs/advanced/search.md index 7440411..7d901d1 100644 --- a/docs/advanced/search.md +++ b/docs/advanced/search.md @@ -1,205 +1,7 @@ -# Search +# Search -**Estimated time:** 10 minutes -**Difficulty:** Intermediate +The public Blog list includes database-backed text search over localized title/content fields. This is not a bundled external search service. ---- +Scout, Meilisearch and other search integrations are optional application work. Add indexing, authorization-aware visibility, lifecycle updates and relevant tests before exposing a search service. Do not index drafts or future publications into a public index. -Add powerful full-text search to LaraCoreKit using database queries, Laravel Scout, or Algolia. - ---- - -## Option 1: Simple Database Search - -Good for small-to-medium datasets (<10,000 records). - -```php -// In a Livewire component -public string $query = ''; - -public function render() -{ - $posts = Post::published() - ->when($this->query, function ($q) { - $q->where(function ($q) { - $q->where('title', 'LIKE', "%{$this->query}%") - ->orWhere('content', 'LIKE', "%{$this->query}%") - ->orWhere('excerpt', 'LIKE', "%{$this->query}%"); - }); - }) - ->latest() - ->paginate(12); - - return view('blog::livewire.blog-list', compact('posts')); -} -``` - -Add database indexes for better performance: - -```php -Schema::table('blog_posts', function (Blueprint $table) { - $table->fullText(['title', 'content', 'excerpt']); -}); -``` - -Then use MATCH AGAINST: - -```php -$posts = Post::whereRaw( - "MATCH(title, content, excerpt) AGAINST(? IN BOOLEAN MODE)", - [$this->query . '*'] -)->get(); -``` - ---- - -## Option 2: Laravel Scout - -The standard approach for scalable search. - -### Install Scout - -```bash -composer require laravel/scout -php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider" -``` - -### Add Searchable Trait - -```php -namespace Modules\Blog\Models; - -use Illuminate\Database\Eloquent\Model; -use Laravel\Scout\Searchable; - -class Post extends Model -{ - use Searchable; - - public function toSearchableArray(): array - { - return [ - 'id' => $this->id, - 'title' => $this->title, - 'content' => $this->content, - 'excerpt' => $this->excerpt, - 'locale' => $this->locale, - 'status' => $this->status, - ]; - } - - public function shouldBeSearchable(): bool - { - return $this->status === 'published'; - } -} -``` - -### Search - -```php -// Simple search -$results = Post::search('laravel tutorial')->get(); - -// With filters -$results = Post::search('laravel')->where('locale', 'en')->paginate(15); -``` - -### Import Existing Records - -```bash -php artisan scout:import "Modules\Blog\Models\Post" -``` - ---- - -## Option 3: Algolia (Best for Production) - -**Algolia DocSearch** is free for open-source projects. - -### Step 1: Install Algolia Driver - -```bash -composer require algolia/algoliasearch-client-php - -# Set Scout driver to algolia -SCOUT_DRIVER=algolia -ALGOLIA_APP_ID=your-app-id -ALGOLIA_SECRET=your-secret-key -``` - -### Step 2: Add Algolia to Your Front-end - -```bash -npm install algoliasearch instantsearch.js -``` - -```javascript -import algoliasearch from 'algoliasearch/lite'; -import instantsearch from 'instantsearch.js'; - -const searchClient = algoliasearch('YOUR_APP_ID', 'YOUR_SEARCH_KEY'); - -const search = instantsearch({ - indexName: 'blog_posts', - searchClient, -}); - -search.start(); -``` - ---- - -## Search UI Component (Livewire) - -```php -class GlobalSearch extends Component -{ - public string $query = ''; - public array $results = []; - - public function updatedQuery(): void - { - if (strlen($this->query) < 2) { - $this->results = []; - return; - } - - $this->results = Post::search($this->query) - ->take(10) - ->get() - ->map(fn ($post) => [ - 'id' => $post->id, - 'title' => $post->title, - 'url' => route('blog.show', $post->slug), - 'type' => 'Post', - ]) - ->toArray(); - } - - public function render() - { - return view('core::livewire.global-search'); - } -} -``` - ---- - -## Search Route - -```php -// In your module's routes/web.php -Route::get('/search', function (Request $request) { - $query = $request->get('q', ''); - $results = $query ? Post::search($query)->paginate(20) : collect(); - - return view('search.results', compact('results', 'query')); -})->name('search'); -``` - ---- - -## Next Steps - -**[FAQ →](../faq)** +See [installation](/docs/installation) and [package architecture](/docs/core/architecture). diff --git a/docs/advanced/testing.md b/docs/advanced/testing.md index 6f67b43..02309f8 100644 --- a/docs/advanced/testing.md +++ b/docs/advanced/testing.md @@ -1,249 +1,25 @@ -# Testing +# Testing -**Estimated time:** 12 minutes -**Difficulty:** Intermediate +Run `composer test` for the PHPUnit suite. Database-mutating tests use SQLite in memory, enforced in phpunit.xml, and demo mode is disabled. Never point regression tests at a real application database. ---- +Coverage includes safe default seeding, demo-seeder guards, login throttling, registration controls, admin access, publication visibility, content sanitization and documentation endpoints. These tests reduce regressions; they are not a complete independent security audit. -LaraCoreKit is configured with **PHPUnit** and supports **Pest PHP** for an elegant, expressive testing experience. +Run `python tools/consumer-smoke.py` to install only the package into an isolated temporary Laravel application, verify public/admin login routes and assets, and test cached routes/configuration. It leaves the temporary consumer for inspection. Use `python tools/consumer-smoke.py --source packagist` to validate the published `^0.1` release without a path or VCS override. CI runs both source and published-package lanes. ---- +Run `composer pint-test`, `composer phpstan`, dependency audits and both frontend builds as well. CI separates locked dependencies from compatible updates. The browser smoke script requires Playwright and the disposable preview fixture; see the screenshot guide. -## Running Tests +See [installation](/docs/installation) and [package architecture](/docs/core/architecture). -```bash -# Run all tests -php artisan test - -# Run with verbose output -php artisan test --verbose - -# Run with coverage -php artisan test --coverage - -# Run a specific test file -php artisan test tests/Feature/Blog/PostTest.php - -# Run tests matching a filter -php artisan test --filter=BlogTest - -# Run in parallel (much faster) -php artisan test --parallel -``` - ---- - -## Test Structure - -``` -tests/ -├── Feature/ ← HTTP/integration tests -│ ├── Auth/ -│ │ ├── LoginTest.php -│ │ └── RegisterTest.php -│ ├── Blog/ -│ │ ├── PostTest.php -│ │ └── BlogListTest.php -│ └── Api/ -│ └── ApiTokenTest.php -├── Unit/ ← Unit tests (no HTTP) -│ ├── Blog/ -│ │ └── PostModelTest.php -│ └── Newsletter/ -│ └── SubscriberTest.php -└── TestCase.php ← Base test class -``` - ---- - -## Feature Test Example - -```php -count(5)->published()->create(); - Post::factory()->count(3)->draft()->create(); - - $response = $this->get(route('blog.index')); - - $response - ->assertOk() - ->assertViewHas('posts') - ->assertViewHas('posts', fn ($posts) => $posts->count() === 5); - } - - /** @test */ - public function it_shows_a_published_post(): void - { - $post = Post::factory()->published()->create([ - 'title' => 'Test Post Title', - ]); - - $this->get(route('blog.show', $post->slug)) - ->assertOk() - ->assertSee('Test Post Title'); - } - - /** @test */ - public function it_returns_404_for_draft_post(): void - { - $post = Post::factory()->draft()->create(); - - $this->get(route('blog.show', $post->slug)) - ->assertNotFound(); - } -} -``` - ---- - -## Unit Test Example - -```php -create(['title' => 'Hello World']); +The default `phpunit.xml` enforces an in-memory SQLite database. For MySQL, create a **disposable** database named `laracorekit_test`, set `DB_PORT` and `DB_PASSWORD` for that server and run: - $this->assertEquals('hello-world', $post->slug); - } - - /** @test */ - public function published_scope_filters_correctly(): void - { - Post::factory()->published()->create(); - Post::factory()->draft()->create(); - - $this->assertEquals(1, Post::published()->count()); - } -} -``` - ---- - -## Livewire Component Tests - -```php -set('email', 'test@laracorekit.com') - ->call('subscribe') - ->assertHasNoErrors() - ->assertSet('success', true); - - $this->assertDatabaseHas('newsletter_subscribers', [ - 'email' => 'test@laracorekit.com', - ]); -}); - -it('fails with invalid email', function () { - Livewire::test(Subscribe::class) - ->set('email', 'not-an-email') - ->call('subscribe') - ->assertHasErrors(['email']); -}); -``` - ---- - -## Authentication Helpers - -```php -// Authenticate as a user in tests -$user = User::factory()->create(); -$this->actingAs($user); - -// Authenticate with a specific role -$admin = User::factory()->create(); -$admin->assignRole('admin'); -$this->actingAs($admin); - -// Test unauthenticated access -$this->get(route('dashboard'))->assertRedirect('/login'); -``` - ---- - -## Model Factories - -Create factories for each module: - -```php -// modules/Blog/database/factories/PostFactory.php -namespace Modules\Blog\Database\Factories; - -use Illuminate\Database\Eloquent\Factories\Factory; -use Modules\Blog\Models\Post; - -class PostFactory extends Factory -{ - protected $model = Post::class; - - public function definition(): array - { - return [ - 'title' => $this->faker->sentence(), - 'slug' => $this->faker->slug(), - 'content' => $this->faker->paragraphs(5, asText: true), - 'excerpt' => $this->faker->paragraph(), - 'status' => 'draft', - 'locale' => 'en', - 'published_at' => null, - ]; - } - - public function published(): static - { - return $this->state([ - 'status' => 'published', - 'published_at' => now()->subDays(rand(1, 30)), - ]); - } - - public function draft(): static - { - return $this->state(['status' => 'draft']); - } -} +```bash +php vendor/bin/phpunit --configuration phpunit.mysql.xml ``` ---- - -## Next Steps - -**[Caching →](caching)** +That configuration forces MySQL on localhost with the dedicated test database. Tests migrate/reset its tables. Never use application data for this database. CI supplies an isolated MySQL 8 service. +The suite now includes reset-token validation/consumption, neutral reset responses, reset throttling, executable/oversized image rejection and module dependency checks. Run `node tools/header-smoke.cjs` against the disposable preview to check header alignment, closed-menu height, open/close behavior and page overflow at seven widths from 320px to 1440px. Set `LARACOREKIT_PREVIEW_URL` to use another preview server. diff --git a/docs/api/authentication.md b/docs/api/authentication.md index 17002f1..5fa38c6 100644 --- a/docs/api/authentication.md +++ b/docs/api/authentication.md @@ -1,126 +1,5 @@ -# API Authentication Flow +# Optional API integration -**Estimated time:** 6 minutes -**Difficulty:** Intermediate - ---- - -This page explains the full token lifecycle for API authentication in LaraCoreKit. - ---- - -## Token Lifecycle - -``` -┌──────────────────────────────────────────────────────────┐ -│ 1. Client POSTs credentials to POST /api/tokens │ -│ 2. Server validates email + password │ -│ 3. Server creates and returns plaintext token │ -│ 4. Client stores token securely │ -│ 5. Client sends token in Authorization header │ -│ 6. Server validates token on each protected request │ -│ 7. Client calls DELETE /api/tokens/current to logout │ -└──────────────────────────────────────────────────────────┘ -``` - ---- - -## Required Headers - -```bash -# For authenticated requests -Authorization: Bearer {your-token} -Accept: application/json -Content-Type: application/json -``` - ---- - -## Step-by-Step Example - -### 1. Login and Get Token - -```javascript -const response = await fetch('/api/tokens', { - method: 'POST', - headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, - body: JSON.stringify({ - email: 'user@laracorekit.com', - password: 'secret', - device_name: 'My Mobile App', - }), -}); - -const { token, user } = await response.json(); - -// Store token securely -localStorage.setItem('token', token); -``` - -### 2. Make Authenticated Requests - -```javascript -const token = localStorage.getItem('token'); - -const response = await fetch('/api/user', { - headers: { - 'Authorization': `Bearer ${token}`, - 'Accept': 'application/json', - }, -}); - -const { data } = await response.json(); -``` - -### 3. Logout - -```javascript -await fetch('/api/tokens/current', { - method: 'DELETE', - headers: { 'Authorization': `Bearer ${token}` }, -}); - -localStorage.removeItem('token'); -``` - ---- - -## Token Abilities (Scoped Tokens) - -Issue tokens with restricted abilities for extra security: - -```php -// Only allow reading posts -$token = $user->createToken('mobile-reader', ['posts:read']); -``` - -In your API controller: - -```php -public function store(Request $request) -{ - if (!$request->user()->tokenCan('posts:write')) { - abort(403, 'Token does not have write access.'); - } - // ... -} -``` - ---- - -## Security Best Practices - -| Practice | Why | -|----------|-----| -| Use HTTPS | Tokens in plaintext over HTTP are interceptable | -| Short expiry | Set `expiration` in `config/sanctum.php` | -| Revoke on logout | Always call DELETE token on logout | -| Scope tokens | Use abilities to limit what each token can do | -| Never log tokens | Keep out of logs, error reports, analytics | - ---- - -## Next Steps - -**[Create a Module →](../modules/create-module)** +The current package implements session-based public authentication and Filament administration. It does **not** ship Sanctum tokens or a public application API. Earlier references to bundled API authentication were inaccurate. +If your application needs an API, install and configure Laravel Sanctum using the [official Laravel documentation](https://laravel.com/docs/13.x/sanctum), adapt your user model, and define your own routes, token abilities, validation and rate limits. Treat this as application development and add authorization tests before exposing endpoints. diff --git a/docs/api/endpoints.md b/docs/api/endpoints.md index f211a7e..5fa38c6 100644 --- a/docs/api/endpoints.md +++ b/docs/api/endpoints.md @@ -1,187 +1,5 @@ -# API Endpoints - -**Estimated time:** 8 minutes -**Difficulty:** Intermediate - ---- - -LaraCoreKit provides a set of REST API endpoints for accessing data programmatically from mobile apps, SPAs, or third-party integrations. - ---- - -## Base URL - -``` -https://www.laracorekit.com/api -``` - -All API responses use JSON format. Always include: - -``` -Accept: application/json -``` - ---- - -## Authentication Endpoints - -| Method | Endpoint | Auth | Description | -|--------|----------|------|-------------| -| `POST` | `/api/tokens` | No | Issue an API token | -| `DELETE` | `/api/tokens/current` | | Revoke current token | -| `DELETE` | `/api/tokens` | | Revoke all tokens | - ---- - -## User Endpoints - -| Method | Endpoint | Auth | Description | -|--------|----------|------|-------------| -| `GET` | `/api/user` | | Get the authenticated user | -| `PUT` | `/api/user` | | Update user profile | -| `PUT` | `/api/user/password` | | Change password | - ---- - -## Blog Endpoints - -| Method | Endpoint | Auth | Description | -|--------|----------|------|-------------| -| `GET` | `/api/posts` | No | List published posts | -| `GET` | `/api/posts/{slug}` | No | Get a single post | - ---- - -## Settings Endpoint - -| Method | Endpoint | Auth | Description | -|--------|----------|------|-------------| -| `GET` | `/api/settings` | No | Get public site settings | - ---- - -## Pagination - -List endpoints return paginated responses: - -```json -{ - "data": [ - { "id": 1, "title": "First Post", "slug": "first-post" } - ], - "meta": { - "current_page": 1, - "last_page": 5, - "per_page": 15, - "total": 72 - }, - "links": { - "first": "https://www.laracorekit.com/api/posts?page=1", - "next": "https://www.laracorekit.com/api/posts?page=2", - "prev": null, - "last": "https://www.laracorekit.com/api/posts?page=5" - } -} -``` - -Pass `?page=2&per_page=20` to paginate. - ---- - -## Query Parameters - -For list endpoints: - -``` -GET /api/posts?locale=en&status=published&page=1&per_page=12 -``` - -| Parameter | Type | Default | Description | -|-----------|------|---------|-------------| -| `locale` | string | `en` | Filter by language | -| `page` | integer | `1` | Page number | -| `per_page` | integer | `15` | Items per page (max 100) | - ---- - -## Error Responses - -```json -{ - "message": "Unauthenticated.", - "errors": {} -} -``` - -| Status Code | Meaning | -|-------------|---------| -| `200` | Success | -| `201` | Created | -| `400` | Bad request | -| `401` | Unauthenticated | -| `403` | Unauthorized | -| `404` | Not found | -| `422` | Validation failed | -| `500` | Server error | - -### Validation Error - -```json -{ - "message": "The email field is required.", - "errors": { - "email": ["The email field is required."] - } -} -``` - ---- - -## Adding a New API Endpoint - -1. Create a controller in your module: - -```php -namespace Modules\Blog\Http\Controllers\Api; - -use Illuminate\Http\JsonResponse; -use Illuminate\Routing\Controller; -use Modules\Blog\Models\Post; - -class PostApiController extends Controller -{ - public function index(): JsonResponse - { - $posts = Post::published() - ->locale(request('locale', 'en')) - ->latest() - ->paginate(request('per_page', 15)); - - return response()->json($posts); - } - - public function show(string $slug): JsonResponse - { - $post = Post::published()->where('slug', $slug)->firstOrFail(); - - return response()->json(['data' => $post]); - } -} -``` - -2. Register routes in `modules/Blog/routes/api.php`: - -```php -Route::prefix('api')->group(function () { - Route::get('/posts', [PostApiController::class, 'index']); - Route::get('/posts/{slug}', [PostApiController::class, 'show']); -}); -``` - ---- - -## Next Steps - -**[API Auth Flow →](authentication)** +# Optional API integration +The current package implements session-based public authentication and Filament administration. It does **not** ship Sanctum tokens or a public application API. Earlier references to bundled API authentication were inaccurate. +If your application needs an API, install and configure Laravel Sanctum using the [official Laravel documentation](https://laravel.com/docs/13.x/sanctum), adapt your user model, and define your own routes, token abilities, validation and rate limits. Treat this as application development and add authorization tests before exposing endpoints. diff --git a/docs/api/sanctum.md b/docs/api/sanctum.md index 55a99b5..5fa38c6 100644 --- a/docs/api/sanctum.md +++ b/docs/api/sanctum.md @@ -1,176 +1,5 @@ -# API Authentication (Sanctum) - -**Estimated time:** 8 minutes -**Difficulty:** Intermediate - ---- - -LaraCoreKit uses **Laravel Sanctum** for API authentication - lightweight, stateless token authentication perfect for mobile apps, SPAs, and third-party integrations. - ---- - -## How Sanctum Works - -``` -1. Client sends email + password to POST /api/tokens -2. Server validates and returns a plaintext token -3. Client stores the token (localStorage, secure cookie, etc.) -4. Client includes the token in the Authorization header -5. Server validates on protected routes -``` - ---- - -## Configuration - -Sanctum is pre-configured. Verify in `.env`: - -```env -SANCTUM_STATEFUL_DOMAINS=localhost,127.0.0.1,laracorekit.com -``` - -And in `config/auth.php`, the API guard should use Sanctum: - -```php -'guards' => [ - 'api' => [ - 'driver' => 'sanctum', - 'provider' => 'users', - ], -], -``` - ---- - -## Issue a Token - -```php -// routes/api.php -Route::post('/tokens', function (Request $request) { - $request->validate([ - 'email' => 'required|email', - 'password' => 'required', - 'device_name' => 'required|string', - ]); - - $user = User::where('email', $request->email)->first(); - - if (!$user || !Hash::check($request->password, $user->password)) { - return response()->json([ - 'message' => 'The provided credentials are incorrect.' - ], 401); - } - - return response()->json([ - 'token' => $user->createToken($request->device_name)->plainTextToken, - 'user' => $user->only('id', 'name', 'email'), - ]); -}); -``` - -**Example request:** - -```bash -curl -X POST https://www.laracorekit.com/api/tokens \ - -H "Content-Type: application/json" \ - -d '{"email":"user@laracorekit.com","password":"secret","device_name":"My App"}' -``` - -**Example response:** - -```json -{ - "token": "1|abc123def456...", - "user": { - "id": 1, - "name": "John Doe", - "email": "john@laracorekit.com" - } -} -``` - ---- - -## Authenticating Requests - -```bash -# Include token in Authorization header -curl -H "Authorization: Bearer 1|abc123def456..." \ - -H "Accept: application/json" \ - https://www.laracorekit.com/api/user -``` - -In JavaScript: - -```javascript -const response = await fetch('/api/user', { - headers: { - 'Authorization': `Bearer ${token}`, - 'Accept': 'application/json', - } -}); -``` - ---- - -## Protecting Routes - -```php -// routes/api.php -Route::middleware('auth:sanctum')->group(function () { - Route::get('/user', fn (Request $r) => $r->user()); - Route::get('/posts', [PostApiController::class, 'index']); - Route::post('/posts', [PostApiController::class, 'store']); -}); -``` - ---- - -## Token Abilities - -Issue tokens with restricted abilities: - -```php -$token = $user->createToken('mobile-app', ['posts:read', 'posts:write']); -``` - -Check abilities in controllers: - -```php -if ($request->user()->tokenCan('posts:write')) { - // Allow write operation -} -``` - ---- - -## Revoking Tokens - -```php -// Revoke current token (logout) -$request->user()->currentAccessToken()->delete(); - -// Revoke all tokens (logout from all devices) -$request->user()->tokens()->delete(); - -// Revoke a specific token -$user->tokens()->where('name', 'mobile-app')->delete(); -``` - ---- - -## Token Expiry - -Set token expiry in `config/sanctum.php`: - -```php -'expiration' => 525960, // Minutes (1 year), or null for no expiry -``` - ---- - -## Next Steps - -**[API Endpoints →](endpoints)** +# Optional API integration +The current package implements session-based public authentication and Filament administration. It does **not** ship Sanctum tokens or a public application API. Earlier references to bundled API authentication were inaccurate. +If your application needs an API, install and configure Laravel Sanctum using the [official Laravel documentation](https://laravel.com/docs/13.x/sanctum), adapt your user model, and define your own routes, token abilities, validation and rate limits. Treat this as application development and add authorization tests before exposing endpoints. diff --git a/docs/comparisons/laracorekit-vs-larament.md b/docs/comparisons/laracorekit-vs-larament.md index eaa65ee..819a062 100644 --- a/docs/comparisons/laracorekit-vs-larament.md +++ b/docs/comparisons/laracorekit-vs-larament.md @@ -1,309 +1,7 @@ -# LaraCoreKit vs Larament +# Choosing a Laravel foundation -A detailed comparison between LaraCoreKit and Larament to help you choose the right Laravel starter kit for your project. +LaraCoreKit combines a public frontend and Filament administration in a reusable package. It is useful when your application needs those features together and you accept the documented Laravel/PHP constraints. -## Quick Comparison +Compare alternatives using their current official documentation and your own clean-install evaluation. This repository does not maintain a verified feature-by-feature comparison of third-party projects. Earlier comparative claims should not be used as evidence of security, performance or completeness. -| Feature | LaraCoreKit | Larament | -|---------|-------------|----------| -| **Laravel Version** | 13.x | 13.x | -| **Admin Panel** | Filament 5 | Filament 5 | -| **Frontend Framework** | Livewire 4 | Livewire 4 | -| **Styling** | Tailwind 4 | Tailwind 4 | -| **PHP Version** | 8.3+ | 8.3+ | -| **License** | MIT (Free) | MIT (Free) | -| **Architecture** | Modular | Monolithic | -| **Multilingual** | Yes (EN/HI/AR built-in) | No (DIY) | -| **RTL Support** | Yes (built-in) | No | -| **Blog Module** | Yes (included) | No | -| **Media Library** | Yes (Spatie Media) | No | -| **Settings Module** | Yes (included) | No | -| **UI Components** | 175+ components | Minimal | -| **Role/Permissions** | Yes (Spatie Permission) | Yes (Spatie Permission) | -| **API Auth** | Sanctum | Sanctum | -| **GitHub** | [LaraCoreKit](https://github.com/ProgrammerNomad/LaraCoreKit) (new) | [Larament](https://github.com/lara-zeus/larament) (established) | -| **Active Development** | Yes | Yes | -| **Documentation** | Comprehensive | Comprehensive | -| **CI/CD** | GitHub Actions | GitHub Actions | -| **Code Quality** | Pint + PHPStan | Pint + PHPStan + Larastan | - -## Detailed Comparison - -### Architecture - -**LaraCoreKit:** -- **Modular architecture** - Each feature (Blog, Settings, Media, User) is in its own module -- Modules can be enabled/disabled independently -- Each module has its own routes, migrations, tests, views, and Filament resources -- Easy to remove features you don't need -- Predictable structure across all modules -- Designed for feature-rich applications - -**Larament:** -- **Monolithic architecture** - All code in standard Laravel app structure -- Simpler, more familiar to Laravel developers -- Less overhead for small applications -- Easier to understand for beginners -- Better for projects that don't need modularity -- Designed as a clean foundation to build upon - -**Winner:** LaraCoreKit if you want modular architecture, Larament if you prefer simplicity - ---- - -### Out-of-the-Box Features - -**LaraCoreKit Ships With:** -- Blog module with multilingual support -- Media library with image management -- Settings module for site configuration -- User management with profiles -- Role and permission system (Spatie Permission) -- Multilingual content (English, Hindi, Arabic) -- RTL support for Arabic -- 175+ UI components -- Admin panel (Filament 5) -- Frontend (Livewire 4) - -**Larament Ships With:** -- User authentication -- Role and permission system (Spatie Permission) -- Admin panel (Filament 5) -- Basic UI components -- Quality assurance tools (Pint, PHPStan, Larastan) -- CI/CD workflows - -**Winner:** LaraCoreKit for feature breadth, Larament for focused simplicity - ---- - -### Multilingual & Internationalization - -**LaraCoreKit:** -- Built-in support for English, Hindi, and Arabic -- JSON translation files included for all modules -- Language switcher in navigation -- Locale middleware and routing -- RTL layout support for Arabic -- Easy to add more languages -- Translatable database fields for content - -**Larament:** -- No built-in multilingual support -- Laravel's standard localization available -- You need to implement language switching yourself -- No RTL support out of the box - -**Winner:** LaraCoreKit (significant advantage if you need multilingual) - ---- - -### Content Management - -**LaraCoreKit:** -- Full blog module with rich text editor -- Draft/Published/Archived statuses -- SEO fields (slug, meta description, OG tags) -- Featured images -- Multilingual blog posts -- Category and tag support -- Filament resource for admin -- Public Livewire frontend - -**Larament:** -- No content management features included -- You build your own blog/CMS if needed -- Clean slate approach - -**Winner:** LaraCoreKit if you need a blog/CMS, Larament if you're building something else - ---- - -### Media Handling - -**LaraCoreKit:** -- Spatie Media Library integrated -- Image upload and management -- Automatic thumbnail generation -- S3 and local storage support -- Media organization -- Image optimization - -**Larament:** -- No media library included -- Standard Laravel file upload available -- Add your own media solution - -**Winner:** LaraCoreKit (media library included) - ---- - -### Quality Assurance - -**LaraCoreKit:** -- Laravel Pint (code formatting) -- PHPStan (static analysis) -- PHPUnit (testing) -- GitHub Actions (Tests, Code Quality, Build) -- Composer scripts: `composer review` - -**Larament:** -- Laravel Pint (code formatting) -- PHPStan (static analysis) -- Larastan (Laravel-specific static analysis) -- PHPUnit (testing) -- GitHub Actions workflows -- Composer scripts for all quality checks -- More mature quality tooling - -**Winner:** Larament (more established QA tooling) - ---- - -### Developer Experience - -**LaraCoreKit:** -- Comprehensive documentation site -- Module development guide -- Contributing guidelines -- Security policy -- Code is well-commented -- Predictable structure across modules -- One command quality check: `composer review` - -**Larament:** -- Excellent documentation -- Established project with proven track record -- Active community -- Production-tested -- Clean, idiomatic Laravel code -- Established best practices - -**Winner:** Larament (more mature, battle-tested) - ---- - -### Community & Support - -**LaraCoreKit:** -- New project (launched 2026) -- Growing community -- Active development -- Documentation site -- GitHub issues and discussions - -**Larament:** -- Established project -- Large community -- Multiple forks and contributors -- Many releases -- Proven in production -- Active community -- Regular updates - -**Winner:** Larament (more established community) - ---- - -### UI Components - -**LaraCoreKit:** -- 175+ production-ready Tailwind components -- 12 component categories -- UI showcase page -- E-commerce components -- Chart components -- Auth components -- Media components - -**Larament:** -- Minimal UI components -- Focus on Filament admin UI -- Frontend is your responsibility -- Add your own component library - -**Winner:** LaraCoreKit (extensive component library) - ---- - -## Use Cases - -### Choose LaraCoreKit if you need: -- Multilingual website (especially with RTL languages) -- Blog or content management system -- Feature-rich application with modules -- Extensive UI component library -- Media library out of the box -- Settings management -- Modular architecture -- Quick start with many features - -### Choose Larament if you want: -- Clean, minimal starting point -- Standard Laravel structure -- Proven, battle-tested foundation -- Strong code quality tooling -- Simpler application -- Build features from scratch your way -- Established community -- Production-ready quality assurance - -## Migration Between Them - -### From Larament to LaraCoreKit: -Difficult. Different architectures (monolithic vs modular). Would require significant refactoring. - -### From LaraCoreKit to Larament: -Easier. You can extract Laravel/Filament/Livewire code and remove modules. But why would you? - -### From either to vanilla Laravel: -Both are Laravel applications, so you can always refactor toward vanilla Laravel if needed. - -## Pricing - -Both are **100% free and open-source** under MIT license. - -## Our Honest Recommendation - -**Choose Larament if:** -- You want a proven, battle-tested foundation -- You prefer building features yourself -- You value simplicity and standard Laravel structure -- You don't need multilingual or blog features -- You want an established community -- Code quality is your top priority - -**Choose LaraCoreKit if:** -- You need multilingual support (especially RTL languages) -- You're building a blog, CMS, or content-driven site -- You want a modular architecture -- You need 175+ UI components ready to use -- You want more features out of the box -- You value quick development speed -- You're building a feature-rich application - -**Can't decide?** -Try both! Both are free. Clone each one, run `composer install`, seed the database, and see which fits your workflow better. The one that feels right is the right choice. - -## Conclusion - -Larament and LaraCoreKit solve different problems: - -- **Larament** is a clean, high-quality foundation to build upon -- **LaraCoreKit** is a feature-rich starter with modules and multilingual support - -Neither is "better" - they serve different needs. Larament has the advantage of maturity and battle-testing. LaraCoreKit has the advantage of built-in features and modular architecture. - -## Further Reading - -- [LaraCoreKit Documentation](https://www.laracorekit.com/docs) -- [Larament GitHub Repository](https://github.com/rizkhal/larament) -- [LaraCoreKit vs Official Livewire Starter](laracorekit-vs-livewire-starter.md) - ---- - -**Have questions or corrections?** - -This comparison is meant to be honest and help you make the right choice. If you spot any inaccuracies, please open an issue or submit a pull request. - -Last updated: April 22, 2026 +Review [implemented features](/docs/introduction), [installation](/docs/installation) and [production requirements](/docs/deployment/production) before deciding. diff --git a/docs/comparisons/laracorekit-vs-livewire-starter.md b/docs/comparisons/laracorekit-vs-livewire-starter.md index 04bac85..819a062 100644 --- a/docs/comparisons/laracorekit-vs-livewire-starter.md +++ b/docs/comparisons/laracorekit-vs-livewire-starter.md @@ -1,467 +1,7 @@ -# LaraCoreKit vs Official Laravel Livewire Starter Kit +# Choosing a Laravel foundation -A detailed comparison between LaraCoreKit and the official Laravel Livewire starter kit to help you choose the right starting point for your project. +LaraCoreKit combines a public frontend and Filament administration in a reusable package. It is useful when your application needs those features together and you accept the documented Laravel/PHP constraints. -## Quick Comparison +Compare alternatives using their current official documentation and your own clean-install evaluation. This repository does not maintain a verified feature-by-feature comparison of third-party projects. Earlier comparative claims should not be used as evidence of security, performance or completeness. -| Feature | LaraCoreKit | Laravel Livewire Starter | -|---------|-------------|--------------------------| -| **Laravel Version** | 13.x | 13.x | -| **Admin Panel** | Filament 5 | None | -| **Frontend Framework** | Livewire 4 | Livewire 4 + Flux UI | -| **Styling** | Tailwind 4 | Tailwind 4 | -| **PHP Version** | 8.3+ | 8.3+ | -| **License** | MIT (Free) | MIT (Free) | -| **Official Support** | Community | Laravel Official | -| **Architecture** | Modular | Standard Laravel | -| **Multilingual** | Yes (EN/HI/AR) | No | -| **RTL Support** | Yes | No | -| **Blog Module** | Yes | No | -| **Admin Panel** | Yes (Filament) | No | -| **UI Components** | 175+ Tailwind | Flux UI Pro Components | -| **Authentication** | Breeze + Custom | Breeze + Flux | -| **Role/Permissions** | Yes (Spatie) | No (DIY) | -| **GitHub** | [LaraCoreKit](https://github.com/ProgrammerNomad/LaraCoreKit) (new) | [Livewire Starter](https://github.com/laravel/starter-kit) (official) | -| **Documentation** | Comprehensive | Official Laravel Docs | - -## Detailed Comparison - -### Official Support & Trust - -**Laravel Livewire Starter Kit:** -- **Official Laravel starter kit** - Maintained by Laravel team -- Direct integration with Laravel installer -- Backed by official documentation -- Part of Laravel ecosystem -- Long-term support guaranteed -- Regular updates with Laravel releases -- Production-ready from day one - -**LaraCoreKit:** -- **Community-maintained** - Created by independent developer -- Not officially endorsed by Laravel -- Community-driven development -- Documentation provided by maintainers -- Updates depend on maintainer availability -- Newer project (less battle-tested) - -**Winner:** Official Livewire Starter (official backing is huge) - ---- - -### Architecture & Scope - -**Laravel Livewire Starter Kit:** -- **Minimal, focused scope** - Auth + basic UI only -- Standard Laravel directory structure -- Clean slate to build upon -- No opinions beyond Livewire + Flux -- Perfect for learning Livewire -- Small footprint -- Fast to understand - -**LaraCoreKit:** -- **Feature-rich, modular** - Auth + Blog + Media + Settings + Admin -- Custom modular directory structure -- Many features out of the box -- Opinionated architecture -- Better for rapid development -- Larger footprint -- More to learn initially - -**Winner:** Depends on your goal - Official starter for learning, LaraCoreKit for building - ---- - -### UI Components - -**Laravel Livewire Starter Kit:** -- **Flux UI components** - Modern, accessible, professionally designed -- Designed specifically for Livewire -- Pro version available (paid) -- Fewer components than LaraCoreKit -- Higher quality, more polished -- Official Laravel design language -- Consistent with Laravel ecosystem - -**LaraCoreKit:** -- **175+ Tailwind components** - Broad variety across 12 categories -- All free and open-source -- E-commerce, charts, media, auth components -- Community-built -- More quantity, varying quality -- Independent design -- Good for prototyping - -**Winner:** Flux UI for quality and official support, LaraCoreKit for quantity and variety - ---- - -### Admin Panel - -**Laravel Livewire Starter Kit:** -- **No admin panel included** -- Build your own admin using Livewire + Flux -- Full control over admin experience -- More work upfront -- Learn by building - -**LaraCoreKit:** -- **Filament 5 admin panel** - Full-featured admin out of the box -- CRUD resources for all modules -- Form builder, table builder, widgets -- Dark mode, responsive -- Role-based access -- Ready to use immediately - -**Winner:** LaraCoreKit (huge advantage if you need an admin) - ---- - -### Authentication - -**Laravel Livewire Starter Kit:** -- Laravel Breeze for auth scaffolding -- Livewire + Flux UI for auth pages -- Login, registration, password reset -- Email verification -- Profile management -- Clean, modern UI -- Official Laravel auth patterns - -**LaraCoreKit:** -- Laravel Breeze + Custom auth -- Livewire 4 for auth pages -- Same features as official starter -- Plus: Avatar uploads -- Plus: User profiles -- Plus: Role-based access -- Filament admin for user management - -**Winner:** Tie (both have solid auth, LaraCoreKit has more features) - ---- - -### Content Management - -**Laravel Livewire Starter Kit:** -- **No content features** - Build your own -- Pure authentication starter -- Add blog/CMS yourself -- Full flexibility - -**LaraCoreKit:** -- **Full blog module** - Ready to use -- Rich text editor (Filament) -- Multilingual blog posts -- SEO fields, featured images -- Draft/publish workflow -- Filament admin + Livewire frontend - -**Winner:** LaraCoreKit (blog included vs none) - ---- - -### Multilingual & Internationalization - -**Laravel Livewire Starter Kit:** -- **No multilingual support** -- Laravel localization available -- Build language switcher yourself -- No RTL support -- Single language by default - -**LaraCoreKit:** -- **Built-in multilingual** - English, Hindi, Arabic -- Language switcher in navigation -- RTL layout support -- Locale middleware -- Translatable content -- Easy to add more languages - -**Winner:** LaraCoreKit (significant advantage) - ---- - -### Developer Experience - -**Laravel Livewire Starter Kit:** -- **Official Laravel documentation** - Best docs in PHP ecosystem -- Laravel installer support: `laravel new --using=livewire` -- Consistent with Laravel conventions -- Large Laravel community -- Abundant tutorials and resources -- Official support channels - -**LaraCoreKit:** -- **Custom documentation site** - Comprehensive but community-built -- Clone via Git (not Laravel installer yet) -- Custom conventions for modules -- Smaller community -- Growing documentation -- Community support - -**Winner:** Official Livewire Starter (better docs and community) - ---- - -### Quality Assurance - -**Laravel Livewire Starter Kit:** -- Official Laravel testing standards -- Clean, well-tested codebase -- Backed by Laravel team -- Production-ready -- Regular security updates - -**LaraCoreKit:** -- PHPUnit tests included -- Laravel Pint (code formatting) -- PHPStan (static analysis) -- GitHub Actions CI/CD -- `composer review` command -- Community-maintained - -**Winner:** Official Livewire Starter (official backing and testing) - ---- - -### Feature Comparison Table - -| Feature | Official Livewire | LaraCoreKit | -|---------|------------------|-------------| -| **Authentication** | Yes | Yes | -| **Registration** | Yes | Yes | -| **Password Reset** | Yes | Yes | -| **Email Verification** | Yes | Yes | -| **Profile Management** | Yes | Yes | -| **Admin Panel** | No | Yes (Filament 5) | -| **User Management** | No | Yes | -| **Role/Permissions** | No | Yes (Spatie) | -| **Blog/CMS** | No | Yes | -| **Media Library** | No | Yes (Spatie) | -| **Settings Module** | No | Yes | -| **Multilingual** | No | Yes (EN/HI/AR) | -| **RTL Support** | No | Yes | -| **UI Components** | Flux UI | 175+ Tailwind | -| **Dark Mode** | Yes | Yes | -| **API Auth** | Sanctum | Sanctum | -| **2FA Ready** | No | No | - ---- - -## Installation Comparison - -### Official Laravel Livewire Starter Kit - -```bash -# One command installation -laravel new my-app --using=livewire - -cd my-app -php artisan migrate -npm install && npm run dev -php artisan serve -``` - -**Pros:** -- Single command -- Official installer -- Fast setup -- Clean slate - -### LaraCoreKit - -```bash -# Git clone installation -git clone https://github.com/ProgrammerNomad/LaraCoreKit.git my-app -cd my-app - -composer install -npm install - -cp .env.example .env -php artisan key:generate - -touch database/database.sqlite -php artisan migrate --seed -php artisan storage:link -php artisan filament:user - -npm run build -php artisan serve -``` - -**Pros:** -- Full features ready -- Seeded demo data -- Admin panel configured -- All modules working - -**Cons:** -- More steps -- Not Laravel installer yet - ---- - -## Use Cases - -### Choose Official Laravel Livewire Starter if: -- You want official Laravel backing -- You're learning Livewire -- You need a minimal, clean foundation -- You prefer building features from scratch -- You want the best documentation -- You value official support -- You're building a simple app -- You want Flux UI components -- You prefer standard Laravel conventions - -### Choose LaraCoreKit if: -- You need an admin panel immediately -- You're building a blog or CMS -- You need multilingual support (especially RTL) -- You want role/permission system out of the box -- You need rapid development -- You want 175+ UI components -- You're building a feature-rich application -- You like modular architecture -- You need media library and settings management - ---- - -## Learning Curve - -**Official Livewire Starter:** -- **Gentle learning curve** - Standard Laravel + Livewire -- Official documentation -- Familiar structure -- Less to learn upfront -- Build features as you learn - -**LaraCoreKit:** -- **Steeper learning curve** - Custom modular architecture -- Need to understand module system -- More features to learn -- Documentation is good but not official -- Faster development once learned - ---- - -## Long-Term Maintenance - -**Official Livewire Starter:** -- **Official maintenance** - Laravel team responsibility -- Regular updates with Laravel releases -- Security patches guaranteed -- Long-term support -- Won't be abandoned - -**LaraCoreKit:** -- **Community maintenance** - Depends on maintainer -- Updates depend on community -- Security patches depend on maintainer activity -- Uncertain long-term support -- Risk of abandonment (like any community project) - -**Winner:** Official Livewire Starter (much lower risk) - ---- - -## Our Honest Recommendation - -### For Learning Livewire: -**Use Official Livewire Starter Kit** -- Best documentation -- Official support -- Clean, minimal codebase -- Learn Livewire the right way - -### For Production Projects: - -**Use Official Livewire Starter if:** -- You want official backing and long-term support -- You're building a simple application -- You have time to build features -- You prefer minimal starting point -- Official documentation is important -- You value stability over features - -**Use LaraCoreKit if:** -- You need an admin panel now -- You're building a content-driven site -- You need multilingual/RTL support -- Time-to-market is critical -- You're comfortable with community projects -- You want features over official backing - -### For Rapid Prototyping: -**LaraCoreKit** - More features out of the box means faster prototyping - -### For Enterprise: -**Official Livewire Starter** - Official support and long-term maintenance guarantee matter most - ---- - -## Can They Work Together? - -**Yes, but carefully:** - -You can use Flux UI components in LaraCoreKit, or add LaraCoreKit modules to an official Livewire starter project. However, architectural differences may cause friction. - -**Better approach:** -- Pick one as your foundation -- Borrow ideas from the other -- Avoid mixing architectures - ---- - -## Migration Path - -### From Official Livewire to LaraCoreKit: -Difficult. Very different architectures. Better to start fresh with LaraCoreKit if you want modular approach. - -### From LaraCoreKit to Official Livewire: -Possible but wasteful. You'd lose all the modules and features. Only do this if you need to standardize on official stack. - ---- - -## Conclusion - -The official Laravel Livewire starter kit and LaraCoreKit serve different audiences: - -**Official Livewire Starter Kit:** -- Official, stable, well-documented foundation -- Perfect for learning and simple projects -- Flux UI components are beautiful -- Best for long-term enterprise projects -- Minimal but high-quality - -**LaraCoreKit:** -- Feature-rich, rapid development starter -- Perfect for content-driven and admin-heavy projects -- Multilingual and modular from day one -- Best for MVPs and feature-rich applications -- Comprehensive but community-maintained - -**The truth:** The official starter has the advantage of official backing, stability, and documentation. LaraCoreKit has the advantage of features, admin panel, and rapid development. - -**Our advice:** If you're torn, start with the official Livewire starter and add features as you need them. If you know you need admin, blog, multilingual, and rapid development, go with LaraCoreKit. - ---- - -## Further Reading - -- [Official Laravel Livewire Starter Kit](https://laravel.com/docs/13.x/starter-kits#livewire) -- [Livewire Documentation](https://livewire.laravel.com) -- [Flux UI](https://fluxui.dev) -- [LaraCoreKit Documentation](https://www.laracorekit.com/docs) -- [LaraCoreKit vs Larament](laracorekit-vs-larament.md) - ---- - -**Questions or corrections?** - -This comparison aims to be honest and helpful. If you find inaccuracies, please open an issue or submit a pull request. - -Last updated: April 22, 2026 +Review [implemented features](/docs/introduction), [installation](/docs/installation) and [production requirements](/docs/deployment/production) before deciding. diff --git a/docs/configuration.md b/docs/configuration.md index 6f02e12..101e9a1 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1,381 +1,16 @@ -# Configuration +# Configuration ---- -**Supported Stack:** Laravel 13 / Filament 5 / Livewire 4 / Tailwind 4 -**Last Updated:** April 22, 2026 -**Estimated Time:** 8 minutes -**Difficulty:** Intermediate -**Source Files:** [config/modules.php](../../config/modules.php) | [config/app.php](../../config/app.php) ---- +After [creating a Laravel application and requiring the package](/docs/installation), run `php artisan laracorekit:install` to publish `config/laracorekit.php` and public CSS. Existing configuration is preserved. -This guide explains all key configuration points in LaraCoreKit, including app settings, module configuration, multilingual setup, and environment-specific options. +| Setting | Default | Purpose | +| --- | --- | --- | +| `configure_auth` | `true` | Select the packaged User model for the `users` auth provider | +| `panel.enabled` | `true` | Register the package's Filament panel | +| `panel.id` / `panel.path` | `admin` | Panel identity and URL path | +| `modules` | all bundled modules enabled | Register module providers and matching panel resources | +| `registration` | `false` | Enable public registration | +| `locales` | `en`, `hi`, `ar` | Accepted language-switch values | ---- - -## Environment File (`.env`) - -Your `.env` file controls runtime behavior for local, staging, and production environments. - -### Core Application Settings - -```env -APP_NAME="LaraCoreKit" -APP_ENV=local -APP_KEY=base64:your-generated-key -APP_DEBUG=true -APP_URL=http://localhost:8000 -``` - -### Localization - -```env -APP_LOCALE=en -APP_FALLBACK_LOCALE=en -APP_FAKER_LOCALE=en_US -``` - -### Database - -```env -DB_CONNECTION=mysql -DB_HOST=127.0.0.1 -DB_PORT=3306 -DB_DATABASE=laracorekit -DB_USERNAME=root -DB_PASSWORD= -``` - -### Cache & Sessions - -```env -CACHE_DRIVER=file -SESSION_DRIVER=file -QUEUE_CONNECTION=sync -``` - -### Mail - -```env -MAIL_MAILER=smtp -MAIL_HOST=mailpit -MAIL_PORT=1025 -MAIL_USERNAME=null -MAIL_PASSWORD=null -MAIL_ENCRYPTION=null -MAIL_FROM_ADDRESS="hello@laracorekit.com" -MAIL_FROM_NAME="${APP_NAME}" -``` - ---- - -## Modules Configuration (`config/modules.php`) - -This is one of the most important files in LaraCoreKit. - -### Example - -```php -return [ - 'namespace' => 'Modules', - - 'paths' => [ - 'modules' => base_path('modules'), - ], - - 'enabled' => [ - 'Core', - 'Auth', - 'User', - 'Blog', - 'Media', - 'Settings', - ], - - 'scan' => [ - 'enabled' => true, - 'paths' => [ - base_path('modules'), - ], - ], -]; -``` - -### Enable/Disable a Module - -Disable module temporarily: - -```php -'enabled' => [ - 'Core', - 'Auth', - 'User', - // 'Blog', // disabled - 'Media', - 'Settings', -], -``` - -Then clear cache: - -```bash -php artisan optimize:clear -``` - ---- - -## Application Config (`config/app.php`) - -Common customizations: - -- Application name -- Timezone -- Locale defaults -- Service providers -- Aliases - -### Recommended - -```php -'name' => env('APP_NAME', 'LaraCoreKit'), -'timezone' => 'UTC', -'locale' => env('APP_LOCALE', 'en'), -'fallback_locale' => env('APP_FALLBACK_LOCALE', 'en'), -``` - ---- - -## Authentication Config (`config/auth.php`) - -LaraCoreKit uses Laravel auth + Sanctum. - -Key sections: - -- `guards` (web, api) -- `providers` (users) -- `passwords` (reset options) - -If using custom user model in a module, update provider model accordingly. - ---- - -## Permissions Config (`config/permission.php`) - -Powered by Spatie Permission. - -Configure: - -- Role model / permission model -- Teams support -- Cache store and expiration -- Table names - -After permission changes, clear permission cache: - -```bash -php artisan permission:cache-reset -``` - ---- - -## Filesystem Config (`config/filesystems.php`) - -Use local or cloud storage. - -### Local Disk - -```php -'public' => [ - 'driver' => 'local', - 'root' => storage_path('app/public'), - 'url' => env('APP_URL').'/storage', - 'visibility' => 'public', -], -``` - -### S3 Disk - -```env -FILESYSTEM_DISK=s3 -AWS_ACCESS_KEY_ID=your_key -AWS_SECRET_ACCESS_KEY=your_secret -AWS_DEFAULT_REGION=us-east-1 -AWS_BUCKET=your_bucket -AWS_URL= -``` - -Create storage symlink for local: - -```bash -php artisan storage:link -``` - ---- - -## Cache & Queue Config - -### Local Development - -```env -CACHE_DRIVER=file -QUEUE_CONNECTION=sync -SESSION_DRIVER=file -``` - -### Production Recommended - -```env -CACHE_DRIVER=redis -QUEUE_CONNECTION=redis -SESSION_DRIVER=redis -``` - -Run queue worker: - -```bash -php artisan queue:work -``` - ---- - -## Mail Configuration - -### Development (Mailpit) - -```env -MAIL_MAILER=smtp -MAIL_HOST=127.0.0.1 -MAIL_PORT=1025 -MAIL_USERNAME=null -MAIL_PASSWORD=null -MAIL_ENCRYPTION=null -``` - -### Production (SMTP) - -```env -MAIL_MAILER=smtp -MAIL_HOST=smtp.mailgun.org -MAIL_PORT=587 -MAIL_USERNAME=postmaster@laracorekit.com -MAIL_PASSWORD=your_password -MAIL_ENCRYPTION=tls -``` - ---- - -## Multilingual Config - -Supported locales are usually managed by Core/Settings modules. - -Typical setup: - -```php -// config/app.php -'locale' => 'en', -'fallback_locale' => 'en', -``` - -And language files in: - -- `lang/en.json` -- `lang/hi.json` -- `lang/ar.json` - -For RTL logic: - -```blade - -``` - ---- - -## Frontend Build Config - -### Vite (`vite.config.js`) - -Make sure module assets/views are included when needed. - -Typical inputs: - -```js -input: ['resources/css/app.css', 'resources/js/app.js'] -``` - -### Tailwind (`tailwind.config.js`) - -Include module blade paths: - -```js -content: [ - './resources/**/*.blade.php', - './modules/**/resources/**/*.blade.php', - './vendor/filament/**/*.blade.php', -] -``` - ---- - -## Config Cache Commands - -Use these commands during configuration updates: - -```bash -php artisan config:clear -php artisan cache:clear -php artisan route:clear -php artisan view:clear -php artisan optimize:clear -``` - -Production optimize: - -```bash -php artisan config:cache -php artisan route:cache -php artisan view:cache -php artisan optimize -``` - ---- - -## Environment Profiles - -### Local - -- `APP_DEBUG=true` -- File cache/session -- Sync queue -- Detailed logs - -### Staging - -- `APP_DEBUG=false` -- Real services where possible -- Redis queue/cache -- Lower log verbosity - -### Production - -- `APP_DEBUG=false` -- Redis for cache/session/queue -- SMTP configured -- Monitoring enabled -- Config and route cache enabled - ---- - -## Common Configuration Mistakes - -1. Forgetting to run `php artisan optimize:clear` after config changes. -2. Missing module path in `config/modules.php`. -3. Not including module blade files in Tailwind content paths. -4. Wrong `APP_URL` causing broken asset URLs. -5. Wrong filesystem disk causing upload failures. - ---- - -## Next Steps - -Next: [Core Architecture →](core/architecture.md) -Then: [Module System →](core/modules-system.md) +The initial supported authentication model is `Modules\User\Models\User`. Disabling `configure_auth` does not automatically adapt resources or relationships to a custom user model. Custom model support requires integration work. +The demo host disables the packaged panel, uses its own provider and enables registration for evaluation. Environment settings such as database, mail, queues, storage and APP_URL remain standard Laravel configuration. Cache configuration after deployment with `php artisan config:cache`. diff --git a/docs/contributing.md b/docs/contributing.md index 2160a1a..a806b00 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -1,165 +1,9 @@ -# Contributing to LaraCoreKit +# Contributing -**Estimated time:** 5 minutes -**Difficulty:** Beginner +Changes are welcome through GitHub pull requests. Read CONTRIBUTING.md at the repository root for the workflow, and use the security policy for sensitive reports. ---- +Package changes belong in packages/core; website/docs/showcase changes belong in the host. Add meaningful regression tests for behavior changes, rebuild package CSS when its source changes, and update installation/upgrade notes when the public contract changes. -Thank you for your interest in contributing to LaraCoreKit! Contributions make the open-source community amazing. +Run tests, Pint, static analysis, dependency audits and production builds before proposing a release. Test package installation independently of the host using the consumer smoke script. ---- - -## Ways to Contribute - -| Contribution | How | -|-------------|-----| -| Report bugs | [GitHub Issues](https://github.com/ProgrammerNomad/LaraCoreKit/issues) | -| Suggest features | GitHub Discussions | -| Improve docs | Edit docs and submit a PR | -| Build modules | Share on GitHub / Packagist | -| Add translations | Create/improve language files | -| Star the repo | Helps others discover it | - ---- - -## Contributing Code - -### Step 1: Fork and Clone - -```bash -# Fork on GitHub first, then: -git clone https://github.com/YOUR_USERNAME/LaraCoreKit.git -cd LaraCoreKit -``` - -### Step 2: Set Up Locally - -```bash -cp .env.example .env -composer install -npm install -php artisan key:generate -php artisan migrate --seed -npm run dev -``` - -### Step 3: Create a Branch - -```bash -git checkout -b feature/your-feature-name -# or -git checkout -b fix/bug-description -``` - -**Branch naming:** -- `feature/` - New feature -- `fix/` - Bug fix -- `docs/` - Documentation improvement -- `refactor/` - Code refactoring - -### Step 4: Make Your Changes - -- Follow PSR-12 coding standards -- Write tests for new features -- Keep commits small and focused -- Write clear commit messages - -### Step 5: Test Your Changes - -```bash -# Format code -./vendor/bin/pint - -# Run all tests -php artisan test - -# Run type checking (if using PHPStan) -./vendor/bin/phpstan analyse -``` - -### Step 6: Submit a Pull Request - -```bash -git push origin feature/your-feature-name -``` - -Then open a PR on GitHub with: -- **Clear title** describing what it does -- **Description** of what changed and why -- **Screenshots** for UI changes -- **Reference** to related issues - ---- - -## Code Style - -LaraCoreKit uses **Laravel Pint** (PSR-12 based): - -```bash -# Auto-format all PHP files -./vendor/bin/pint - -# Check without fixing -./vendor/bin/pint --test -``` - ---- - -## Documentation - -Docs files are in `/docs/*.md`. Edit them directly and submit a PR. - -Guidelines: -- Start each page with a clear **H1 heading** -- Include `**Estimated time:**` and `**Difficulty:**` -- Use real, working code examples -- End with a **"Next Steps"** section -- Avoid vague descriptions - be specific - ---- - -## Bug Reports - -A great bug report includes: -- **LaraCoreKit version** (`git log --oneline -1`) -- **PHP version** (`php -v`) -- **Steps to reproduce** (exact steps, no assumptions) -- **Expected behavior** -- **Actual behavior** -- **Error messages / stack trace** - ---- - -## Feature Requests - -Open a GitHub Discussion with: -- **What problem does this solve?** -- **Who would use this feature?** -- **How should it work?** (API, UI, behavior) -- **Alternative solutions you considered** - ---- - -## Module Contributions - -Built an awesome module? Share it! - -1. Create a Composer package (see [Publishing Modules](modules/publishing.md)) -2. Post in GitHub Discussions with `[Module]` prefix -3. We may feature it in the official docs! - ---- - -## Code of Conduct - -Be respectful, inclusive, and constructive. We follow the [Contributor Covenant](https://www.contributor-covenant.org/) Code of Conduct. - ---- - -## License - -By contributing, you agree that your contributions will be licensed under the **MIT License**. - ---- - -**Thank you for helping make LaraCoreKit better! ** +See [installation](/docs/installation) and [package architecture](/docs/core/architecture). diff --git a/docs/core/architecture.md b/docs/core/architecture.md index 47bf552..d57087b 100644 --- a/docs/core/architecture.md +++ b/docs/core/architecture.md @@ -1,129 +1,46 @@ -# Architecture - -**Estimated time:** 10 minutes -**Difficulty:** Intermediate - ---- - -LaraCoreKit is built on a modular architecture where each feature is isolated into a module with clear boundaries. - ---- - -## Architectural Goals - -1. **Separation of concerns** - Features are isolated. -2. **Scalability** - Add new modules without touching core. -3. **Maintainability** - Smaller, focused code areas. -4. **Reusability** - Modules can be reused across projects. -5. **Testability** - Module-level testing is straightforward. - ---- - -## High-Level Design - +# Package architecture + +The reusable package and the demo host have separate responsibilities. + +```text +LaraCoreKit/ + packages/core/ programmernomad/laracorekit + composer.json package dependencies and discovery + src/CoreServiceProvider.php configuration and module registration + src/Console/ installer and administrator creation + src/Filament/ default package admin panel + config/laracorekit.php package defaults + modules/ Core, Auth, User, Settings, Media, Blog + resources/dist/ prebuilt public frontend CSS + app/ demo/site application and custom panel + modules/Docs/ website documentation viewer + modules/UIShowcase/ component demonstration application + resources/views/site/ marketing homepage and changelog + resources/views/vendor/core/ host override for shared layout + database/seeders/ safe defaults and guarded demo seeders + docs/ documentation source ``` -Application Core -├── Module Loader -├── Global Middleware -├── Shared Layouts -└── Cross-cutting Services - -Feature Modules -├── Auth -├── User -├── Blog -├── Media -└── Settings -``` - -Core is intentionally minimal. Most business logic belongs in modules. - ---- - -## Request Lifecycle (Simplified) - -1. Request enters Laravel HTTP kernel. -2. Global middleware runs. -3. Routes resolve (core + module routes). -4. Controller/Livewire from module executes. -5. View or JSON response is returned. - ---- - -## Layering Strategy - -### Core Layer - -- Boots module system -- Provides shared helpers/layouts -- Coordinates application-level concerns - -### Module Layer - -Each module owns: - -- Domain models -- Routes/controllers/livewire -- Admin resources -- Migrations/seeders -- Views/translations - -### Infrastructure Layer - -- Database, cache, queue, mail -- Filesystem/media -- External services - ---- - -## Why This Works Well - -- Teams can work in parallel by module. -- New features are additive, not invasive. -- Refactoring one feature has minimal side effects. -- Optional modules can be distributed as packages. - ---- - -## Design Principles - -1. Keep `app/` small and framework-centric. -2. Keep feature code inside `modules/{Feature}`. -3. Prefer explicit module contracts over hidden coupling. -4. Avoid cross-module direct DB assumptions when possible. -5. Use events/services for looser integration. - ---- - -## Typical Data Flow - -Example: creating a blog post -1. Authenticated user submits form. -2. Blog module validates request. -3. Blog model persists translated fields. -4. Permission checks use shared RBAC system. -5. Optional media attachments via Media module. -6. Response returns to frontend/admin. +Composer loads package namespaces and Laravel discovers `LaraCoreKit\Core\CoreServiceProvider`. It registers enabled module providers from `config/laracorekit.php` and the default panel when enabled. The host disables the default panel and provides its own. There is one registration contract; modules are no longer registered individually in the host's `bootstrap/providers.php`. ---- +## Public and admin features -## Trade-offs +Auth and Blog register public routes and Livewire components. User, Settings, Blog and Media provide the models, migrations and admin resources. Core supplies the shared layout, locale component and middleware. The homepage, changelog, docs and UI demonstration are website responsibilities and are excluded from the Composer package. -### Benefits +The first release bundles functional modules in one package to keep compatibility and releases manageable. Their internal boundaries remain available for future extraction. Installing the bundle installs its PHP dependencies; disabling Blog does not uninstall Media Library or remove database tables. -- Better structure for medium/large apps. -- Faster feature onboarding. -- Cleaner ownership boundaries. +## Application ownership -### Costs +Keep application logic and view overrides outside `vendor/`. Your app owns its homepage, environment, mail, database, storage, queues and deployment. The installer publishes configuration and prebuilt public CSS. It does not overwrite your routes or create demo accounts. The default admin uses Filament's theme; the host's custom admin theme is separate. -- Slightly more setup for new modules. -- Requires consistent conventions. -- Developers must understand module boot process. +The public model namespaces remain `Modules\...` for compatibility with existing code. Applications that already use those namespaces or the package's route names need conflict resolution. Existing applications must review user-model and data compatibility before installation. ---- +## Extension points -## Next Steps +- Publish config with `php artisan vendor:publish --tag=laracorekit-config`. +- Override namespaced Blade views under `resources/views/vendor/{namespace}`. +- Disable the packaged panel and register resources in your own Filament panel. +- Use normal Laravel packages with auto-discovered providers for additional modules. +- Re-publish assets after updates with `php artisan vendor:publish --tag=laracorekit-assets --force`. -Next: [Module System →](modules-system.md) +See [installation](/docs/installation) and [upgrade notes](/docs/upgrade-guide). diff --git a/docs/core/middleware.md b/docs/core/middleware.md index 81246e9..2d8d0d9 100644 --- a/docs/core/middleware.md +++ b/docs/core/middleware.md @@ -1,73 +1,9 @@ -# Middleware +# Middleware -**Estimated time:** 6 minutes -**Difficulty:** Intermediate +Core appends `Modules\Core\Http\Middleware\SetLocale` to the web middleware group. It reads the session locale and accepts only configured supported values. ---- +Public auth pages use guest middleware, while the account dashboard and logout require authentication. Filament uses its own authenticated panel middleware stack and the User model's panel-access check. -Middleware provides request-level control for authentication, localization, permissions, and feature flags. +CSRF protection, session handling and cookie encryption remain Laravel responsibilities. Configure trusted proxies correctly when deploying behind a load balancer, since IP-based rate limits depend on the resolved client address. ---- - -## Common Middleware in LaraCoreKit - -- `web` - session, CSRF, cookies -- `auth` - authenticated users only -- `verified` - email verified only -- `setLocale` - locale from request/session/user -- `permission:*` - permission-based access control - ---- - -## Global vs Route Middleware - -### Global middleware - -Runs on every request (registered in HTTP kernel). - -### Route middleware - -Applied only on specific routes/groups: - -```php -Route::middleware(['auth', 'verified'])->group(function () { - // Protected routes -}); -``` - ---- - -## Localization Middleware - -Typical behavior: - -1. Detect locale from route/session/user preference. -2. Set `app()->setLocale($locale)`. -3. Apply RTL layout if locale is Arabic. - ---- - -## Permission Middleware - -Spatie permission middleware controls route-level RBAC: - -```php -Route::middleware(['auth', 'permission:blog.create'])->group(function () { - Route::get('/admin/blog/create', ...); -}); -``` - ---- - -## Best Practices - -1. Keep middleware focused and single-purpose. -2. Avoid heavy logic in middleware. -3. Use route groups for clean middleware stacking. -4. Document custom middleware behavior. - ---- - -## Next Steps - -Next: [Authentication Feature →](../features/authentication.md) +See [installation](/docs/installation) and [package architecture](/docs/core/architecture). diff --git a/docs/core/modules-system.md b/docs/core/modules-system.md index 92ed4f7..0d12c43 100644 --- a/docs/core/modules-system.md +++ b/docs/core/modules-system.md @@ -1,201 +1,7 @@ -# Module System +# Module system -**Estimated time:** 10 minutes -**Difficulty:** Intermediate +Package modules live in `packages/core/modules`. Configure their providers through `config/laracorekit.php`, under `modules`. Core always loads. Auth requires User; Blog requires User and Media; the packaged panel requires User. Invalid combinations fail explicitly. ---- +Providers own routes, namespaced views and migrations. The packaged panel registers resources only for enabled modules. Disabling a module does not delete data or remove Composer dependencies. The website's Docs and UIShowcase modules are host-only providers. -The LaraCoreKit Module System is the **core differentiator** that makes this starter kit production-ready and team-scalable. Instead of one giant `app/` directory, features are organized into self-contained, independent modules. - ---- - -## What is a Module? - -A **module** is a self-contained PHP package directory within `/modules` that handles a single feature area. Each module owns: - -- Its own **Models** -- Its own **Controllers / Livewire components** -- Its own **Migrations** and **Seeders** -- Its own **Views** and **Blade components** -- Its own **Routes** -- Its own **Translations** -- Its own **Service Provider** - ---- - -## How Modules Load - -The loading pipeline: - -``` -config/modules.php - │ - ▼ -App\Providers\ModuleServiceProvider::register() - │ (iterates enabled modules) - │ - ▼ -Each Module's ServiceProvider::boot() - │ - ├── loadViewsFrom() - ├── loadMigrationsFrom() - ├── loadRoutesFrom() - └── Livewire::component(...) -``` - -### `config/modules.php` - -```php -return [ - 'modules' => [ - 'Blog' => [ - 'enabled' => true, - 'namespace' => 'Modules\\Blog', - 'provider' => 'Modules\\Blog\\BlogServiceProvider', - ], - // ... more modules - ], -]; -``` - -Setting `enabled => false` completely disables a module - no routes registered, no migrations run. - ---- - -## Benefits - -| Benefit | What it means for you | -|---------|----------------------| -| **Independent** | Teams can work on separate modules independently | -| **Enable/Disable** | Toggle features without touching any other code | -| **Distributable** | Publish as Composer packages | -| **Testable** | Test each module in isolation | -| **Scalable** | Add features without touching existing code | - ---- - -## Module Directory Structure - -``` -modules/ -└── Blog/ - ├── src/ - │ ├── BlogServiceProvider.php ← Registers everything - │ ├── Models/ - │ │ └── Post.php - │ ├── Http/ - │ │ └── Livewire/ - │ │ ├── BlogList.php - │ │ └── BlogDetail.php - │ └── Filament/ - │ └── Resources/ - │ └── PostResource.php - ├── database/ - │ ├── migrations/ - │ │ └── 2024_01_01_create_posts_table.php - │ └── seeders/ - │ └── BlogSeeder.php - ├── views/ - │ └── blog/ - │ ├── list.blade.php - │ └── detail.blade.php - └── routes/ - └── web.php -``` - ---- - -## The Service Provider - -Every module has one `ServiceProvider` that bootstraps the module: - -```php -namespace Modules\Blog; - -use Illuminate\Support\ServiceProvider; -use Livewire\Livewire; - -class BlogServiceProvider extends ServiceProvider -{ - public function register(): void - { - // Bind interfaces, share config, etc. - } - - public function boot(): void - { - // Load migrations - $this->loadMigrationsFrom(__DIR__ . '/../database/migrations'); - - // Load Blade views under 'blog::' namespace - $this->loadViewsFrom(__DIR__ . '/../views', 'blog'); - - // Register Livewire components - Livewire::component('blog.blog-list', \Modules\Blog\Http\Livewire\BlogList::class); - Livewire::component('blog.blog-detail', \Modules\Blog\Http\Livewire\BlogDetail::class); - - // Load routes - $this->loadRoutesFrom(__DIR__ . '/../routes/web.php'); - } -} -``` - ---- - -## Accessing Module Views - -Module views use a **namespace** prefix: - -```blade -{{-- In any Blade view --}} -@extends('blog::layouts.base') - -@include('blog::partials.card') -``` - ---- - -## Module Autoloading - -Modules are autoloaded via `composer.json`: - -```json -{ - "autoload": { - "psr-4": { - "Modules\\Blog\\": "modules/Blog/src/", - "Modules\\Blog\\Database\\Seeders\\": "modules/Blog/database/seeders/" - } - } -} -``` - -After adding a new module, run: - -```bash -composer dump-autoload -``` - ---- - -## Disabling a Module - -To temporarily disable the Blog module: - -```php -// config/modules.php -'Blog' => [ - 'enabled' => false, // ← toggle this - ... -], -``` - -Run `php artisan optimize:clear` after changing this. - ---- - -## Next Steps - -**[Create a Module →](../modules/create-module)** - -Step-by-step guide to building your first custom module. +For additional independently distributed modules, follow the existing demo module's Composer service-provider discovery pattern. Do not edit the installed package to add application features. diff --git a/docs/core/routing.md b/docs/core/routing.md index 71bd9e6..e7dc0e5 100644 --- a/docs/core/routing.md +++ b/docs/core/routing.md @@ -1,107 +1,9 @@ -# Routing +# Routing -**Estimated time:** 7 minutes -**Difficulty:** Intermediate +Auth provides session authentication routes and Blog provides `/blog` and `/blog/{slug}`. Core provides the named `locale.switch` route. Routes use the web middleware group. ---- +Your application owns `/`; the package does not replace your homepage. This repository's host additionally defines `/docs`, `/docs/{page}`, `/docs-source/{page}`, `/llms.txt`, `/changelog` and `/sitemap.xml`. UIShowcase owns `/ui-showcase` routes. -Routing in LaraCoreKit combines global Laravel routes with module-specific routes. +Use `php artisan route:list` to inspect exact routes. Conventional names such as `login`, `dashboard` and `blog.index` can collide with existing application routes. Resolve conflicts before installation and test `php artisan route:cache` during deployment. ---- - -## Route Sources - -1. `routes/web.php` - global routes -2. `routes/api.php` - global API routes -3. `modules/*/src/routes/web.php` - module web routes -4. `modules/*/src/routes/api.php` - module API routes - ---- - -## Module Route Loading - -Module providers load their own routes: - -```php -$this->loadRoutesFrom(__DIR__.'/routes/web.php'); -``` - -This keeps routes close to feature code. - ---- - -## Recommended Route Conventions - -### Public web routes - -```php -Route::get('/blog', [BlogController::class, 'index'])->name('blog.index'); -``` - -### Protected routes - -```php -Route::middleware(['auth'])->group(function () { - Route::get('/dashboard', DashboardController::class)->name('dashboard'); -}); -``` - -### API routes - -```php -Route::middleware('auth:sanctum')->group(function () { - Route::get('/profile', [ProfileController::class, 'show']); -}); -``` - ---- - -## Route Naming - -Use consistent names to avoid conflicts: - -- `blog.index` -- `blog.show` -- `user.profile.edit` -- `settings.general.update` - -Prefer module-prefixed route names. - ---- - -## Route Caching - -Production: - -```bash -php artisan route:cache -``` - -After route changes: - -```bash -php artisan route:clear -``` - ---- - -## Debugging Routes - -List routes: - -```bash -php artisan route:list -``` - -Filter by module/prefix: - -```bash -php artisan route:list --name=blog -php artisan route:list --path=admin -``` - ---- - -## Next Steps - -Next: [Middleware →](middleware.md) +See [installation](/docs/installation) and [package architecture](/docs/core/architecture). diff --git a/docs/core/service-providers.md b/docs/core/service-providers.md index 45de34b..7faf0b0 100644 --- a/docs/core/service-providers.md +++ b/docs/core/service-providers.md @@ -1,78 +1,9 @@ -# Service Providers +# Service providers -**Estimated time:** 6 minutes -**Difficulty:** Intermediate +Laravel discovers `LaraCoreKit\Core\CoreServiceProvider` from the package's Composer metadata. It merges configuration, selects the packaged auth model when enabled, registers configured module providers, and optionally registers the default Filament panel. ---- +Module providers load namespaced views, migrations, public routes and Livewire aliases. The package also registers the locale middleware and console commands. The host's `AppServiceProvider` handles website-only integration, including the docs view namespace and the demo's language-switch plugin. -Service providers are the bootstrap layer of LaraCoreKit and each module. +The former application `ModuleServiceProvider` and `config/modules.php` have been removed. Use `config/laracorekit.php` for bundled modules. Independently distributed addons should use normal Composer provider discovery. ---- - -## Why Providers Matter - -Service providers tell Laravel how to wire your application: - -- Register services in the container -- Load routes/views/translations/migrations -- Bind interfaces to implementations -- Register event listeners and commands - ---- - -## Provider Types in LaraCoreKit - -1. `AppServiceProvider` - global app bootstrapping. -2. `ModuleServiceProvider` - discovers and registers modules. -3. `*ModuleServiceProvider` - one per module. - ---- - -## Typical Module Provider - -```php -class BlogServiceProvider extends ServiceProvider -{ - public function register(): void - { - // Bind services or merge config - } - - public function boot(): void - { - $this->loadRoutesFrom(__DIR__.'/routes/web.php'); - $this->loadViewsFrom(__DIR__.'/resources/views', 'blog'); - $this->loadMigrationsFrom(__DIR__.'/Database/migrations'); - $this->loadTranslationsFrom(__DIR__.'/resources/lang', 'blog'); - } -} -``` - ---- - -## Register vs Boot - -- `register()`: - - Container bindings - - Config merge - - No runtime dependencies - -- `boot()`: - - Route/view/migration loading - - Event registration - - Runtime-ready logic - ---- - -## Best Practices - -1. Keep providers lightweight. -2. Avoid heavy DB queries in `boot()`. -3. Use dedicated classes for complex registration logic. -4. Namespace module views/translations. - ---- - -## Next Steps - -Next: [Routing →](routing.md) +See [installation](/docs/installation) and [package architecture](/docs/core/architecture). diff --git a/docs/deployment/demo-setup.md b/docs/deployment/demo-setup.md index a696007..1c36c00 100644 --- a/docs/deployment/demo-setup.md +++ b/docs/deployment/demo-setup.md @@ -1,1047 +1,18 @@ -# Demo Mode Setup Guide +# Demo setup -**Auto-resetting demo environment for LaraCoreKit with Filament integration** +The demo is a disposable application hosted by this repository. It is not part of `programmernomad/laracorekit`. The existing `programmernomad/laracorekit-demo-module` dependency manages reset behavior and restrictions. -**Package**: [programmernomad/laracorekit-demo-module](https://packagist.org/packages/programmernomad/laracorekit-demo-module) -**Repository**: [GitHub](https://github.com/ProgrammerNomad/laracorekit-demo-module) +First complete the [GitHub host installation](/docs/installation#option-b-run-the-complete-github-demodevelopment-host), including dependencies, environment, application key, database and frontend builds. The commands below add sample content to that configured host; they do not install Laravel or the demo website. ---- - -## Quick Start - -### 1. Install Package - -```bash -composer require programmernomad/laracorekit-demo-module -``` - -### 2. Configure Environment - -Add to `.env`: - -```env -DEMO_MODE=true -DEMO_RESET_INTERVAL=30 -DEMO_ADMIN_EMAIL=admin@laracorekit.com -DEMO_ADMIN_PASSWORD=Admin@123 -DEMO_USER_EMAIL=user@laracorekit.com -DEMO_USER_PASSWORD=User@123 -``` - -### 3. Update User Seeder - -Modify `modules/User/Database/Seeders/UserSeeder.php` to use demo credentials: - -```php -// Admin user -$admin = User::firstOrCreate( - ['email' => config('demo.credentials.admin.email', 'admin@laracorekit.com')], - [ - 'name' => 'Admin User', - 'password' => Hash::make(config('demo.credentials.admin.password', 'password')), - 'email_verified_at' => now(), - ] -); - -// Regular user -$user = User::firstOrCreate( - ['email' => config('demo.credentials.user.email', 'user@laracorekit.com')], - [ - 'name' => 'Demo User', - 'password' => Hash::make(config('demo.credentials.user.password', 'password')), - 'email_verified_at' => now(), - ] -); -``` - -### 4. Add Frontend Banner (Optional) - -Edit `modules/Auth/views/livewire/login.blade.php`: - -```blade -{{-- Demo Banner --}} -@if(config('demo.enabled') && view()->exists('demo::components.login-banner')) - @include('demo::components.login-banner', ['type' => 'user']) -@endif -``` - -### 5. Run Database Reset - -```bash -php artisan demo:reset --force -``` - -### 6. Test Login - -**Frontend**: http://localhost/login -- Email: `user@laracorekit.com` -- Password: `User@123` - -**Admin**: http://localhost/admin/login -- Email: `admin@laracorekit.com` -- Password: `Admin@123` - -**Done!** Demo banners appear automatically. - ---- - -## What's Included - -### Auto-Registered Features - -The package automatically provides: - -1. **Filament Admin Login Banner** - Shows credentials before login form (auto-injected via render hook) -2. **Artisan Command** - `php artisan demo:reset` to reset database -3. **Scheduled Reset** - Cron job every 30 minutes (configurable) -4. **Action Blocking** - Prevents destructive operations (user deletion, etc.) -5. **Middleware** - `demo` and `demo.block` for route protection -6. **Blade Component** - `@include('demo::components.login-banner')` for frontend - -### 📋 Manual Setup Required - -1. **User Seeder** - Update to use demo credentials from config -2. **Frontend Login** - Add `@include` directive to show banner -3. **Cron Job** - Setup Laravel scheduler on server - ---- - -## Features - -### Method 1: Packagist (Recommended) - -**Production/Demo Server:** -```bash -composer require programmernomad/laracorekit-demo-module -``` - -**Local Development:** -```bash -composer require programmernomad/laracorekit-demo-module --dev -``` - -### Method 2: Local Development (Path Repository) - -**For contributing or testing changes:** - -```bash -# Clone package repo -cd C:\xampp\htdocs -git clone https://github.com/ProgrammerNomad/laracorekit-demo-module.git -``` - -**In `composer.json`:** -```json -{ - "repositories": [ - { - "type": "path", - "url": "../laracorekit-demo-module", - "options": { - "symlink": true - } - } - ], - "require-dev": { - "programmernomad/laracorekit-demo-module": "@dev" - } -} -``` - -```bash -composer update programmernomad/laracorekit-demo-module -``` - -**Benefits:** -- Changes in `laracorekit-demo-module/` instantly reflect in LaraCoreKit -- Perfect for development and testing - ---- - -## Configuration - -### Step 1: Publish Config File +Use a separate database and storage location. Explicitly set `DEMO_MODE=true` only for the demo application. Follow the demo package's allowed-host requirements before enabling it in production. Then migrate and seed: ```bash -php artisan vendor:publish --tag=demo-config -``` - -This creates `config/demo.php` with all customizable options. - -### Step 2: Update `.env` (Production/Demo Server) - -**Add to `.env` on your demo server:** -```env -# Demo Mode Configuration -DEMO_MODE=true -DEMO_RESET_INTERVAL=30 - -# Demo Credentials (displayed on login pages) -DEMO_ADMIN_EMAIL=admin@laracorekit.com -DEMO_ADMIN_PASSWORD=Admin@123 -DEMO_USER_EMAIL=user@laracorekit.com -DEMO_USER_PASSWORD=User@123 -``` - -### Step 3: Update `.env.example` (Repository) - -**For contributors and documentation:** -```env -# Demo Mode (set to true on demo server only) -DEMO_MODE=false -DEMO_RESET_INTERVAL=30 -DEMO_ADMIN_EMAIL=admin@laracorekit.com -DEMO_ADMIN_PASSWORD=Admin@123 -DEMO_USER_EMAIL=user@laracorekit.com -DEMO_USER_PASSWORD=User@123 -``` - -### Step 4: Customize Settings (Optional) - -**Edit `config/demo.php`** to customize: - -- Reset interval -- Allowed domains (security) -- Blocked actions -- Banner appearance -- Cleanup settings - -**Example customizations:** -```php -// config/demo.php - -'allowed_hosts' => [ - 'www.laracorekit.com', // Your demo domain - 'localhost', - '127.0.0.1', -], - -'blocked_actions' => [ - 'user.delete', - 'role.delete', - 'backup.run', - // Add your custom actions -], - -'banner' => [ - 'background_color' => 'blue-50', // Change colors - 'border_color' => 'blue-500', - 'text_color' => 'blue-900', -], -``` - ---- - -## Plesk Cron Setup - -The demo module automatically schedules database resets using Laravel's task scheduler. You just need to add Laravel's scheduler to your server's cron. - -### Step 1: Access Plesk Cron Jobs - -1. Log into Plesk Control Panel -2. Go to **Websites & Domains** -3. Select **www.laracorekit.com** -4. Click **Scheduled Tasks (Cron Jobs)** - -### Step 2: Add Laravel Scheduler Cron - -**Settings:** -- **Command**: `cd /var/www/vhosts/laracorekit.com && php artisan schedule:run >> /dev/null 2>&1` -- **Run**: Every minute (*/1) -- **Minute**: `*` -- **Hour**: `*` -- **Day of Month**: `*` -- **Month**: `*` -- **Day of Week**: `*` - -**Alternative (if using different path):** -```bash -cd /home/username/public_html && /usr/bin/php artisan schedule:run >> /dev/null 2>&1 -``` - -**Find your PHP path in Plesk:** -```bash -which php -# Output: /usr/bin/php8.2 or similar -``` - -**Full command with explicit PHP version:** -```bash -cd /var/www/vhosts/laracorekit.com && /usr/bin/php8.2 artisan schedule:run >> /dev/null 2>&1 -``` - -### Step 3: Verify Cron is Running - -**SSH into server:** -```bash -ssh username@www.laracorekit.com -cd /var/www/vhosts/laracorekit.com - -# Test schedule manually -php artisan schedule:list - -# Check if demo:reset is scheduled -php artisan schedule:work -``` - -### Step 4: Monitor Cron Logs - -**Create log output (temporary for testing):** -```bash -cd /var/www/vhosts/laracorekit.com && php artisan schedule:run >> storage/logs/cron.log 2>&1 -``` - -**Check logs:** -```bash -tail -f storage/logs/cron.log -tail -f storage/logs/laravel.log -``` - ---- - -## UI Integration - -### Add Demo Banner to Login Pages - -The package provides Blade components that automatically show demo credentials when `DEMO_MODE=true`. - -**Frontend Login** (`modules/Auth/views/login.blade.php`): -```blade - -``` - -**Admin Login** (create `app/Filament/Pages/Auth/Login.php`): -```php -login(Login::class) -``` - -**Admin Dashboard Widget**: -```php -// app/Filament/Pages/Dashboard.php -use LaraCoreKit\DemoModule\Filament\Widgets\DemoBannerWidget; - -protected function getHeaderWidgets(): array -{ - return [ - DemoBannerWidget::class, - ]; -} -``` - ---- - -## Security & Testing -```php -use Modules\Demo\Filament\Widgets\DemoBannerWidget; - -protected function getHeaderWidgets(): array -{ - return [ - DemoBannerWidget::class, - ]; -} -``` - ---- - -## Phase 4: Plesk Cron Setup - -### Step 4.1: Access Plesk Cron Jobs - -1. Log into Plesk Control Panel -2. Go to **Websites & Domains** -3. Select **www.laracorekit.com** -4. Click **Scheduled Tasks (Cron Jobs)** - -### Step 4.2: Add Laravel Scheduler Cron - -**Settings:** -- **Command**: `cd /var/www/vhosts/laracorekit.com && php artisan schedule:run >> /dev/null 2>&1` -- **Run**: Every minute (*/1) -- **Minute**: `*` -- **Hour**: `*` -- **Day of Month**: `*` -- **Month**: `*` -- **Day of Week**: `*` - -**Alternative (if using different path):** -```bash -cd /home/username/public_html && /usr/bin/php artisan schedule:run >> /dev/null 2>&1 -``` - -**Find your PHP path in Plesk:** -```bash -which php -# Output: /usr/bin/php8.2 or similar -``` - -**Full command with explicit PHP version:** -```bash -cd /var/www/vhosts/laracorekit.com && /usr/bin/php8.2 artisan schedule:run >> /dev/null 2>&1 -``` - -### Step 4.3: Verify Cron is Running - -**SSH into server:** -```bash -ssh username@www.laracorekit.com -cd /var/www/vhosts/laracorekit.com - -# Test schedule manually -php artisan schedule:list - -# Check if demo:reset is scheduled -php artisan schedule:work -``` - -### Step 4.4: Monitor Cron Logs - -**Create log output (temporary for testing):** -```bash -cd /var/www/vhosts/laracorekit.com && php artisan schedule:run >> storage/logs/cron.log 2>&1 -``` - -**Check logs:** -```bash -tail -f storage/logs/cron.log -tail -f storage/logs/laravel.log -``` - ---- - -## Phase 5: Security & Testing - -### Step 5.1: Test Manual Reset - -**SSH into server:** -```bash -cd /var/www/vhosts/laracorekit.com - -# Run manual reset -php artisan demo:reset --force - -# Verify database was reset -php artisan tinker ->>> \App\Models\User::count() ->>> \Modules\Blog\Models\Post::count() -``` - -### Step 5.2: Test Blocked Actions - -1. Login as admin -2. Try to delete a user Should show "Action disabled in demo mode" -3. Try to modify critical settings Should be blocked -4. Upload a file Should work (will be deleted on reset) - -### Step 5.3: Security Checklist - -- [ ] `DEMO_MODE=false` in local `.env` -- [ ] `DEMO_MODE=true` only on `www.laracorekit.com` -- [ ] Verify `allowed_hosts` in config includes demo domain -- [ ] Test that demo banner shows on login pages -- [ ] Test that cron job runs every 30 minutes -- [ ] Verify uploaded files get deleted on reset -- [ ] Check sessions are cleared on reset -- [ ] Test that database credentials work after reset - -### Step 5.4: Monitoring Setup - -**Install Laravel Telescope (if not already):** -```bash -composer require laravel/telescope -php artisan telescope:install php artisan migrate +php artisan db:seed --class="Database\Seeders\DemoSeeder" ``` -**Monitor:** -- Scheduled commands at `/telescope/schedule` -- Database queries at `/telescope/queries` -- Logs at `/telescope/logs` - -**Enable only in demo:** -```php -// config/telescope.php -'enabled' => env('TELESCOPE_ENABLED', env('DEMO_MODE', false)), -``` - ---- - -## Phase 6: CI/CD Integration - -### Step 6.1: GitHub Actions Workflow - -**File**: `.github/workflows/deploy-demo.yml` -```yaml -name: Deploy Demo Environment - -on: - push: - branches: - - main - - demo - -jobs: - deploy: - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Deploy to Plesk - uses: appleboy/ssh-action@master - with: - host: ${{ secrets.DEMO_SERVER_HOST }} - username: ${{ secrets.DEMO_SERVER_USER }} - key: ${{ secrets.DEMO_SERVER_SSH_KEY }} - script: | - cd /var/www/vhosts/laracorekit.com - - # Pull latest code - git pull origin main - - # Install dependencies - composer install --no-dev --optimize-autoloader - - # Run migrations (safe with fresh flag in demo) - php artisan migrate --force - - # Clear caches - php artisan config:cache - php artisan route:cache - php artisan view:cache - - # Build assets - npm ci - npm run build - - # Reset demo database immediately after deploy - php artisan demo:reset --force - - # Restart queues if applicable - php artisan queue:restart -``` - -### Step 6.2: GitHub Secrets Setup - -**In GitHub Repository Settings Secrets:** -``` -DEMO_SERVER_HOST = www.laracorekit.com -DEMO_SERVER_USER = your-ssh-username -DEMO_SERVER_SSH_KEY = (paste your private SSH key) -``` - -### Step 6.3: Plesk Git Integration (Alternative) - -**If using Plesk Git:** -1. Go to **Git** in Plesk -2. Add repository: `https://github.com/yourusername/LaraCoreKit.git` -3. Set branch: `main` or `demo` -4. **Deployment Actions** Add commands: -```bash -composer install --no-dev --optimize-autoloader -php artisan migrate --force -php artisan config:cache -npm ci && npm run build -php artisan demo:reset --force -``` - ---- - -## Phase 7: Production Deployment - -### Step 7.1: Pre-Deployment Checklist - -- [ ] All code committed to GitHub -- [ ] `.env` configured on Plesk server -- [ ] `DEMO_MODE=true` set -- [ ] Cron job added in Plesk -- [ ] SSH access verified -- [ ] Database backed up -- [ ] CI/CD secrets configured - -### Step 7.2: Deploy to Production - -**Option A: Manual Deployment** -```bash -# SSH into server -ssh username@www.laracorekit.com - -cd /var/www/vhosts/laracorekit.com - -# Pull latest code -git pull origin main - -# Install dependencies -composer install --no-dev --optimize-autoloader - -# Publish demo config -php artisan vendor:publish --tag=demo-config - -# Run migrations -php artisan migrate --force - -# Seed demo data -php artisan db:seed --force - -# Clear and cache -php artisan config:cache -php artisan route:cache -php artisan view:cache - -# Build assets -npm ci -npm run build - -# Initial demo reset -php artisan demo:reset --force -``` - -**Option B: CI/CD Auto-Deploy** -```bash -# Just push to main branch -git push origin main - -# GitHub Actions will handle deployment -``` - -### Step 7.3: Verify Deployment - -**Visit site:** -- Frontend: https://www.laracorekit.com/login -- Admin: https://www.laracorekit.com/admin/login - -**Check:** -- [ ] Demo banner visible on login pages -- [ ] Demo credentials work -- [ ] Admin dashboard shows demo widget -- [ ] Can create blog post (temporary) -- [ ] Wait 30 minutes verify auto-reset worked -- [ ] Check logs: `storage/logs/laravel.log` - -### Step 7.4: Post-Deployment Monitoring - -**Monitor for first 24 hours:** -```bash -# Watch cron execution -tail -f storage/logs/laravel.log | grep "Demo database reset" - -# Check scheduled tasks -php artisan schedule:list - -# Monitor Telescope -# Visit: https://www.laracorekit.com/telescope -``` - ---- - -## Troubleshooting - -### Issue: Cron not running - -**Solution:** -```bash -# Check if cron daemon is running -sudo service cron status - -# Check Plesk cron logs -tail -f /var/log/cron - -# Manually test Laravel scheduler -cd /var/www/vhosts/laracorekit.com -php artisan schedule:work -``` - -### Issue: Demo reset fails - -**Solution:** -```bash -# Check Laravel logs -tail -f storage/logs/laravel.log - -# Run manually with verbose output -php artisan demo:reset --force -vvv - -# Check database connection -php artisan tinker ->>> DB::connection()->getPdo() -``` - -### Issue: Demo banner not showing - -**Solution:** -```php -// Check config -php artisan config:clear -php artisan tinker ->>> config('demo.enabled') ->>> config('demo.banner.show_on_login') - -// Clear view cache -php artisan view:clear -``` - -### Issue: Files not being deleted - -**Solution:** -```bash -# Check permissions -ls -la storage/app/public/media/ -chmod -R 775 storage/app/public/media/ -chown -R www-data:www-data storage/app/public/media/ - -# Manual cleanup test -php artisan tinker ->>> \Illuminate\Support\Facades\File::cleanDirectory(storage_path('app/public/media')) -``` - ---- - -## Module Management - -### Option 1: Disable Demo Module (Recommended for End Users) - -**In `.env`:** -```env -DEMO_MODE=false -DEMO_MODULE_ENABLED=false -``` - -**What this does:** -- Module code remains in `modules/Demo/` -- Service provider won't register -- No demo features active -- Zero overhead (not loaded) - -**When to use:** -- Production environments -- Local development (non-demo) -- Temporarily disable without removing files - ---- - -### Option 2: Remove Demo Module Completely - -**If you want to delete the module entirely:** - -**Step 1: Disable in config** -```php -// config/modules.php -'modules' => [ - // Comment out or remove: - // 'Demo' => [ - // 'enabled' => env('DEMO_MODULE_ENABLED', false), - // 'provider' => \Modules\Demo\DemoServiceProvider::class, - // ], -], -``` - -**Step 2: Remove from ModuleServiceProvider** -```php -// app/Providers/ModuleServiceProvider.php -// Remove these lines: -// if (config('modules.modules.Demo.enabled')) { -// $this->app->register(\Modules\Demo\DemoServiceProvider::class); -// } -``` - -**Step 3: Delete module directory** -```bash -# PowerShell -Remove-Item -Recurse -Force modules\Demo - -# Or Git (to keep in history) -git rm -r modules/Demo -git commit -m "feat: remove Demo module" -``` - -**Step 4: Update autoload** -```bash -composer dump-autoload -``` - ---- - -### Option 3: Extract as Standalone Composer Package (Advanced) - -**This allows users to `composer require/remove` the demo module** - -**Benefits:** -- Users can install: `composer require laracorekit/demo-module` -- Users can remove: `composer remove laracorekit/demo-module` -- Version management (1.0.0, 1.1.0, etc.) -- Separate repo, separate maintenance -- Can be used in other Laravel projects - -**Steps to extract:** - -**1. Create new repository** -```bash -# On GitHub, create: laracorekit/demo-module -git clone https://github.com/laracorekit/demo-module.git -cd demo-module -``` - -**2. Copy module files** -```bash -# From LaraCoreKit project -cp -r modules/Demo/* demo-module/ -``` - -**3. Create standalone `composer.json`** - -**File**: `composer.json` (in demo-module repo root) -```json -{ - "name": "laracorekit/demo-module", - "description": "Auto-resetting demo environment module for Laravel applications", - "keywords": ["laravel", "demo", "module", "filament"], - "license": "MIT", - "type": "library", - "authors": [ - { - "name": "Your Name", - "email": "your.email@laracorekit.com" - } - ], - "require": { - "php": "^8.2", - "laravel/framework": "^11.0|^12.0", - "filament/filament": "^3.0" - }, - "autoload": { - "psr-4": { - "LaraCoreKit\\DemoModule\\": "src/" - } - }, - "extra": { - "laravel": { - "providers": [ - "LaraCoreKit\\DemoModule\\DemoServiceProvider" - ] - } - }, - "minimum-stability": "dev", - "prefer-stable": true -} -``` - -**4. Update namespace in all PHP files** -```php -// Change from: -namespace Modules\Demo; - -// To: -namespace LaraCoreKit\DemoModule; -``` - -**5. Create README.md for package** -```markdown -# Demo Module for Laravel - -Auto-resetting demo environment with Filament integration. - -## Installation - -composer require laracorekit/demo-module - -## Configuration - -php artisan vendor:publish --tag=demo-config - -## Usage - -See full documentation... -``` - -**6. Publish to Packagist** -```bash -# Push to GitHub -git add . -git commit -m "Initial release" -git tag 1.0.0 -git push origin main --tags - -# Submit to Packagist.org -# Go to: https://packagist.org/packages/submit -# Enter: https://github.com/laracorekit/demo-module -``` - -**7. Install in LaraCoreKit** - -**Remove local module:** -```bash -git rm -r modules/Demo -``` - -**Install via Composer:** -```bash -composer require laracorekit/demo-module -``` - -**Update config/modules.php:** -```php -'modules' => [ - 'Demo' => [ - 'enabled' => env('DEMO_MODULE_ENABLED', false), - 'provider' => \LaraCoreKit\DemoModule\DemoServiceProvider::class, - ], -], -``` - -**8. Users can now uninstall:** -```bash -# Remove package -composer remove laracorekit/demo-module - -# Remove from config/modules.php -# Done! Module completely removed -``` - ---- - -### Comparison: Built-in vs Composer Package - -| Feature | Built-in Module | Composer Package | -|---------|----------------|------------------| -| Installation | Included by default | `composer require` | -| Removal | Delete directory | `composer remove` | -| Updates | Git pull main repo | `composer update` | -| Versioning | Follows main repo | Independent (1.0, 2.0) | -| Portability | LaraCoreKit only | Any Laravel project | -| Maintenance | Same repo | Separate repo | -| User Control | Less flexible | Full control | - ---- - -### Recommended Approach - -**For LaraCoreKit Distribution:** - -**Option A: Keep Built-in (Default)** -- Include in main repo -- Users disable via `.env` -- Easier for beginners -- Less setup complexity - -**Option B: Make it Optional** -- Don't include in `modules/` by default -- Provide installation docs -- Users install if needed: `composer require laracorekit/demo-module` -- Cleaner for production users - -**Option C: Hybrid (Best of Both)** -- Include in repo but **disabled by default** -- `.env.example` has `DEMO_MODULE_ENABLED=false` -- README shows how to enable OR how to remove completely -- Users choose their path - ---- - -### Implementation for "Composer Uninstallable" - -**If you want users to be able to `composer remove` it:** - -**1. Extract to package (follow Option 3 above)** - -**2. Remove from main LaraCoreKit repo** -```bash -git rm -r modules/Demo -git commit -m "feat: extract Demo module to separate package" -``` - -**3. Add as dev dependency** -```bash -composer require laracorekit/demo-module --dev -``` - -**4. Update documentation** -```markdown -## Demo Module (Optional) - -Install demo auto-reset functionality: - -composer require laracorekit/demo-module - -Remove when not needed: - -composer remove laracorekit/demo-module -``` - -**5. Users have full control** -```bash -# Install -composer require laracorekit/demo-module - -# Enable -# .env: DEMO_MODULE_ENABLED=true - -# Disable -# .env: DEMO_MODULE_ENABLED=false - -# Remove completely -composer remove laracorekit/demo-module -``` - ---- - -## Maintenance - -### Regular Tasks - -**Weekly:** -- Check cron logs for failures -- Monitor storage usage (media uploads) -- Review Telescope for anomalies - -**Monthly:** -- Update demo credentials (security) -- Review blocked actions list -- Test manual reset -- Backup database before changes - ---- - -## Summary - -**Module Benefits:** -- Isolated demo logic -- Easy to enable/disable -- Production-safe (domain whitelisting) -- Auto-resetting (30-min cron) -- Plesk-compatible -- CI/CD integrated -- Extractable as package - -**Next Steps:** -1. Create module structure (Phase 1) -2. Configure `.env` on Plesk (Phase 2) -3. Add UI banners (Phase 3) -4. Setup Plesk cron (Phase 4) -5. Test & deploy (Phase 5-7) +The seeder refuses to run with demo mode disabled. Admin/editor sample passwords come from the demo administrator credential configuration; user credentials come from demo user configuration. These accounts are publicly shared and must never exist in a customer application. -**Questions? Issues?** -Refer to troubleshooting section or Laravel docs. +The demo package's reset command rebuilds its configured database and calls the default seeder, which delegates to DemoSeeder only when demo mode is enabled. Configure Laravel's scheduler only on the disposable demo host. Review blocked actions and test restrictions after package updates. Do not run reset commands against valuable data. +Public-facing credential banners should appear only while demo mode is active. Screenshots must use a disposable demo instance and contain no real customer information. diff --git a/docs/deployment/docker.md b/docs/deployment/docker.md index 8228da5..921b34f 100644 --- a/docs/deployment/docker.md +++ b/docs/deployment/docker.md @@ -1,210 +1,7 @@ -# Docker Deployment +# Docker -**Estimated time:** 12 minutes -**Difficulty:** Intermediate +Docker is an optional deployment/development choice. This repository includes Laravel Sail as a development dependency; it does not claim a maintained production container image. ---- +For container deployment, build your own reviewed PHP/Node stages, install locked dependencies, compile assets, run as a suitable non-root user and mount persistent storage appropriately. Configure secrets at runtime and run migrations as a deliberate deployment step. Validate the resulting image with your application's smoke tests. -LaraCoreKit supports containerized deployment with Docker, both for local development (via Laravel Sail) and production. - ---- - -## Option 1: Laravel Sail (Development) - -Laravel Sail is pre-configured for development containers. - -```bash -# Install Sail -php artisan sail:install - -# Start all services (MySQL, Redis, etc.) -./vendor/bin/sail up -d - -# Run artisan commands inside container -./vendor/bin/sail artisan migrate -./vendor/bin/sail artisan queue:work - -# Run composer inside container -./vendor/bin/sail composer require some/package - -# Run npm inside container -./vendor/bin/sail npm run dev -``` - ---- - -## Option 2: Custom Docker Setup (Production) - -### `Dockerfile` - -```dockerfile -FROM php:8.3-fpm-alpine - -# Install system dependencies -RUN apk add --no-cache \ - git curl zip unzip \ - libpng-dev libjpeg-dev libwebp-dev \ - icu-dev libzip-dev \ - && docker-php-ext-install \ - pdo_mysql mbstring zip bcmath \ - gd intl exif opcache - -# Install Composer -COPY --from=composer:2 /usr/bin/composer /usr/bin/composer - -# Set working directory -WORKDIR /var/www/html - -# Copy application -COPY . . - -# Install PHP dependencies -RUN composer install --no-dev --optimize-autoloader --no-interaction - -# Build frontend assets -COPY --from=node:20-alpine /usr/local/bin/node /usr/local/bin/node -COPY --from=node:20-alpine /usr/local/lib/node_modules /usr/local/lib/node_modules -COPY --from=node:20-alpine /usr/local/bin/npm /usr/local/bin/npm -RUN npm ci && npm run build && rm -rf node_modules - -# Optimize Laravel -RUN php artisan optimize - -# Set permissions -RUN chown -R www-data:www-data /var/www/html/storage \ - && chmod -R 775 /var/www/html/storage /var/www/html/bootstrap/cache - -EXPOSE 9000 -CMD ["php-fpm"] -``` - -### `docker-compose.yml` - -```yaml -version: '3.8' - -services: - app: - build: - context: . - dockerfile: Dockerfile - restart: unless-stopped - working_dir: /var/www/html - volumes: - - ./storage:/var/www/html/storage - - ./.env:/var/www/html/.env - depends_on: - - db - - redis - networks: - - laracorekit - - nginx: - image: nginx:alpine - restart: unless-stopped - ports: - - "80:80" - - "443:443" - volumes: - - ./public:/var/www/html/public - - ./docker/nginx.conf:/etc/nginx/conf.d/default.conf - - /etc/letsencrypt:/etc/letsencrypt:ro - depends_on: - - app - networks: - - laracorekit - - db: - image: mysql:8.0 - restart: unless-stopped - environment: - MYSQL_DATABASE: laracorekit - MYSQL_USER: laracorekit - MYSQL_PASSWORD: secret - MYSQL_ROOT_PASSWORD: root_secret - volumes: - - db_data:/var/lib/mysql - networks: - - laracorekit - - redis: - image: redis:7-alpine - restart: unless-stopped - volumes: - - redis_data:/data - networks: - - laracorekit - - queue: - build: - context: . - dockerfile: Dockerfile - restart: unless-stopped - command: php artisan queue:work redis --sleep=3 --tries=3 - environment: - QUEUE_CONNECTION: redis - depends_on: - - db - - redis - networks: - - laracorekit - -volumes: - db_data: - redis_data: - -networks: - laracorekit: - driver: bridge -``` - ---- - -## Nginx Config for Docker - -```nginx -# docker/nginx.conf -server { - listen 80; - server_name _; - root /var/www/html/public; - index index.php; - - location / { - try_files $uri $uri/ /index.php?$query_string; - } - - location ~ \.php$ { - fastcgi_pass app:9000; - fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; - include fastcgi_params; - } -} -``` - ---- - -## Deploy Commands - -```bash -# Build and start all containers -docker compose up -d --build - -# Run migrations -docker compose exec app php artisan migrate --force - -# Optimize -docker compose exec app php artisan optimize - -# View logs -docker compose logs -f app - -# Restart app container -docker compose restart app -``` - ---- - -## Next Steps - -**[Hosting Guide →](hosting)** +See [installation](/docs/installation) and [package architecture](/docs/core/architecture). diff --git a/docs/deployment/hosting.md b/docs/deployment/hosting.md index c2ffd79..26aa306 100644 --- a/docs/deployment/hosting.md +++ b/docs/deployment/hosting.md @@ -1,181 +1,9 @@ -# Hosting Guide +# Hosting -**Estimated time:** 8 minutes -**Difficulty:** Beginner +Deploy a supported PHP 8.3+ Laravel environment with required extensions, HTTPS, a webroot pointing at public/, a configured database, mail, storage and background workers as needed. ---- - -## Recommended Hosting Providers - -| Provider | Type | Best For | Starting Cost | -|----------|------|----------|--------------| -| **Laravel Cloud** | Managed | Easiest deployment | ~$5/mo | -| **Forge + VPS** | VPS Panel | Full control | ~$12/mo | -| **Ploi** | VPS Panel | Affordable alternative | ~$10/mo | -| **Railway** | PaaS | Fast hobby projects | Free tier | -| **Fly.io** | PaaS | Docker-based | Free tier | -| **DigitalOcean App** | PaaS | Simple setup | ~$12/mo | - ---- - -## Option 1: Laravel Cloud (Easiest) - -The official managed Laravel hosting platform. - -```bash -# Install CLI -curl -fsSL https://cloud.laravel.com/installer.sh | sh - -# Login -cloud login - -# Deploy from your project root -cloud deploy -``` - -Laravel Cloud handles: -- Zero-downtime deployments -- Auto-scaling -- SSL certificates -- Queue workers -- Cron jobs - ---- - -## Option 2: Forge + DigitalOcean - -Best balance of control and automation. - -### Step 1: Create a DigitalOcean Droplet - -- Ubuntu 22.04 LTS -- At least 2GB RAM (4GB recommended) -- 2 vCPUs - -### Step 2: Connect to Forge - -1. Visit [forge.laravel.com](https://forge.laravel.com) -2. Add your server (DigitalOcean) -3. Forge SSH's in and configures PHP, Nginx, MySQL, Redis - -### Step 3: Add Your Site - -1. Add site: `laracorekit.com` -2. Connect GitHub repo -3. Click **Deploy Now** - -### Step 4: Set Environment Variables - -In Forge → Site → Environment → Edit `.env`: - -```env -APP_ENV=production -APP_DEBUG=false -APP_URL=https://www.laracorekit.com -DB_DATABASE=laracorekit -DB_PASSWORD=your-secure-password -QUEUE_CONNECTION=redis -CACHE_DRIVER=redis -``` - -### Step 5: Deployment Script - -```bash -cd /home/forge/laracorekit.com -git pull origin main -composer install --no-dev --optimize-autoloader -npm ci && npm run build -php artisan migrate --force -php artisan optimize -php artisan queue:restart -``` - ---- - -## Option 3: Railway - -Great for quick deployments with zero server management. - -```bash -# Install Railway CLI -npm install -g @railway/cli - -# Login -railway login - -# Initialize project -railway init - -# Add services -railway add mysql -railway add redis - -# Deploy -railway up -``` - -Set environment variables in the Railway dashboard. - ---- - -## Option 4: Fly.io - -Docker-based deployment with global edge distribution. - -```bash -# Install flyctl -curl -L https://fly.io/install.sh | sh - -# Login -fly auth login - -# Initialize (creates fly.toml) -fly launch - -# Deploy -fly deploy -``` - -**fly.toml** (based on your Dockerfile): -```toml -[build] - dockerfile = "Dockerfile" - -[env] - APP_ENV = "production" - -[[services]] - protocol = "tcp" - internal_port = 80 - [[services.ports]] - port = 80 - handlers = ["http"] - [[services.ports]] - port = 443 - handlers = ["tls", "http"] -``` - ---- - -## SSL Certificates - -### Using Let's Encrypt (Free) - -```bash -# Install Certbot -sudo apt install certbot python3-certbot-nginx - -# Issue certificate -sudo certbot --nginx -d laracorekit.com -d www.laracorekit.com - -# Auto-renewal (runs twice daily) -sudo systemctl enable certbot.timer -``` - ---- - -## Next Steps - -**[Performance Optimization →](optimization)** +Use the production checklist for environment hardening, migrations, unique credentials and dependency audits. Do not expose .env, storage logs or repository files. Route requests through Laravel's front controller. +Keep the demo deployment isolated from customer applications and data. The package itself does not provision hosting, certificates or monitoring. +See [installation](/docs/installation) and [package architecture](/docs/core/architecture). diff --git a/docs/deployment/optimization.md b/docs/deployment/optimization.md index aa8e039..3224024 100644 --- a/docs/deployment/optimization.md +++ b/docs/deployment/optimization.md @@ -1,199 +1,9 @@ -# Performance Optimization +# Performance -**Estimated time:** 10 minutes -**Difficulty:** Intermediate +The host builds ordinary public JavaScript separately from Chart.js, Sortable and Prism used by the component showcase. Images below the fold should use lazy loading, defined dimensions and suitable compression. ---- - -Speed directly impacts user experience, SEO rankings, and conversion rates. This guide covers key optimizations for LaraCoreKit in production. - ---- - -## Laravel Built-in Optimizations - -Run all at once: - -```bash -php artisan optimize -``` - -Or individually: - -```bash -# Cache config (major speedup) -php artisan config:cache - -# Cache routes (faster route matching) -php artisan route:cache - -# Cache views (skip Blade compilation) -php artisan view:cache - -# Cache events (avoid dynamic discovery) -php artisan event:cache -``` - -Clear all caches: - -```bash -php artisan optimize:clear -``` - ---- - -## PHP OPcache - -Enable OPcache in `php.ini`: - -```ini -opcache.enable=1 -opcache.enable_cli=1 -opcache.memory_consumption=256 -opcache.max_accelerated_files=20000 -opcache.validate_timestamps=0 ; Disable in production -opcache.save_comments=1 -opcache.fast_shutdown=1 -``` - -Verify it's active: - -```bash -php -r "echo opcache_get_status()['opcache_enabled'] ? 'OPcache ON' : 'OPcache OFF';" -``` - ---- - -## Redis for Cache, Sessions, Queues - -Switch all drivers to Redis in `.env`: - -```env -CACHE_DRIVER=redis -SESSION_DRIVER=redis -QUEUE_CONNECTION=redis -``` - -Redis is dramatically faster than file-based drivers under load. - ---- - -## Database Indexes - -Add indexes to frequently queried columns: - -```php -// In a migration -Schema::table('blog_posts', function (Blueprint $table) { - $table->index(['status', 'locale']); - $table->index('slug'); - $table->index('published_at'); - $table->index('author_id'); -}); -``` - -Check for missing indexes using Laravel Telescope or the query log. - ---- - -## Eager Loading (Avoid N+1) - -```php -// ❌ Bad - N+1 queries -$posts = Post::all(); -foreach ($posts as $post) { - echo $post->author->name; // Query per post -} - -// Good - 2 queries total -$posts = Post::with('author', 'tags', 'media')->get(); -``` - ---- - -## HTTP Caching with Cache Headers - -```php -// In a controller -return response()->view('blog.show', compact('post')) - ->header('Cache-Control', 'public, max-age=3600'); -``` - ---- - -## Asset Optimization (Vite) - -Already handled by `npm run build`: -- Minification -- Tree-shaking -- Content hash for cache busting -- CSS extraction - ---- - -## Image Optimization - -When using Spatie MediaLibrary, add WebP conversions: - -```php -$this->addMediaConversion('webp') - ->format('webp') - ->quality(80); -``` - -Use lazy loading in Blade: - -```blade -{{ $post->title }} -``` - ---- - -## Livewire Optimization - -```php -// Use lazy loading for heavy components -@livewire('blog.blog-list', lazy: true) - -// Use wire:navigate for SPA-like navigation (Livewire 4) -Blog - -// Minimize re-renders with computed properties -#[Computed] -public function posts() -{ - return Post::published()->latest()->paginate(12); -} -``` - ---- - -## Benchmark Your App - -```bash -# Install k6 for load testing -# https://k6.io - -# Or use Apache Benchmark -ab -n 1000 -c 10 https://www.laracorekit.com/blog -``` - ---- - -## Monitoring - -Use these tools in production: - -| Tool | Purpose | -|------|---------| -| Laravel Telescope | Debug queries, jobs, requests | -| Sentry | Error tracking | -| UptimeRobot | Uptime monitoring | -| New Relic / Datadog | APM (Application Performance Monitoring) | - ---- - -## Next Steps - -**[Testing →](../advanced/testing)** +Use production builds, reviewed lockfiles, OPcache, appropriate cache storage and eager loading for public content. Paginate lists and measure real response times with representative data before making performance claims. +Run `npm run build:core` for the package's prebuilt public stylesheet and `npm run build` for the demo host. Package consumers do not need the demo's npm dependencies to use default views. Test view overrides after changes. +See [installation](/docs/installation) and [package architecture](/docs/core/architecture). diff --git a/docs/deployment/production.md b/docs/deployment/production.md index d54f2cf..32efb27 100644 --- a/docs/deployment/production.md +++ b/docs/deployment/production.md @@ -1,220 +1,38 @@ -# Production Setup +# Production setup -**Estimated time:** 15 minutes -**Difficulty:** Intermediate +Start with [package installation](/docs/installation) and test in staging. The package supplies frontend and admin features; your application remains responsible for infrastructure and operations. ---- +1. Set `APP_ENV=production`, `APP_DEBUG=false`, a unique application key and correct HTTPS `APP_URL`. +2. Keep `DEMO_MODE=false`. Do not seed demo accounts or run the demo reset scheduler in a customer application. +3. Install from reviewed lockfiles with `composer install --no-dev --optimize-autoloader`. Build and publish assets during deployment; do not run a Vite development server publicly. +4. Back up data before running `php artisan migrate --force`. Create the first administrator using `php artisan laracorekit:admin` and a unique password. +5. Configure transactional mail and test password recovery. Email-verification enforcement is not bundled. +6. Configure storage, file-size/type restrictions, queue workers and scheduled tasks appropriate to your application. Run `php artisan storage:link` for public local uploads. +7. Cache configuration/routes/views, monitor failures, test backups and restore procedures, and run dependency audits regularly. +8. Verify anonymous visitors cannot read unpublished or future-dated posts, regular users cannot enter the admin panel, and editors cannot manage users or roles. -This guide covers what you need to do to deploy LaraCoreKit to a live production server safely and efficiently. +The installer never creates known production credentials. Registration is disabled by default. Login failures are rate limited; choose a shared cache store across application servers so limits apply consistently. ---- +Security reports belong in the repository's [security policy](https://github.com/ProgrammerNomad/LaraCoreKit/security/policy), not public issues containing sensitive details. -## Pre-Deployment Checklist +## Application deployment -Before going live, verify: - -- [ ] `APP_ENV=production` -- [ ] `APP_DEBUG=false` -- [ ] `APP_URL` set to your real domain -- [ ] Database configured with a strong password -- [ ] Mail configured (Mailgun, SES, Postmark) -- [ ] Storage configured (local or S3) -- [ ] Queue worker running (Redis recommended) -- [ ] HTTPS certificate installed (Let's Encrypt) -- [ ] File permissions set correctly - ---- - -## Environment Variables - -```env -APP_NAME="My App" -APP_ENV=production -APP_DEBUG=false -APP_URL=https://www.laracorekit.com -APP_KEY=base64:... # Generate with: php artisan key:generate - -LOG_CHANNEL=stack -LOG_LEVEL=error - -DB_CONNECTION=mysql -DB_HOST=127.0.0.1 -DB_PORT=3306 -DB_DATABASE=laracorekit_prod -DB_USERNAME=dbuser -DB_PASSWORD=very_secure_password_here - -BROADCAST_DRIVER=log -CACHE_DRIVER=redis -FILESYSTEM_DISK=local -QUEUE_CONNECTION=redis -SESSION_DRIVER=redis -SESSION_LIFETIME=120 - -REDIS_HOST=127.0.0.1 -REDIS_PORT=6379 -REDIS_PASSWORD=null - -MAIL_MAILER=smtp -MAIL_HOST=smtp.mailgun.org -MAIL_PORT=587 -MAIL_USERNAME=your@mailgun.org -MAIL_PASSWORD=your-mailgun-key -MAIL_FROM_ADDRESS=noreply@laracorekit.com -MAIL_FROM_NAME="${APP_NAME}" -``` - ---- - -## Deployment Script +Install the tagged Packagist package in a fresh Laravel application as described in the installation guide. Commit the resulting application lockfile. Deploy from that lockfile rather than resolving new versions on the production server: ```bash -#!/bin/bash -set -e - -# Navigate to app -cd /var/www/laracorekit - -# Pull latest code -git pull origin main - -# Install/update PHP dependencies -composer install --no-dev --optimize-autoloader --no-interaction - -# Install/build frontend -npm ci && npm run build - -# Cache everything -php artisan config:cache -php artisan route:cache -php artisan view:cache -php artisan event:cache - -# Run migrations +composer install --no-dev --prefer-dist --optimize-autoloader +php artisan laracorekit:install php artisan migrate --force - -# Create storage symlink (if not exists) php artisan storage:link - -# Restart queue workers -php artisan queue:restart - -echo " Deployment complete!" -``` - -Make it executable: -```bash -chmod +x deploy.sh -./deploy.sh -``` - ---- - -## Nginx Configuration - -```nginx -server { - listen 80; - listen 443 ssl http2; - server_name www.laracorekit.com laracorekit.com; - root /var/www/laracorekit/public; - index index.php; - - ssl_certificate /etc/letsencrypt/live/laracorekit.com/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/laracorekit.com/privkey.pem; - - # Redirect HTTP to HTTPS - if ($scheme != "https") { - return 301 https://$server_name$request_uri; - } - - # Gzip Compression - gzip on; - gzip_types text/plain text/css application/json application/javascript; - - # Browser caching for assets - location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ { - expires 1y; - add_header Cache-Control "public, immutable"; - try_files $uri =404; - } - - location / { - try_files $uri $uri/ /index.php?$query_string; - } - - location ~ \.php$ { - fastcgi_pass unix:/var/run/php/php8.3-fpm.sock; - fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; - include fastcgi_params; - } - - location ~ /\. { - deny all; - } -} -``` - ---- - -## File Permissions - -```bash -# Set correct ownership -sudo chown -R www-data:www-data /var/www/laracorekit - -# Set permissions -sudo find /var/www/laracorekit -type f -exec chmod 644 {} \; -sudo find /var/www/laracorekit -type d -exec chmod 755 {} \; - -# Storage and cache dirs need write access -sudo chmod -R 775 /var/www/laracorekit/storage -sudo chmod -R 775 /var/www/laracorekit/bootstrap/cache -``` - ---- - -## Queue Worker (Supervisor) - -```ini -; /etc/supervisor/conf.d/laracorekit-queue.conf -[program:laracorekit-queue] -process_name=%(program_name)s_%(process_num)02d -command=php /var/www/laracorekit/artisan queue:work redis --sleep=3 --tries=3 --max-time=3600 -autostart=true -autorestart=true -stopasgroup=true -killasgroup=true -user=www-data -numprocs=2 -redirect_stderr=true -stdout_logfile=/var/log/laracorekit-queue.log -stopwaitsecs=3600 -``` - -```bash -supervisorctl reread -supervisorctl update -supervisorctl start laracorekit-queue:* -``` - ---- - -## Scheduled Tasks (Cron) - -```cron -* * * * * www-data php /var/www/laracorekit/artisan schedule:run >> /dev/null 2>&1 -``` - -Add via: -```bash -crontab -e -u www-data +php artisan optimize ``` ---- +Run migrations only after a backup and staging verification. The package installer preserves published configuration and refreshes assets. The package's default public views do not require the demo host's npm build. Custom frontend assets still need their own build. -## Next Steps +## Website and demonstration host -**[Docker →](docker)** +The main repository is also a development monorepo: it uses its local `packages/core` source through Composer, so keep that directory in the deployment checkout. Build core and host assets with `npm ci`, `npm run build:core` and `npm run build`. Point the HTTPS document root only at `public/`; keep `.env`, storage logs and database backups private. Use a dedicated database and storage for any disposable demo, with least-privilege database credentials separated from customer infrastructure. +Verify mail delivery, password recovery, uploads, authorization, scheduled jobs, queue workers and backup restoration in the actual deployment environment. Check Laravel's `/up` health endpoint and representative public/admin routes after deployment. Source validation alone does not verify TLS, server configuration or operational readiness. +GitHub Actions may remain blocked by account billing even when local checks pass. Resolve that account state and pass the configured PHP/database/build/consumer jobs before treating remote validation as complete. No independent security certification or production deployment is implied by the release tag. diff --git a/docs/faq.md b/docs/faq.md index b1a571b..92b2176 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -1,418 +1,35 @@ -# Frequently Asked Questions (FAQ) +# Frequently asked questions -Comprehensive answers to common questions about LaraCoreKit. +## Is this only an admin panel? ---- +No. The package provides a public Livewire frontend and a Filament admin workspace, with shared users, roles, blog, settings and media. -## General Questions +## Should I clone GitHub or install with Composer? -### What is LaraCoreKit? +Install `programmernomad/laracorekit:"^0.1"` from Packagist in a fresh Laravel application for your product. Clone the full repository to run the demo website, docs and showcase or contribute. GitHub dev-main is for testing unreleased changes. -LaraCoreKit is a modular Laravel 13 starter kit that provides a feature-rich foundation for building admin-driven and content-driven applications. It combines Filament 5 (admin panel), Livewire 4 (dynamic frontend), and Tailwind 4 (styling) with built-in modules for auth, blog, media, settings, multilingual support, and RTL layouts. +For Composer, first run `composer create-project laravel/laravel my-app "^13.0"` and enter `my-app`. Requiring the core and running its installer alone do not finish setup: configure the database, migrate and create an administrator. A GitHub clone already contains Laravel, but still needs environment setup and asset builds. Follow the [complete installation commands](/docs/installation) for your chosen path. -### Is LaraCoreKit free? +## Does Composer install the demo too? -Yes, 100% free and open-source under the MIT license. You can use it for personal projects, commercial projects, and client work without any restrictions. +No. The package has no dependency on the demo module, marketing website, Docs module or UIShowcase module. Its own Laravel/Filament dependencies still need to be downloaded. -### Who maintains LaraCoreKit? +## Can I update my application later? -Created and maintained by Shiv Singh (ProgrammerNomad) and the open-source community. It is a community-driven project. +Yes, package code can be updated through Composer. Your application code and view overrides stay outside vendor. Read release notes, back up data and test migrations in staging. Before 1.0, pin a tested minor release series. -### Is LaraCoreKit production-ready? +## Can I add it to an existing application? -LaraCoreKit is actively developed with quality assurance tools (tests, code formatting, static analysis). As a newer project, we recommend thorough testing before production deployment. +The initial supported path is a fresh Laravel 13 application. Existing authentication models, route names, tables and Modules namespaces require compatibility review. The installer does not resolve those conflicts automatically. -### What are the system requirements? +## Is everything advertised implemented? -- PHP 8.3 or higher -- Composer 2.x -- Node.js 18.x or higher -- MySQL 8.0+, PostgreSQL 13+, or SQLite 3.x -- 512MB RAM minimum (2GB+ recommended) +The installation and introduction pages list the implemented scope. API tokens, email-verification enforcement, billing, tenancy and a module marketplace are not bundled. There is no claim of a completed independent security audit. ---- +## Are installations tracked? -## Installation & Setup +No telemetry or registration is required. Packagist downloads indicate distribution activity, but cannot identify developers or count unique active installations. -### I get "Class not found" errors +## Can AI tools read the documentation? -```bash -composer dump-autoload -php artisan optimize:clear -``` - -### Migration fails with database connection error - -1. Check `.env` database credentials -2. Ensure database server is running -3. For MySQL, create database: `CREATE DATABASE laracorekit;` - -### Vite build fails with Node.js errors - -```bash -rm -rf node_modules package-lock.json -npm install --legacy-peer-deps -npm run build -``` - -### White screen after installation - -Check: -- `.env` file exists and configured -- Storage permissions: `chmod -R 755 storage bootstrap/cache` -- Run `php artisan config:clear` -- Check `storage/logs/laravel.log` - ---- - -## Features - -### Does it include a blog? - -Yes! Full blog module with multilingual posts, rich text editor, SEO fields, draft/published states, Filament admin, and Livewire frontend. - -### Does it support e-commerce? - -UI components are included, but no full e-commerce module yet. Planned as future addon module. - -### Does it have payment integration? - -No, payment systems are planned as separate addon modules (Stripe, Razorpay, PayPal). - -### Can I build a SaaS with this? - -Partially. Includes foundation (auth, admin, roles/permissions, API), but lacks subscription billing and multi-tenancy. These are planned as addon modules. - -### How many languages are included? - -Three: English, Hindi, and Arabic. Easy to add more via JSON translation files. - -### What's included in the 175+ components? - -Typography, Buttons, Forms, Navigation, Layouts, Data Display, Feedback, Charts, Media, Auth, E-commerce, and Advanced components. - ---- - -## Modules - -### Can I remove modules I don't need? - -Yes! Each module is self-contained. To remove: -1. Delete module directory -2. Remove service provider from `bootstrap/providers.php` -3. Remove module routes -4. Update tests - -### Can I disable a built-in module? - -Set `enabled => false` in `config/modules.php`, then run `php artisan optimize:clear`. - -### Can I create my own modules? - -Yes! See [Module Development Guide](https://www.laracorekit.com/docs/contributing/module-development). - -### I added a new module but routes aren't loading - -1. Add to `config/modules.php` with `enabled => true` -2. Add namespace to `composer.json` autoload psr-4 -3. Run `composer dump-autoload && php artisan optimize:clear` - ---- - -## Admin Panel - -### I can't log into the admin panel - -Create admin user: -```bash -php artisan filament:user -``` - -### How do I change the admin URL? - -Edit `app/Providers/Filament/AdminPanelProvider.php`: -```php -->path('dashboard') // Changes /admin to /dashboard -``` - -### Where are Filament admin resources? - -Inside each module: `modules/{Module}/src/Filament/Resources/` - -### Filament admin not loading - -Check: -- Admin user created -- Assets published: `php artisan filament:assets` -- Clear cache: `php artisan cache:clear` - ---- - -## Customization - -### Can I change the design/styling? - -Yes! Edit `tailwind.config.js`, modify Blade templates, add custom CSS in `resources/css/app.css`, then run `npm run build`. - -### Can I use Bootstrap instead of Tailwind? - -Not recommended. Entire UI built with Tailwind. Switching requires rewriting all templates. - -### Can I use Inertia instead of Livewire? - -Not easily. Livewire deeply integrated. Consider Laravel Breeze with Inertia for that preference. - -### Can I customize UI components? - -Yes! Edit directly in `modules/*/views/`, extend with your variants, or replace entirely. - ---- - -## Multilingual & RTL - -### How does multilingual content work? - -Two approaches: -1. **Static text** - JSON files in `lang/` directories -2. **Database content** - JSON columns for translatable fields - -### How do I add a new language? - -1. Add `lang/fr.json` -2. Add to each module: `modules/*/lang/fr.json` -3. Update language switcher -4. Add to `config/app.php` supported locales - -### How does RTL support work? - -- Locale middleware detects Arabic/Hebrew -- Tailwind RTL plugin handles layout mirroring -- Use `rtl:` prefix for custom RTL styles - -### Can I make the site RTL by default? - -Set default locale in `config/app.php`: -```php -'locale' => 'ar', -``` - ---- - -## Development - -### How do I run tests? - -```bash -php artisan test -# Or -composer test -``` - -### How do I check code quality? - -```bash -composer review # Runs all checks -# Or individually: -composer pint # Format code -composer pint-test # Check style -composer phpstan # Static analysis -``` - -### How do I enable debug mode? - -Edit `.env`: -```env -APP_DEBUG=true -APP_ENV=local -``` -Never enable in production! - -### I updated a view but see old content - -```bash -php artisan view:clear -``` - -### How do I see SQL queries? - -Install Laravel Telescope: -```bash -composer require laravel/telescope --dev -php artisan telescope:install -php artisan migrate -``` -Visit `/telescope` - ---- - -## Deployment - -### Can I deploy to shared hosting? - -Yes, but requires PHP 8.3+, Composer, Node.js, and SSH. Modern platforms (Forge, Vapor, DigitalOcean) recommended. - -### Does it work with Docker? - -Yes! Works with Laravel Sail or custom Docker setups: -```bash -composer require laravel/sail --dev -php artisan sail:install -./vendor/bin/sail up -``` - -### Does it work with Laravel Forge/Vapor? - -Yes! Standard Laravel application compatible with all Laravel deployment tools. - -### How do I set up queues? - -Configure in `.env`: -```env -QUEUE_CONNECTION=database -``` - -Run: -```bash -php artisan queue:table -php artisan migrate -php artisan queue:work -``` - -For production, use Supervisor. - ---- - -## Performance & Security - -### How do I speed up my app? - -```bash -php artisan optimize # Cache everything -``` - -Use Redis for cache/sessions/queues in `.env`: -```env -CACHE_DRIVER=redis -SESSION_DRIVER=redis -QUEUE_CONNECTION=redis -``` - -### Is LaraCoreKit secure? - -Includes: CSRF protection, XSS protection, SQL injection protection, password hashing, rate limiting, Sanctum API auth, and RBAC. - -### How do I report security vulnerabilities? - -Use GitHub Security Advisories (recommended): -- https://github.com/ProgrammerNomad/LaraCoreKit/security/advisories/new - -Or contact the repository owner directly through GitHub. See [Security Policy](SECURITY.md) for full details. - -**Do not create public issues for security vulnerabilities.** - -### Is it GDPR compliant? - -Provides tools (data export, deletion) but compliance is your responsibility. Consult legal counsel. - ---- - -## Comparisons - -### LaraCoreKit vs Laravel Breeze? - -- Breeze: Minimal auth only -- LaraCoreKit: Full starter with admin, blog, media, settings - -Use Breeze for minimal auth, LaraCoreKit for complete foundation. - -### LaraCoreKit vs Laravel Jetstream? - -- Jetstream: Auth + teams + 2FA + API -- LaraCoreKit: Auth + admin + blog + media + multilingual - -Different focus: Jetstream on auth, LaraCoreKit on content management. - -### LaraCoreKit vs Filament? - -- Filament: Admin panel framework -- LaraCoreKit: Complete starter using Filament - -LaraCoreKit includes Filament plus frontend, modules, multilingual. - -See detailed comparisons: -- [LaraCoreKit vs Larament](comparisons/laracorekit-vs-larament.md) -- [LaraCoreKit vs Official Livewire Starter](comparisons/laracorekit-vs-livewire-starter.md) - ---- - -## Troubleshooting - -### Images not displaying - -Check: -- Storage linked: `php artisan storage:link` -- Permissions: `chmod -R 755 storage` -- Config: `config/filesystems.php` -- APP_URL in `.env` - -### Dark mode not working - -Add to `` tag: -```blade - -``` - -Or toggle with Alpine.js: -```javascript -document.documentElement.classList.toggle('dark'); -``` - ---- - -## Support - -### Where can I get help? - -- **Documentation:** https://www.laracorekit.com/docs -- **GitHub Issues:** https://github.com/ProgrammerNomad/LaraCoreKit/issues -- **Discussions:** https://github.com/ProgrammerNomad/LaraCoreKit/discussions - -### How do I report bugs? - -Use [Bug Report template](https://github.com/ProgrammerNomad/LaraCoreKit/issues/new?template=bug_report.md) with Laravel version, PHP version, steps to reproduce, and error logs. - -### Can I contribute? - -Yes! See [Contributing Guide](CONTRIBUTING.md). Fix bugs, add features, improve docs, write tests, or help in discussions. - -### Is there paid support? - -Not currently. Community support is available via GitHub Discussions and Issues. See [Support section in README](../README.md#support). - ---- - -## License - -### Can I use this for client projects? - -Yes! MIT license allows commercial use without restriction. - -### Do I need to credit LaraCoreKit? - -Not required, but appreciated! Only requirement is including the license file. - -### Can I sell products built with LaraCoreKit? - -Yes! MIT license allows commercial products. - -### Can I create paid themes/modules? - -Yes! Create and sell extensions for LaraCoreKit. - ---- - -**Don't see your question?** - -Search [GitHub Issues](https://github.com/ProgrammerNomad/LaraCoreKit/issues) or ask in [Discussions](https://github.com/ProgrammerNomad/LaraCoreKit/discussions). - -Last updated: April 22, 2026 +Documentation is server-rendered HTML with stable links and a plain-text index at `/llms.txt`. Markdown source is available under `/docs-source/{page}`. These formats help tools retrieve accurate information; they do not guarantee search rankings or recommendations. diff --git a/docs/features/authentication.md b/docs/features/authentication.md index a89db6b..e06b817 100644 --- a/docs/features/authentication.md +++ b/docs/features/authentication.md @@ -1,202 +1,11 @@ -# Features: Authentication +# Authentication ---- -**Supported Stack:** Laravel 13 / Filament 5 / Livewire 4 / Tailwind 4 -**Module Status:** Core -**Last Updated:** April 22, 2026 -**Source Files:** [Auth Module](../../modules/Auth/) | [Login Component](../../modules/Auth/views/livewire/login.blade.php) ---- +The Auth module implements session login, optional public registration, logout, password recovery and an authenticated account dashboard using Livewire. It is custom application code, not an installed Breeze scaffold. Sanctum API tokens and email-verification enforcement are not implemented. -LaraCoreKit's Auth module provides a complete, production-ready authentication system built on **Laravel Breeze** with added enhancements for multilingual support, admin integration, and API token management. +Routes: `/login`, `/forgot-password`, `/reset-password/{token}`, `/dashboard` and POST `/logout`. `/register` exists only when `laracorekit.registration` is enabled. Form submission uses Livewire actions, not standalone POST login/register controllers. ---- +Login failures are limited per normalized email/IP and per IP. Successful login regenerates the session and clears the account counter. Registration and reset requests are rate limited. Configure a shared cache in multi-server deployments and working mail transport for password recovery. -## What's Included - -| Feature | Status | -|---------|--------| -| Login / Register | | -| Email Verification | | -| Password Reset | | -| Remember Me | | -| Sanctum API Tokens | | -| Filament Admin Auth | | -| Multilingual Forms | | - ---- - -## Module Location - -``` -modules/Auth/ -├── src/ -│ ├── AuthServiceProvider.php -│ └── Http/ -│ └── Livewire/ -│ ├── Login.php -│ ├── Register.php -│ └── ForgotPassword.php -├── views/ -│ └── auth/ -│ ├── login.blade.php -│ └── register.blade.php -└── routes/ - └── web.php -``` - ---- - -## Routes - -The Auth module registers these routes automatically: - -```php -GET /login → Auth\Login -POST /login → Auth\Login (Livewire action) -GET /register → Auth\Register -POST /register → Auth\Register (Livewire action) -GET /forgot-password → Auth\ForgotPassword -POST /forgot-password → Email password reset link -GET /reset-password/{token} -POST /logout -GET /email/verify -GET /email/verify/{id}/{hash} -``` - ---- - -## Login Component - -The `Login` Livewire component handles authentication: - -```php -namespace Modules\Auth\Http\Livewire; - -use Livewire\Component; -use Illuminate\Support\Facades\Auth; - -class Login extends Component -{ - public string $email = ''; - public string $password = ''; - public bool $remember = false; - - public function login() - { - $this->validate([ - 'email' => 'required|email', - 'password' => 'required|min:6', - ]); - - if (!Auth::attempt(['email' => $this->email, 'password' => $this->password], $this->remember)) { - $this->addError('email', __('auth.failed')); - return; - } - - redirect()->intended('/dashboard'); - } -} -``` - ---- - -## Protecting Routes - -Use standard Laravel middleware to protect routes: - -```php -// In any module's routes/web.php -Route::middleware(['auth'])->group(function () { - Route::get('/dashboard', DashboardPage::class)->name('dashboard'); -}); - -// Verify email -Route::middleware(['auth', 'verified'])->group(function () { - Route::get('/profile', ProfilePage::class)->name('profile'); -}); -``` - ---- - -## Admin Authentication - -Filament admin authentication is handled separately. Admin users must be explicitly created: - -```bash -php artisan filament:user -``` - -Under the hood, Filament checks `canAccessFilament()` on the User model via a Filament Panel configuration in `app/Providers/Filament/AdminPanelProvider.php`. - ---- - -## Email Verification - -Enable email verification by implementing `MustVerifyEmail` on the User model: - -```php -use Illuminate\Contracts\Auth\MustVerifyEmail; - -class User extends Authenticatable implements MustVerifyEmail -{ - // ... -} -``` - -Configure your mail settings in `.env`: - -```env -MAIL_MAILER=smtp -MAIL_HOST=smtp.mailgun.org -MAIL_PORT=587 -MAIL_USERNAME=your@mailgun.org -MAIL_PASSWORD=secret -MAIL_FROM_ADDRESS=noreply@laracorekit.com -``` - ---- - -## Sanctum API Tokens - -For API authentication, Sanctum is pre-configured: - -```php -// Create a token for the authenticated user -$token = $user->createToken('my-app')->plainTextToken; - -// Revoke all tokens -$user->tokens()->delete(); -``` - -API routes should use: - -```php -Route::middleware('auth:sanctum')->get('/user', function (Request $request) { - return $request->user(); -}); -``` - ---- - -## Customization - -### Custom Login Redirect - -Override the `redirectTo` property in the Login component: - -```php -protected string $redirectTo = '/dashboard'; -``` - -### Custom Guards - -Add a new guard in `config/auth.php` and create a corresponding provider. - ---- - -## Next Steps - -**[Users & Profiles →](users)** - -Learn how to manage user profiles, avatars, and extended user data. +Registration creates an ordinary User role and redirects to the account dashboard. Administrative access requires the appropriate role and resource permissions. Create administrators with `php artisan laracorekit:admin`. +See [installation](/docs/installation) and [package architecture](/docs/core/architecture). diff --git a/docs/features/blog.md b/docs/features/blog.md index 2c00a13..3f1f98d 100644 --- a/docs/features/blog.md +++ b/docs/features/blog.md @@ -1,139 +1,9 @@ -# Blog System +# Blog ---- -**Supported Stack:** Laravel 13 / Filament 5 / Livewire 4 / Tailwind 4 -**Module Status:** Core -**Last Updated:** April 22, 2026 -**Source Files:** [BlogResource](../../modules/Blog/src/Filament/Resources/BlogResource.php) | [Routes](../../modules/Blog/routes/web.php) | [Post Model](../../modules/Blog/src/Models/Post.php) ---- +Blog supports JSON translations for titles, excerpts, content, categories and metadata, unique slugs, authors, draft/published/archived status, featured posts, publication timestamps and soft deletion. -The Blog module in LaraCoreKit provides a fully multilingual blog system with SEO-friendly slugs, categories, and Filament admin integration. +Public routes are `/blog` and `/blog/{slug}`. The published scope requires published status and a publication time at or before now, so future-dated posts and drafts remain private. Blog HTML is sanitized before public rendering. The list includes search, categories and pagination; related-post filtering uses Laravel JSON queries rather than MySQL-specific raw SQL. ---- +Filament BlogResource provides authoring and permission checks. Featured-image and gallery attachments use Media Library. Configure storage and workers for the media operations you enable. Blog depends on User and Media. -## Features - -- Multilingual posts (EN, HI, AR) -- SEO-friendly slugs -- Categories and tags -- Featured images via Media Library -- Draft/Published status -- Author attribution -- Filament admin CRUD - ---- - -## Routes - -``` -GET /blog → BlogList (Livewire) -GET /blog/{slug} → BlogDetail (Livewire) -GET /admin/posts → Filament admin -``` - ---- - -## Post Model - -```php -namespace Modules\Blog\Models; - -use Illuminate\Database\Eloquent\Model; -use Spatie\MediaLibrary\HasMedia; -use Spatie\MediaLibrary\InteractsWithMedia; - -class Post extends Model implements HasMedia -{ - use InteractsWithMedia; - - protected $fillable = [ - 'title', 'slug', 'content', 'excerpt', - 'status', 'locale', 'author_id', 'published_at', - ]; - - public function scopePublished($query) - { - return $query->where('status', 'published'); - } - - public function scopeLocale($query, string $locale) - { - return $query->where('locale', $locale); - } -} -``` - ---- - -## Creating a Post Programmatically - -```php -use Modules\Blog\Models\Post; - -Post::create([ - 'title' => 'Getting Started with LaraCoreKit', - 'slug' => 'getting-started-with-laracorekit', - 'content' => '...', - 'excerpt' => 'A short summary of the post.', - 'status' => 'published', - 'locale' => 'en', - 'published_at' => now(), -]); -``` - ---- - -## Displaying Posts in Blade - -```blade -@foreach($posts as $post) -
-

{{ $post->title }}

-

{{ $post->excerpt }}

- Read more → -
-@endforeach -``` - ---- - -## Blog in Multiple Languages - -Filter posts by locale: - -```php -$posts = Post::published()->locale(app()->getLocale())->latest()->paginate(12); -``` - ---- - -## Admin Panel - -Navigate to `/admin/posts` to: -- Create, edit, delete posts -- Set status (Draft/Published) -- Upload featured images -- Set SEO metadata - ---- - -## Customizing the Blog - -Add a new field to posts: - -```php -// In migration -$table->string('reading_time')->nullable(); - -// In model $fillable -'reading_time', - -// In Filament resource schema -TextInput::make('reading_time')->suffix('min'), -``` - ---- - -## Next Steps - -**[Media Management →](media)** +See [installation](/docs/installation) and [package architecture](/docs/core/architecture). diff --git a/docs/features/media.md b/docs/features/media.md index 7d0437f..9bb7875 100644 --- a/docs/features/media.md +++ b/docs/features/media.md @@ -1,138 +1,9 @@ -# Media Management +# Media attachments ---- -**Supported Stack:** Laravel 13 / Filament 5 / Livewire 4 / Tailwind 4 -**Module Status:** Core -**Last Updated:** April 22, 2026 -**Source Files:** [Media Module](../../modules/Media/) | [MediaResource](../../modules/Media/src/Filament/Resources/MediaResource.php) ---- +The package requires Spatie Laravel Media Library and registers its media-table migration. Blog implements Media Library's HasMedia contract, with `featured_image` as a single-file collection and a `gallery` collection. -LaraCoreKit uses **Spatie Laravel MediaLibrary** for file uploads, image optimization, and media management. - ---- - -## Features - -- Upload any file type -- Automatic image conversions (thumbnails, etc.) -- Store locally or on S3 -- Admin media browser -- Associate media with any Eloquent model - ---- - -## Setup - -Add `HasMedia` and `InteractsWithMedia` to any model: - -```php -use Spatie\MediaLibrary\HasMedia; -use Spatie\MediaLibrary\InteractsWithMedia; - -class Post extends Model implements HasMedia -{ - use InteractsWithMedia; - - public function registerMediaCollections(): void - { - $this->addMediaCollection('cover') - ->singleFile() // Only one cover per post - ->acceptsMimeTypes(['image/jpeg', 'image/png', 'image/webp']); - } - - public function registerMediaConversions(Media $media = null): void - { - $this->addMediaConversion('thumb') - ->width(400) - ->height(300) - ->sharpen(10); - - $this->addMediaConversion('og') - ->width(1200) - ->height(630); - } -} -``` - ---- - -## Uploading Files - -### From Request (controller/Livewire) - -```php -// Upload from file upload -$post->addMediaFromRequest('cover_image') - ->toMediaCollection('cover'); - -// Upload from URL -$post->addMediaFromUrl('https://www.laracorekit.com/image.jpg') - ->toMediaCollection('cover'); - -// Upload from existing file path -$post->addMedia('/path/to/file.jpg') - ->toMediaCollection('cover'); -``` - ---- - -## Retrieving Media - -```php -// Get first media URL -$coverUrl = $post->getFirstMediaUrl('cover'); - -// Get thumbnail conversion -$thumbUrl = $post->getFirstMediaUrl('cover', 'thumb'); - -// Get all media -$allImages = $post->getMedia('images'); - -// Check if media exists -if ($post->hasMedia('cover')) { - // ... -} -``` - ---- - -## In Blade Templates - -```blade -{{ $post->title }} -``` - ---- - -## Admin Media Library - -Access the media browser at `/admin/media` to: -- Browse all uploaded files -- Delete unused media -- Preview images - ---- - -## Storage Configuration - -For production, use S3: - -```env -FILESYSTEM_DISK=s3 -AWS_ACCESS_KEY_ID=your-key -AWS_SECRET_ACCESS_KEY=your-secret -AWS_DEFAULT_REGION=us-east-1 -AWS_BUCKET=your-bucket -``` - ---- - -## Next Steps - -**[Settings →](settings)** +The Media module supplies infrastructure, not a standalone `/admin/media` library resource. Automatic thumbnails, a full media browser and storage-specific configuration should not be assumed. Configure permitted file types, size limits, storage and queue behavior for your application, and test uploads before deployment. +Run `php artisan storage:link` when using public local storage. S3 requires your own disk configuration and credentials. The demo's reset behavior is separate from this module. +See [installation](/docs/installation) and [package architecture](/docs/core/architecture). diff --git a/docs/features/multilingual.md b/docs/features/multilingual.md index 0ca7365..f5fe5bf 100644 --- a/docs/features/multilingual.md +++ b/docs/features/multilingual.md @@ -1,131 +1,9 @@ -# Multilingual Support +# Multilingual content ---- -**Supported Stack:** Laravel 13 / Filament 5 / Livewire 4 / Tailwind 4 -**Module Status:** Core -**Last Updated:** April 22, 2026 -**Source Files:** [LocaleSwitcher](../../modules/Core/src/Http/Livewire/LocaleSwitcher.php) | [Middleware](../../modules/Core/src/Http/Middleware/SetLocale.php) ---- +English, Hindi and Arabic are the default locale choices. Core supplies language switching and locale middleware, while package JSON translations provide interface text. Blog/settings fields can store language-keyed JSON values. -LaraCoreKit ships with multilingual support for **English**, **Hindi**, and **Arabic** out of the box, including automatic RTL layout switching for Arabic. +The session locale is checked against configured supported locales before application locale is changed. The locale switch returns to the application's root. Content views generally fall back to English when a field translation is missing. ---- +Adding a language requires configuring its locale, labels, JSON translations and any content/form fields your application needs. The demo marketing copy may fall back to English; supported locale selection does not imply every site paragraph is translated. -## Supported Languages - -| Code | Language | Direction | Flag | -|------|----------|-----------|------| -| `en` | English | LTR | | -| `hi` | Hindi | LTR | | -| `ar` | Arabic | RTL | | - ---- - -## Locale Switcher - -The `LocaleSwitcher` Livewire component (Core module) handles language switching: - -```blade -@livewire('locale-switcher') -``` - -It stores the selected locale in the session and redirects back with the new locale active. - -**Component:** `modules/Core/src/Http/Livewire/LocaleSwitcher.php` - ---- - -## Translation Files - -### JSON translations (recommended for UI strings) - -``` -lang/ -├── en.json -├── hi.json -└── ar.json -``` - -```json -// lang/hi.json -{ - "Welcome": "स्वागत है", - "Log in": "लॉग इन करें", - "Register": "पंजीकरण करें" -} -``` - -### PHP translation files (for organized namespaced strings) - -```php -// lang/hi/auth.php -return [ - 'failed' => 'प्रमाण-पत्र इनमें से किसी से मेल नहीं खाते।', - 'throttle' => 'बहुत अधिक लॉगिन प्रयास।', -]; -``` - ---- - -## Using Translations in Blade - -```blade -{{ __('Welcome') }} -{{ __('Hello, :name!', ['name' => $user->name]) }} -@lang('auth.failed') -``` - ---- - -## Using Translations in PHP - -```php -__('Welcome'); -trans('auth.failed'); -app()->getLocale(); // 'en', 'hi', 'ar' -``` - ---- - -## Detecting Current Locale - -```php -$locale = app()->getLocale(); -$isRTL = in_array($locale, ['ar']); -``` - ---- - -## Adding a New Language - -1. Create `lang/{locale}.json` with translations: - -```json -// lang/fr.json -{ - "Welcome": "Bienvenue", - "Log in": "Se connecter" -} -``` - -2. Add to the locale switcher options in `CoreServiceProvider.php` - -3. If it's RTL, add to the RTL detection in your layout - ---- - -## SEO with Multilingual - -Use `hreflang` tags for multilingual SEO: - -```blade - - - -``` - ---- - -## Next Steps - -**[RTL Support →](rtl-support)** +See [installation](/docs/installation) and [package architecture](/docs/core/architecture). diff --git a/docs/features/roles-permissions.md b/docs/features/roles-permissions.md index dc83cb8..25355bb 100644 --- a/docs/features/roles-permissions.md +++ b/docs/features/roles-permissions.md @@ -1,136 +1,9 @@ -# Roles & Permissions +# Roles and permissions ---- -**Supported Stack:** Laravel 13 / Filament 5 / Livewire 4 / Tailwind 4 -**Module Status:** Core -**Last Updated:** April 22, 2026 -**Source Files:** [RoleResource](../../modules/User/src/Filament/Resources/RoleResource.php) | [Config](../../config/permission.php) ---- +Spatie Laravel Permission supplies authorization. `RolePermissionSeeder` creates Admin, Editor and User roles with permissions for user/role management, blog actions, settings and media-related operations. It never promotes a user based on a well-known email address. -LaraCoreKit uses **Spatie Laravel Permission** for role-based access control (RBAC), pre-configured and seeded with sensible defaults. +The User model permits Admin and Editor roles into the panel. Resources additionally check the relevant permissions for viewing, creating, editing and deleting records; entering the panel does not grant access to every resource. Settings saves check `edit-settings`. Blog publication checks `publish-blog`. ---- +Default editors can author and publish blog content but cannot manage users or roles. Test custom roles and direct resource URLs when extending authorization. Do not treat hidden navigation items as a security boundary. -## Default Roles - -| Role | Description | -|------|-------------| -| `super-admin` | Full access to everything | -| `admin` | Access to admin panel | -| `editor` | Can manage blog content | -| `user` | Standard registered user | - ---- - -## Default Permissions - -| Permission | Description | -|-----------|-------------| -| `view users` | List all users | -| `edit users` | Update user profiles | -| `delete users` | Remove users | -| `manage posts` | Full blog post access | -| `manage settings` | Change site configuration | - ---- - -## Assigning Roles - -```php -// Assign a single role -$user->assignRole('editor'); - -// Assign multiple roles -$user->assignRole('editor', 'user'); - -// Sync roles (removes old ones) -$user->syncRoles(['editor', 'user']); - -// Remove a role -$user->removeRole('editor'); -``` - ---- - -## Checking Roles & Permissions - -```php -// Check role -$user->hasRole('admin'); -$user->hasAnyRole(['admin', 'super-admin']); -$user->hasAllRoles(['admin', 'editor']); - -// Check permission -$user->can('edit posts'); -$user->hasPermissionTo('delete users'); - -// Via Gate facade -Gate::allows('manage posts'); -``` - ---- - -## In Blade Templates - -```blade -@role('admin') - Admin Panel -@endrole - -@can('edit posts') - Edit Post -@endcan - -@hasanyrole('admin|editor') - {{-- Admin or editor content --}} -@endhasanyrole -``` - ---- - -## In Middleware - -```php -// In routes -Route::middleware(['role:admin'])->group(function () { - Route::get('/admin', AdminDashboard::class); -}); - -Route::middleware(['permission:manage posts'])->group(function () { - Route::get('/posts/create', CreatePost::class); -}); -``` - ---- - -## Creating Custom Roles - -Via Seeder: - -```php -use Spatie\Permission\Models\Role; -use Spatie\Permission\Models\Permission; - -// Create role -$role = Role::create(['name' => 'moderator']); - -// Create permission -$permission = Permission::create(['name' => 'moderate comments']); - -// Assign permission to role -$role->givePermissionTo('moderate comments'); -``` - ---- - -## Admin Panel - -Manage roles and permissions from the Filament admin: -- `/admin/roles` - Create, edit, delete roles -- `/admin/users` - Assign roles to users - ---- - -## Next Steps - -**[Blog System →](blog)** +See [installation](/docs/installation) and [package architecture](/docs/core/architecture). diff --git a/docs/features/rtl-support.md b/docs/features/rtl-support.md index 8592a52..6caeb15 100644 --- a/docs/features/rtl-support.md +++ b/docs/features/rtl-support.md @@ -1,105 +1,7 @@ -# RTL Support +# Right-to-left layouts ---- -**Supported Stack:** Laravel 13 / Filament 5 / Livewire 4 / Tailwind 4 -**Module Status:** Core -**Last Updated:** April 22, 2026 ---- +The shared public layout sets `dir="rtl"` for Arabic and `ltr` otherwise. The website uses logical spacing where practical, and Filament supplies its own locale-aware interface. -LaraCoreKit automatically enables RTL (right-to-left) layout when the Arabic locale is active, without any additional setup required. +Test your custom views, dropdown alignment, tables and embedded widgets in Arabic. Direction switching does not translate text automatically. The component showcase contains examples rather than a guarantee that every third-party widget is RTL compatible. ---- - -## How It Works - -The layout detects the current locale and sets the HTML `dir` attribute automatically: - -```blade - -``` - -When `ar` locale is set, the entire page flips to RTL - text, navigation, sidebars, and all components. - ---- - -## TailwindCSS v4 RTL Classes - -TailwindCSS v4 supports RTL modifiers natively: - -```html - -
- Content with direction-aware alignment -
- - -
- Direction-aware margin -
- - -
- Items reverse in RTL -
-``` - ---- - -## Adding a New RTL Language - -For example, adding Urdu (`ur`): - -### Step 1: Create translations - -``` -lang/ur.json -lang/ur/auth.php -``` - -### Step 2: Add to RTL locales - -In your layout file, add `'ur'` to the RTL array: - -```blade - -``` - -### Step 3: Add to locale switcher - -In `modules/Core/src/Http/Livewire/LocaleSwitcher.php`: - -```php -protected array $locales = [ - 'en' => 'English', - 'hi' => 'हिन्दी', - 'ar' => 'العربية', - 'ur' => 'اردو', // Add this -]; -``` - ---- - -## Testing RTL - -Switch to Arabic locale: - -``` -http://localhost:8000?locale=ar -``` - -You should see the entire layout mirror to right-to-left. - ---- - -## Filament RTL - -Filament 5 also supports RTL. It auto-detects from the `` attribute. - ---- - -## Next Steps - -**[Admin Panel Overview →](../admin/filament-overview)** +See [installation](/docs/installation) and [package architecture](/docs/core/architecture). diff --git a/docs/features/settings.md b/docs/features/settings.md index a454d30..71c2285 100644 --- a/docs/features/settings.md +++ b/docs/features/settings.md @@ -1,106 +1,9 @@ -# Settings +# Site settings ---- -**Supported Stack:** Laravel 13 / Filament 5 / Livewire 4 / Tailwind 4 -**Module Status:** Core -**Last Updated:** April 22, 2026 -**Source Files:** [Settings Module](../../modules/Settings/) | [Setting Model](../../modules/Settings/src/Models/Setting.php) ---- +Settings stores key/value data with JSON values, type metadata and translatable fields. Its Filament page edits site identity, contact details, footer and SEO fields. Loading the page requires `view-settings`; saving requires `edit-settings`. -The Settings module provides a centralized key-value store for site-wide configuration, fully managed from the Filament admin panel. +The model provides `Setting::get($key, $default)` and `Setting::set($key, $value)`. The page caches individual settings and invalidates affected keys when saving rather than clearing the application's entire cache. ---- +The package does not seed the demo's brand/contact information into customer applications. Configure your own defaults. Keep secrets in appropriate environment/secret storage rather than publicly rendered settings. -## Default Settings - -| Key | Default | Description | -|-----|---------|-------------| -| `site_name` | LaraCoreKit | Site display name | -| `site_description` | - | Meta description | -| `default_locale` | `en` | Default language | -| `maintenance_mode` | `false` | Maintenance toggle | -| `logo` | - | Site logo path | -| `social_twitter` | - | Twitter/X URL | -| `social_github` | - | GitHub URL | - ---- - -## Reading Settings - -```php -use Modules\Settings\Models\Setting; - -// Get a value with default -$siteName = Setting::get('site_name', 'LaraCoreKit'); - -// Get all settings as key-value array -$all = Setting::getAll(); -``` - ---- - -## Writing Settings - -```php -// Set a single setting -Setting::set('site_name', 'My Awesome App'); - -// Set multiple at once -Setting::setMany([ - 'site_name' => 'My App', - 'site_description' => 'A great Laravel app', -]); -``` - ---- - -## In Blade Templates - -Settings are auto-shared as a view global: - -```blade -{{ setting('site_name', 'LaraCoreKit') }} - -``` - ---- - -## Admin Panel - -All settings are editable at `/admin/settings` - no code changes needed. - -The settings admin shows a clean form UI generated from the settings schema. - ---- - -## Adding a Custom Setting - -1. Add to the Settings seeder: - -```php -Setting::firstOrCreate(['key' => 'custom_key'], ['value' => 'default_value']); -``` - -2. Run the seeder: - -```bash -php artisan db:seed --class=Modules\\Settings\\Database\\Seeders\\SettingsSeeder -``` - ---- - -## Caching Settings - -Settings are cached automatically. To clear the settings cache: - -```bash -php artisan cache:forget settings -# Or clear everything -php artisan optimize:clear -``` - ---- - -## Next Steps - -**[Multilingual →](multilingual)** +See [installation](/docs/installation) and [package architecture](/docs/core/architecture). diff --git a/docs/features/users.md b/docs/features/users.md index ea442d1..2dd4125 100644 --- a/docs/features/users.md +++ b/docs/features/users.md @@ -1,96 +1,9 @@ -# Users & Profiles +# Users and account dashboard ---- -**Supported Stack:** Laravel 13 / Filament 5 / Livewire 4 / Tailwind 4 -**Module Status:** Core -**Last Updated:** April 22, 2026 -**Source Files:** [User Model](../../modules/User/src/Models/User.php) | [User Resource](../../modules/User/src/Filament/Resources/UserResource.php) ---- +The packaged `Modules\User\Models\User` extends Laravel's authenticatable model and includes Spatie Permission roles, notifications and a package-specific factory. Passwords are hashed through a model cast; password and remember token are hidden from serialization. -The User module manages user profiles, avatars, and extended user data beyond the core `users` table. +The public dashboard displays account information. Filament provides user CRUD to authorized administrators. A complete self-service profile editor, avatar pipeline and enforced email-verification flow are not bundled. ---- - -## User Model - -The User model lives in `modules/User/src/Models/User.php` and extends Laravel's base Authenticatable. - -## Profile Fields - -| Field | Type | Description | -|-------|------|-------------| -| `name` | string | Display name | -| `email` | string | Unique email address | -| `avatar` | string (nullable) | Profile picture path | -| `bio` | text (nullable) | Short user biography | -| `locale` | string | Preferred language | - ---- - -## Working with Users - -```php -use Modules\User\Models\User; - -// Get all users -$users = User::all(); - -// Find by email -$user = User::where('email', 'john@laracorekit.com')->first(); - -// Update profile -$user->update(['name' => 'John Doe', 'bio' => 'Laravel developer']); -``` - ---- - -## Roles - -Roles are managed via Spatie Laravel Permission. Users can have multiple roles. - -```php -// Assign a role -$user->assignRole('editor'); - -// Check role -$user->hasRole('admin'); - -// Get all roles -$user->roles; -``` - ---- - -## Avatars - -Profile pictures are stored via Spatie MediaLibrary: - -```php -// Upload avatar -$user->addMediaFromRequest('avatar')->toMediaCollection('avatars'); - -// Get avatar URL -$avatarUrl = $user->getFirstMediaUrl('avatars'); -``` - -In Blade: -```blade -{{ $user->name }} -``` - ---- - -## Admin Management - -Users are managed at `/admin/users` in the Filament admin panel: -- View all registered users -- Assign/revoke roles -- Reset passwords -- View activity - ---- - -## Next Steps - -**[Roles & Permissions →](roles-permissions)** +The package uses Laravel's standard users table. Existing applications with a different auth model must plan integration before installing. Create the first administrator interactively; normal seeding creates roles without known accounts. +See [installation](/docs/installation) and [package architecture](/docs/core/architecture). diff --git a/docs/frontend/components.md b/docs/frontend/components.md index df2e71f..c25e88d 100644 --- a/docs/frontend/components.md +++ b/docs/frontend/components.md @@ -1,161 +1,9 @@ -# UI Components +# Frontend components -**Estimated time:** 8 minutes -**Difficulty:** Beginner +The reusable package includes its locale selector and public application views. The repository's UIShowcase contains additional interface examples for developers to explore; its routes and JavaScript dependencies are not bundled into the Composer package. ---- +Use showcase examples as starting points and adapt data, authorization, semantics, keyboard controls and responsive behavior for your application. An interface example is not a complete backend feature. -LaraCoreKit ships with **175+ ready-to-use UI components** built with TailwindCSS v4 and Livewire. Browse them all interactively at `/ui-showcase`. - ---- - -## Component Categories - -### Core UI -| Component | Usage | -|-----------|-------| -| Buttons | Primary, secondary, outline, ghost, icon, loading | -| Badges | Status, counter, label variants | -| Alerts | Success, warning, error, info with dismiss | -| Avatars | Sizes, with status, group | -| Spinners | Loading states for buttons and pages | - -### Forms -| Component | Usage | -|-----------|-------| -| Text Input | Standard, with icon, with error | -| Select | Native, searchable, multi-select | -| Textarea | Resizable with character count | -| Checkbox | Single, group | -| Radio | Button group style | -| Toggle | Switch component | -| File Upload | With drag-and-drop preview | - -### Layout -| Component | Usage | -|-----------|-------| -| Cards | Basic, profile, stats, bordered | -| Modals | Confirmation, form, full-screen | -| Drawers | Side panel sliding menu | -| Tabs | Horizontal, vertical | -| Accordion | Collapsible FAQ sections | - -### Navigation -| Component | Usage | -|-----------|-------| -| Navbar | Sticky, with search, mobile | -| Sidebar | Collapsible, with groups | -| Breadcrumbs | With icons, truncated | -| Pagination | Standard, compact, infinite scroll | - -### Data Display -| Component | Usage | -|-----------|-------| -| Tables | Sortable, filterable, with actions | -| Stats | Number cards, with trend | -| Progress | Bar, circular, step indicator | -| Timeline | Activity feed | -| Charts | Bar, line, doughnut (Alpine.js) | - ---- - -## Using Components - -### Blade Components (x-tags) - -```blade -{{-- Button --}} - - Save Changes - - - - Delete - - -{{-- Alert --}} - - Your changes have been saved successfully! - - -{{-- Card --}} - - - - -{{-- Badge --}} -Published -Draft -``` - -### Form Components - -```blade -
- - - - - - - - Save - Saving... - - -``` - ---- - -## Livewire Components - -Pre-built interactive components: - -```blade -{{-- Blog listing with search & pagination --}} -@livewire('blog.blog-list') - -{{-- Newsletter subscribe form --}} -@livewire('newsletter.subscribe') - -{{-- Locale switcher dropdown --}} -@livewire('locale-switcher') -``` - ---- - -## Dark Mode - -All components support dark mode automatically via TailwindCSS `dark:` variants. No extra configuration needed - just set `dark` class on ``. - ---- - -## Customizing Components - -Components are in `modules/UIShowcase/views/components/` and `resources/views/components/`. - -Override any component by publishing: - -```bash -php artisan vendor:publish --tag=laracorekit-components -``` - ---- - -## Next Steps - -**[Layout System →](layouts)** +Keep Chart.js, Sortable and Prism in the showcase bundle. Ordinary website pages load the smaller base bundle. Livewire supplies Alpine for both. +See [installation](/docs/installation) and [package architecture](/docs/core/architecture). diff --git a/docs/frontend/layouts.md b/docs/frontend/layouts.md index fbc7fcf..96a1f40 100644 --- a/docs/frontend/layouts.md +++ b/docs/frontend/layouts.md @@ -1,176 +1,9 @@ -# Layout System +# Shared layouts -**Estimated time:** 6 minutes -**Difficulty:** Beginner +The package's shared layout is `core::layouts.app`, loaded from its Core module. It provides a responsive page shell, stylesheet link, Livewire assets and navigation for enabled modules. ---- +Override individual templates under `resources/views/vendor/core`. The demo host overrides `layouts/app.blade.php` there with the website header, footer, theme controls and metadata. Host-only marketing copy does not ship in the package. -LaraCoreKit uses a modular layout system where each module can define its own layouts while sharing the core design tokens, navigation, and assets. +Auth, Blog and Settings views use their own namespaces and can be overridden under matching vendor-view directories. Review copied overrides when upgrading, since they do not automatically inherit package fixes. ---- - -## Core Layout - -The primary app layout lives in the Core module: - -``` -modules/Core/views/layouts/app.blade.php -``` - -```blade - - - - - - {{ $title ?? config('app.name') }} - @vite(['resources/css/app.css', 'resources/js/app.js']) - @livewireStyles - - - - {{-- Navigation --}} - - - {{-- Locale Switcher --}} - @livewire('locale-switcher') - - {{-- Page Content --}} -
- {{ $slot }} -
- - {{-- Footer --}} - - - @livewireScripts - - -``` - ---- - -## Extending the Layout - -### With Livewire full-page components - -```php -class BlogList extends Component -{ - public function render() - { - return view('blog::livewire.blog-list') - ->layout('core::layouts.app', [ - 'title' => 'Blog - ' . config('app.name'), - ]); - } -} -``` - -### With Blade extends - -```blade -@extends('core::layouts.app', ['title' => 'My Page']) - -@section('content') -

My page content

-@endsection -``` - ---- - -## Module-Specific Layouts - -Modules can define their own layouts: - -``` -modules/Blog/views/layouts/blog.blade.php -``` - -```blade -@extends('core::layouts.app') - -@section('content') -
- - -
- {{ $slot }} -
- - -
-@endsection -``` - ---- - -## Guest Layout (Auth Pages) - -``` -modules/Auth/views/layouts/guest.blade.php -``` - -A centered, minimal layout for login/register pages with no navigation. - ---- - -## Named Slots - -```blade -{{-- In the layout file --}} -
- {{ $header ?? '' }} -
- -
{{ $slot }}
- -
- {{ $footer ?? '' }} -
-``` - -```blade -{{-- When using the layout --}} - - -

Page Title

-
- -

Page content here

-
-``` - ---- - -## Asset Pipeline - -Assets are compiled with **Vite**: - -``` -resources/ -├── css/ -│ └── app.css ← Main CSS (TailwindCSS v4) -└── js/ - └── app.js ← Main JS (Alpine.js, Livewire) -``` - -Development: -```bash -npm run dev # Hot-reload -``` - -Production: -```bash -npm run build # Minified assets -``` - ---- - -## Next Steps - -**[UI Showcase →](ui-showcase)** +See [installation](/docs/installation) and [package architecture](/docs/core/architecture). diff --git a/docs/frontend/livewire.md b/docs/frontend/livewire.md index 9273103..d7ab7e6 100644 --- a/docs/frontend/livewire.md +++ b/docs/frontend/livewire.md @@ -1,226 +1,9 @@ -# Livewire Basics +# Livewire frontend -**Estimated time:** 10 minutes -**Difficulty:** Beginner +Public package pages use Livewire 4 components and the `core::layouts.app` layout. Auth components implement login, registration, password recovery and the account dashboard. Blog components implement the public list/detail pages. ---- +Components are registered by module providers with stable aliases. The demo Home and Changelog components live under `app/Livewire`, outside the package. Livewire bundles Alpine; do not load a second Alpine instance. -LaraCoreKit is built on **Livewire v4** - Laravel's full-stack component framework that lets you build dynamic, reactive UIs without writing JavaScript. - ---- - -## How Livewire Works - -Livewire components consist of: -1. A **PHP class** (holds state + handles actions) -2. A **Blade view** (renders the UI) - -When users interact, Livewire sends AJAX requests to the server, re-renders only the changed part, and updates the DOM with morphdom diffing. - ---- - -## A Simple Component - -### PHP Class - -```php -when($this->query, fn ($q) => - $q->where('title', 'like', "%{$this->query}%") - ) - ->latest() - ->take(10) - ->get(); - - return view('blog::livewire.blog-search', compact('posts')); - } -} -``` - -### Blade View - -```blade -
- - -
- Searching... -
- - -
-``` - ---- - -## Essential Wire Directives - -| Directive | What it does | -|-----------|-------------| -| `wire:click="method"` | Call a PHP method on click | -| `wire:model="property"` | Two-way bind an input to a property | -| `wire:model.live` | Bind and sync on every keystroke | -| `wire:model.blur` | Bind and sync on field blur | -| `wire:submit="method"` | Handle form submission | -| `wire:loading` | Show element during AJAX request | -| `wire:loading.remove` | Hide element during AJAX request | -| `wire:navigate` | SPA-style page navigation | -| `wire:confirm="message"` | Confirm dialog before action | - ---- - -## Form with Validation - -```php -class ContactForm extends Component -{ - public string $name = ''; - public string $email = ''; - public string $message = ''; - public bool $sent = false; - - protected $rules = [ - 'name' => 'required|min:2|max:100', - 'email' => 'required|email', - 'message' => 'required|min:10|max:2000', - ]; - - public function send(): void - { - $this->validate(); - - // Send email logic... - Mail::to('admin@laracorekit.com')->send(new ContactMail($this->all())); - - $this->reset(['name', 'email', 'message']); - $this->sent = true; - } -} -``` - -```blade -
- @if($sent) -
Message sent! We'll get back to you soon.
- @else -
- - @error('name') {{ $message }} @enderror - - - @error('email') {{ $message }} @enderror - - - @error('message') {{ $message }} @enderror - - -
- @endif -
-``` - ---- - -## Registering a Component - -In the module's ServiceProvider: - -```php -Livewire::component('blog.search', \Modules\Blog\Http\Livewire\BlogSearch::class); -``` - -Using in Blade: - -```blade -@livewire('blog.search') - -{{-- Or with props --}} -@livewire('blog.search', ['category' => 'tutorial']) - -{{-- Or as Blade component tag --}} - -``` - ---- - -## Lifecycle Hooks - -```php -class MyComponent extends Component -{ - public function mount(): void - { - // Runs once when component mounts - $this->loadData(); - } - - public function updated($property): void - { - // Runs after any property updates - } - - public function updatedQuery(): void - { - // Runs specifically when $query updates - $this->resetPage(); - } -} -``` - ---- - -## Pagination - -```php -use Livewire\WithPagination; - -class BlogList extends Component -{ - use WithPagination; - - public function render() - { - return view('blog::list', [ - 'posts' => Post::published()->paginate(12), - ]); - } -} -``` - ---- - -## Next Steps - -**[UI Components →](components)** +Treat public component methods as externally callable endpoints: validate inputs, authorize mutations and rate-limit abuse-sensitive operations. Test them with Livewire's component testing helpers. +See [installation](/docs/installation) and [package architecture](/docs/core/architecture). diff --git a/docs/frontend/ui-showcase.md b/docs/frontend/ui-showcase.md index 09865f0..385be2b 100644 --- a/docs/frontend/ui-showcase.md +++ b/docs/frontend/ui-showcase.md @@ -1,92 +1,9 @@ -# UI Showcase +# UI showcase -**Estimated time:** 5 minutes -**Difficulty:** Beginner +Visit `/ui-showcase` in the GitHub host to browse examples organized by category. Categories are defined in `modules/UIShowcase/config/components.php`; views and routes live in that module. ---- +The showcase is host-only. It does not imply that every demonstrated feature, including e-commerce or advanced charts, has an implemented application backend. Copy/adapt the examples you need into your own views. -The UI Showcase is an interactive, searchable gallery of all **175+ components** included in LaraCoreKit. It's the fastest way to explore what's available and copy-paste into your project. +The showcase has mobile navigation and theme switching. Its Chart.js, Sortable and Prism dependencies load through a separate Vite entry rather than on all public pages. ---- - -## Access the Showcase - -``` -http://localhost:8000/ui-showcase -``` - -**Live:** [www.laracorekit.com/ui-showcase](https://www.laracorekit.com/ui-showcase/) - ---- - -## What You'll Find - -### Interactive Previews -Every component renders live in the browser - dark mode, RTL, responsive - exactly as it will look in your app. - -### Copy-Paste Ready Code -Click **"Copy Code"** on any component to copy the Blade/Livewire markup. Paste into your views and it works. - -### Multiple Formats -Components shown in: -- **Blade** (x-component tags) -- **HTML/TailwindCSS** (raw markup) -- **Livewire** (wire:* directives) - ---- - -## Component Categories in Showcase - -``` -Core -├── Typography - Headings, body text, code -├── Buttons - All variants and sizes -├── Badges - Colors, sizes, pill vs square -└── Icons - Heroicons reference - -Forms -├── Inputs - Text, email, password, number -├── Selects - Dropdown, multi-select -├── Textareas - Plain and with character count -├── Checkboxes - Single and group -├── Radios - Button group style -├── Toggles - Switch style -└── File Upload - Drag & drop, image preview - -Layout -├── Cards - Basic, profile, stats -├── Modals - Confirmation, form modal -├── Drawers - Slide-in panels -├── Tabs - Horizontal tabs -└── Accordion - Collapsible FAQ - -Navigation -├── Navbar - Desktop and mobile -├── Sidebar - With groups + badges -├── Breadcrumbs - Icon and text -└── Pagination - Standard and compact - -Data Display -├── Tables - Sortable, with actions -├── Stats Cards - Number, with trend -├── Progress - Bar and ring -└── Timeline - Activity log - -Advanced -├── Auth Flows - Login, register, forgot password -├── Media - Gallery, lightbox, video -└── Charts - Bar, line, pie (Alpine.js + Chart.js) -``` - ---- - -## Adding Your Own Component to Showcase - -1. Create your component in `modules/UIShowcase/views/components/` -2. Register it in the showcase index - ---- - -## Next Steps - -**[API Authentication →](../api/sanctum)** +See [installation](/docs/installation) and [package architecture](/docs/core/architecture). diff --git a/docs/images/screenshots/admin-dashboard.png b/docs/images/screenshots/admin-dashboard.png new file mode 100644 index 0000000..f5fb484 Binary files /dev/null and b/docs/images/screenshots/admin-dashboard.png differ diff --git a/docs/images/screenshots/blog-detail.png b/docs/images/screenshots/blog-detail.png new file mode 100644 index 0000000..7460cc5 Binary files /dev/null and b/docs/images/screenshots/blog-detail.png differ diff --git a/docs/images/screenshots/blog-editor.png b/docs/images/screenshots/blog-editor.png new file mode 100644 index 0000000..8bf3870 Binary files /dev/null and b/docs/images/screenshots/blog-editor.png differ diff --git a/docs/images/screenshots/blog-management.png b/docs/images/screenshots/blog-management.png new file mode 100644 index 0000000..6d7f379 Binary files /dev/null and b/docs/images/screenshots/blog-management.png differ diff --git a/docs/images/screenshots/blog.png b/docs/images/screenshots/blog.png new file mode 100644 index 0000000..cc64d8b Binary files /dev/null and b/docs/images/screenshots/blog.png differ diff --git a/docs/images/screenshots/documentation.png b/docs/images/screenshots/documentation.png new file mode 100644 index 0000000..e40298e Binary files /dev/null and b/docs/images/screenshots/documentation.png differ diff --git a/docs/images/screenshots/homepage-dark.png b/docs/images/screenshots/homepage-dark.png new file mode 100644 index 0000000..5c9be9c Binary files /dev/null and b/docs/images/screenshots/homepage-dark.png differ diff --git a/docs/images/screenshots/homepage.png b/docs/images/screenshots/homepage.png new file mode 100644 index 0000000..8820a3f Binary files /dev/null and b/docs/images/screenshots/homepage.png differ diff --git a/docs/images/screenshots/mobile-navigation.png b/docs/images/screenshots/mobile-navigation.png new file mode 100644 index 0000000..6507d42 Binary files /dev/null and b/docs/images/screenshots/mobile-navigation.png differ diff --git a/docs/images/screenshots/rtl-support.png b/docs/images/screenshots/rtl-support.png new file mode 100644 index 0000000..123bdeb Binary files /dev/null and b/docs/images/screenshots/rtl-support.png differ diff --git a/docs/images/screenshots/ui-showcase.png b/docs/images/screenshots/ui-showcase.png new file mode 100644 index 0000000..d5f8666 Binary files /dev/null and b/docs/images/screenshots/ui-showcase.png differ diff --git a/docs/images/screenshots/walkthrough.gif b/docs/images/screenshots/walkthrough.gif new file mode 100644 index 0000000..43023c2 Binary files /dev/null and b/docs/images/screenshots/walkthrough.gif differ diff --git a/docs/implementation-report.md b/docs/implementation-report.md new file mode 100644 index 0000000..b83da82 --- /dev/null +++ b/docs/implementation-report.md @@ -0,0 +1,67 @@ +# Package and website implementation report + +Reviewed 19 October 2026. + +## Distribution + +- Composer identity: `programmernomad/laracorekit` (public frontend **and** administration). +- Package source: `packages/core` in this monorepo. +- Public distribution repository: [ProgrammerNomad/laracorekit-package](https://github.com/ProgrammerNomad/laracorekit-package). +- Core, Auth, User, Settings, Media and Blog ship together initially. Marketing pages, Docs, UIShowcase, sample seeders and the demo dependency stay in the host. +- The package archive is about 84 KB compressed, excluding installed PHP dependencies. The export checks that host public assets are not accidentally copied into the package. +- Packagist publishes v0.1.0 from package commit `220940d294bcd7d6de84f26d293867d576820e71`. Composer installation is the primary application path; GitHub VCS is a development fallback. + +## Installation and updates + +Package discovery registers the reusable providers. The explicit installer publishes configuration and prebuilt public CSS plus Filament assets, preserving existing configuration. Migrations run only when requested. Administrator creation is interactive and cannot promote an existing email address. + +Source namespaces and migration filenames are preserved for migration from older checkouts. `config/laracorekit.php` replaces the old application module-loader configuration. The default package panel is optional; the host demonstrates a custom panel. Existing custom user models and conflicting routes require integration planning. + +## Security and dependency changes + +- Updated compatible PHP dependencies and the frontend toolchain; Composer and npm audits report no advisories at validation time. +- Added login/registration/reset throttling and neutral password-reset responses. +- Kept known accounts behind explicit demo mode and removed email-based automatic administrator promotion. +- Enforced direct record access, settings save and blog publication permissions. +- Sanitized public blog HTML and excluded future/draft posts from public publication queries. +- Generated default avatars locally instead of sending names to an external avatar service. Used Filament's bundled font by default. +- Removed unused crawler, Alpine and syntax-highlighter dependencies from the host where applicable. + +These are tested improvements, not a claim of a completed independent security audit. + +## Website and documentation + +- Rebuilt the public homepage around the actual frontend/admin bundle, explicit installation paths and accurate release status. +- Added responsive site/showcase navigation, accessible theme controls and improved documentation search keyboard/focus behavior. Restored the original red/black logo, removed the locale-template BOM that shifted the language control, reduced header height and fixed narrow-screen installation-card overflow; browser regression checks pass at seven widths from 320px to 1440px. +- Added permission-aware admin overview statistics and real screenshots from disposable fixtures. +- Corrected unsupported feature claims in installation, architecture, feature, deployment and addon guides. +- Added Markdown source endpoints, `/llms.txt`, page descriptions, source-code metadata and a dynamic documentation sitemap. A pre-existing local static sitemap containing localhost URLs was moved into private storage so it cannot mask the route. +- Split showcase libraries from ordinary public JavaScript: approximately 50 KB for the base bundle versus 304 KB previously. Package public CSS is approximately 46 KB uncompressed. + +## Validation + +- 31 PHPUnit tests, 137 assertions passed on both SQLite and an isolated MySQL 8.0.45 server, locally on PHP 8.3. +- Pint and PHPStan passed. +- Root and package Composer schemas validated strictly. +- Composer and npm dependency audits reported zero advisories. +- Package and host production builds passed. +- Independent consumer installation passed public/admin login routes, asset availability, safe seed defaults, no demo dependency, and cached routes/configuration. +- Desktop/mobile browser checks covered primary public/admin pages and all 46 linked documentation pages. All 122 linked showcase URLs returned HTTP 200. + +## Automation and external status + +Weekly Dependabot proposals, scheduled dependency audits, PHP locked/compatible CI lanes, a MySQL 8 service job, clean-consumer CI and a manual package-preview archive workflow are configured in source. GitHub vulnerability alerts and automated security-fix PRs are enabled and API-verified on both repositories. The distribution repository also has a manual draft release-notes PR workflow; it does not tag or publish. + +The distribution repository has a daily source-sync workflow using its own short-lived GITHUB_TOKEN. It proposes draft PRs rather than merging or tagging automatically, and waits for the extraction to reach the monorepo main branch. + +The first remote run [39212465937](https://github.com/ProgrammerNomad/laracorekit-package/actions/runs/39212465937) did **not** execute: GitHub reported, “The job was not started because your account is locked due to a billing issue.” Remote CI is therefore unverified and blocked by account state; local checks are the evidence above. Billing settings were not changed. + +The host's optional `laracorekit:stats` command saves validated daily Packagist download snapshots without installation telemetry. Missing/unavailable responses do not become zero counts. Packagist registration is complete; enable collection on persistent production storage when deploying. + +Remaining operational actions: resolve the GitHub Actions account lock, pass remote checks, review/merge the host changes and deploy the updated website. Package tag v0.1.0 and Packagist registration are complete; production website deployment is not verified. + +## Published-package follow-up + +Packagist's Composer feed confirms v0.1.0. A fresh Laravel consumer installed the tagged package directly from Packagist with no path/VCS override and passed route, asset, migration, safe-default and cached configuration checks. CI now tests both local source and the published package. + +Composer installation is the primary path in the homepage, host README, distribution README, installation guide and demo module introduction. Updated release-status documents remove the former publication-pending claim. Real screenshots and a four-view, 12-second GIF illustrate the public site/admin/docs host. Production deployment and the account-blocked remote CI remain separate operational requirements. diff --git a/docs/installation.md b/docs/installation.md index 780a9b1..099eac5 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -1,590 +1,104 @@ -# Installation +# Installation ---- -**Supported Stack:** Laravel 13 / Filament 5 / Livewire 4 / Tailwind 4 -**Last Updated:** April 22, 2026 -**Estimated Time:** 10 minutes -**Difficulty:** Beginner ---- +LaraCoreKit is a reusable Laravel package for **both a public frontend and a Filament admin panel**. The website/demo application is a separate host in this repository. PHP 8.3+, Composer 2 and Laravel 13 are required. Node 22.12+ is required when building this repository's assets; CI uses Node 24. -This guide covers detailed installation instructions for LaraCoreKit in various environments. +## Release status ---- +Stable releases are published on [Packagist](https://packagist.org/packages/programmernomad/laracorekit) as `programmernomad/laracorekit` (current stable line: `^0.1`). The package source is maintained in this monorepo under `packages/core`; the [distribution repository](https://github.com/ProgrammerNomad/laracorekit-package) tracks tagged releases. No account, activation key or telemetry is required. -## System Requirements +## Option A: install from Packagist (recommended) -### Minimum Requirements +Start with a **fresh Laravel 13 application**. The first release uses `Modules\User\Models\User` and the stock Laravel `users` table; integrating an existing authentication system needs a separate migration plan. -- **PHP:** 8.3 or higher -- **Composer:** 2.0 or higher -- **Node.js:** 18.0 or higher -- **Database:** MySQL 8.0+, PostgreSQL 13+, or SQLite 3.35+ -- **Web Server:** Apache 2.4+ or Nginx 1.20+ -- **Memory:** 512MB RAM minimum, 1GB recommended - -### PHP Extensions Required - -Ensure these PHP extensions are enabled: - -```bash -php -m | grep -E "openssl|pdo|mbstring|tokenizer|xml|ctype|json|bcmath|curl|fileinfo|gd" -``` - -Required extensions: -- OpenSSL -- PDO -- Mbstring -- Tokenizer -- XML -- Ctype -- JSON -- BCMath -- cURL -- Fileinfo -- GD or Imagick (for image processing) - ---- - -## Installation Methods - -Choose the method that fits your environment: - -- [Local Development](#local-development) (Recommended for beginners) -- [Docker Setup](#docker-setup) (Isolated environment) -- [Production Server](#production-server) (Deployment-ready) - ---- - -## Local Development - -### 1. Clone Repository +The `create-project` command installs Laravel and initializes its `.env`, application key and default SQLite database. Run the remaining commands inside `my-app`. `composer require` and `laracorekit:install` alone assume Laravel already exists and do not create the complete demo website. ```bash -git clone https://github.com/ProgrammerNomad/LaraCoreKit.git -cd LaraCoreKit +composer create-project laravel/laravel my-app "^13.0" +cd my-app +composer require programmernomad/laracorekit:"^0.1" +php artisan laracorekit:install ``` -### 2. Install PHP Dependencies +Configure `.env` with your application URL, mail and database settings. For local evaluation, keep the generated SQLite configuration and set `APP_URL=http://127.0.0.1:8000`. Keep `APP_DEBUG=false` in production. ```bash -composer install +php artisan migrate +php artisan laracorekit:admin +php artisan storage:link +php artisan serve ``` -If you encounter memory issues: +Open `/admin` for administration and `/blog` for the public frontend. Your own `/` route remains under your application's control. `/login`, `/forgot-password`, `/reset-password/{token}` and `/dashboard` are provided by the Auth module. Public registration is disabled by default; enable `registration` in `config/laracorekit.php` when needed. -```bash -COMPOSER_MEMORY_LIMIT=-1 composer install -``` +The administrator command prompts for a unique email and a hidden password. It does not promote an existing account. Default seeding does not create sample users. Prebuilt package CSS is published by the installer, so consuming the default package views does not require the demo's npm dependencies. -### 3. Install JavaScript Dependencies +Package discovery registers providers, views, routes and migrations. Composer installs dependencies; it does **not** configure your database or run package installation migrations automatically. `laracorekit:install --migrate` is available when you explicitly want the installer to run outstanding migrations. Re-running the installer preserves existing configuration. -```bash -npm install -``` - -Or using Yarn: +For contributors testing unreleased changes only, add a VCS repository and require `dev-main`. Use the tagged Packagist package above for application installs: ```bash -yarn install +composer config repositories.laracorekit vcs https://github.com/ProgrammerNomad/laracorekit-package +composer require programmernomad/laracorekit:dev-main ``` -### 4. Environment Configuration - -Copy the example environment file: +## Option B: run the complete GitHub demo/development host ```bash -cp .env.example .env +git clone https://github.com/ProgrammerNomad/LaraCoreKit.git my-demo +cd my-demo +php -r "copy('.env.example', '.env');" +composer install ``` -Generate application key: +Laravel is already included in this checkout; do not run `composer create-project` here. Set `APP_URL=http://127.0.0.1:8000` in `.env`. Keep the default `DB_CONNECTION=sqlite` for local evaluation; the command below creates its database file. For MySQL, configure an existing database and credentials instead and skip the SQLite file command. ```bash php artisan key:generate -``` - -### 5. Database Configuration - -#### Option A: SQLite (Easiest) - -Edit `.env`: - -```env -DB_CONNECTION=sqlite -# Comment out or remove these: -# DB_HOST=127.0.0.1 -# DB_PORT=3306 -# DB_DATABASE=laracorekit -# DB_USERNAME=root -# DB_PASSWORD= -``` - -Create the database file: - -```bash -# Windows -type nul > database\database.sqlite - -# macOS/Linux -touch database/database.sqlite -``` - -#### Option B: MySQL - -Create a database: - -```sql -CREATE DATABASE laracorekit CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -``` - -Edit `.env`: - -```env -DB_CONNECTION=mysql -DB_HOST=127.0.0.1 -DB_PORT=3306 -DB_DATABASE=laracorekit -DB_USERNAME=root -DB_PASSWORD=your_password -``` - -#### Option C: PostgreSQL - -Create a database: - -```sql -CREATE DATABASE laracorekit ENCODING 'UTF8'; -``` - -Edit `.env`: - -```env -DB_CONNECTION=pgsql -DB_HOST=127.0.0.1 -DB_PORT=5432 -DB_DATABASE=laracorekit -DB_USERNAME=postgres -DB_PASSWORD=your_password -``` - -### 6. Run Migrations - -```bash +php -r "file_exists('database/database.sqlite') || touch('database/database.sqlite');" php artisan migrate --seed -``` - -This will: -- Create all database tables -- Seed default roles and permissions -- Create sample blog posts -- Create demo users (if configured) - -### 7. Build Frontend Assets - -For development with hot reload: - -```bash -npm run dev -``` - -For production build: - -```bash +php artisan laracorekit:admin +php artisan storage:link +npm ci +npm run build:core npm run build -``` - -### 8. Create Admin User - -```bash -php artisan filament:user -``` - -Follow the prompts to create your admin account. - -### 9. Start Development Server - -```bash php artisan serve ``` -Access at: **http://localhost:8000** - ---- - -## Docker Setup - -LaraCoreKit includes Docker support via Laravel Sail. - -### 1. Install Docker - -Download and install Docker Desktop: -- **Windows:** https://docs.docker.com/desktop/windows/install/ -- **macOS:** https://docs.docker.com/desktop/mac/install/ -- **Linux:** https://docs.docker.com/engine/install/ - -### 2. Install Dependencies +This repository uses a Composer **path repository** pointing at `packages/core`; keep that directory with the checkout. It includes the marketing website, docs viewer, showcase and the separately published demo-module dependency. The reusable package does not require any of those. -First, install Composer dependencies using a temporary Docker container: +Only on a disposable demo database, explicitly enable `DEMO_MODE=true` and seed `Database\Seeders\DemoSeeder`. Demo mode permits known sample credentials and scheduled resets. Never enable it for a customer deployment. See [demo setup](/docs/deployment/demo-setup). -```bash -docker run --rm \ - -u "$(id -u):$(id -g)" \ - -v $(pwd):/var/www/html \ - -w /var/www/html \ - laravelsail/php82-composer:latest \ - composer install --ignore-platform-reqs -``` - -### 3. Start Sail - -```bash -./vendor/bin/sail up -d -``` +The package installs Laravel dependencies into an existing app; it does not download the demo website. See [release preparation](/docs/package-release) and [upgrading](/docs/upgrade-guide). -This starts: -- PHP 8.3 with Laravel -- MySQL 8.0 -- Redis -- Mailhog (email testing) +## Customization -### 4. Setup Environment - -```bash -cp .env.example .env -./vendor/bin/sail artisan key:generate -``` - -### 5. Run Migrations - -```bash -./vendor/bin/sail artisan migrate --seed -``` - -### 6. Install JavaScript Dependencies - -```bash -./vendor/bin/sail npm install -./vendor/bin/sail npm run build -``` - -### 7. Create Admin User - -```bash -./vendor/bin/sail artisan filament:user -``` - -### 8. Access Application - -- **Application:** http://localhost -- **Admin Panel:** http://localhost/admin -- **Mailhog:** http://localhost:8025 - -### Sail Aliases - -Add to your shell profile (`~/.bashrc` or `~/.zshrc`): - -```bash -alias sail='./vendor/bin/sail' -``` - -Then use: - -```bash -sail up -d -sail artisan migrate -sail npm run dev -``` +- Edit published `config/laracorekit.php` for registration, modules and panel settings. +- Override individual views under `resources/views/vendor/core`, `auth`, `blog` or `settings`, following Laravel's namespaced-view override convention. Do not edit `vendor` files. +- To use your own Filament panel, set `panel.enabled=false` and register the desired resources/pages in your provider. The demo host is an example of this pattern. +- Keep User enabled for Auth, Blog and the packaged panel. Blog also requires Media. Invalid dependency combinations fail with an explicit configuration error. +- Disabling a module stops its provider/routes/resources from loading. It does not drop data or remove installed Composer dependencies. +- Routes use conventional names such as `login`, `dashboard`, and `blog.index`. Resolve collisions before integrating with existing routes. ---- +The initial package is intended for new applications. API tokens, email-verification enforcement, billing, tenancy and a public module marketplace are not bundled capabilities. -## Production Server +## Local package development -### 1. Server Setup +When contributing from the monorepo, use a path repository instead of the GitHub VCS repository: -Install required software on Ubuntu/Debian: +Add this path entry to the consumer application's `repositories` array in `composer.json`. The explicit local version keeps the command working when the monorepo is checked out on a feature branch: -```bash -# Update system -sudo apt update && sudo apt upgrade -y - -# Install PHP 8.3 -sudo add-apt-repository ppa:ondrej/php -sudo apt install php8.3-fpm php8.3-cli php8.3-mysql php8.3-pgsql \ - php8.3-xml php8.3-mbstring php8.3-curl php8.3-zip \ - php8.3-gd php8.3-bcmath php8.3-intl - -# Install Composer -curl -sS https://getcomposer.org/installer | php -sudo mv composer.phar /usr/local/bin/composer - -# Install Node.js 18 -curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash - -sudo apt install -y nodejs - -# Install MySQL -sudo apt install mysql-server - -# Install Nginx -sudo apt install nginx -``` - -### 2. Clone and Configure - -```bash -cd /var/www -sudo git clone https://github.com/ProgrammerNomad/LaraCoreKit.git -cd LaraCoreKit - -# Install dependencies (production) -composer install --no-dev --optimize-autoloader -npm install --production -npm run build - -# Setup environment -cp .env.example .env -php artisan key:generate - -# Set permissions -sudo chown -R www-data:www-data /var/www/LaraCoreKit -sudo chmod -R 755 /var/www/LaraCoreKit -sudo chmod -R 775 /var/www/LaraCoreKit/storage -sudo chmod -R 775 /var/www/LaraCoreKit/bootstrap/cache -``` - -### 3. Environment Configuration - -Edit `.env` for production: - -```env -APP_ENV=production -APP_DEBUG=false -APP_URL=https://www.laracorekit.com - -DB_CONNECTION=mysql -DB_HOST=127.0.0.1 -DB_DATABASE=laracorekit_prod -DB_USERNAME=laracorekit_user -DB_PASSWORD=secure_password_here - -CACHE_DRIVER=redis -SESSION_DRIVER=redis -QUEUE_CONNECTION=redis - -MAIL_MAILER=smtp -MAIL_HOST=smtp.laracorekit.com -MAIL_PORT=587 -MAIL_USERNAME=your_email -MAIL_PASSWORD=your_password -``` - -### 4. Database Setup - -```bash -# Create production database -mysql -u root -p << EOF -CREATE DATABASE laracorekit_prod CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -CREATE USER 'laracorekit_user'@'localhost' IDENTIFIED BY 'secure_password_here'; -GRANT ALL PRIVILEGES ON laracorekit_prod.* TO 'laracorekit_user'@'localhost'; -FLUSH PRIVILEGES; -EOF - -# Run migrations -php artisan migrate --force -``` - -### 5. Nginx Configuration - -Create `/etc/nginx/sites-available/laracorekit`: - -```nginx -server { - listen 80; - server_name www.laracorekit.com laracorekit.com; - root /var/www/LaraCoreKit/public; - - add_header X-Frame-Options "SAMEORIGIN"; - add_header X-Content-Type-Options "nosniff"; - - index index.php; - - charset utf-8; - - location / { - try_files $uri $uri/ /index.php?$query_string; - } - - location = /favicon.ico { access_log off; log_not_found off; } - location = /robots.txt { access_log off; log_not_found off; } - - error_page 404 /index.php; - - location ~ \.php$ { - fastcgi_pass unix:/var/run/php/php8.2-fpm.sock; - fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; - include fastcgi_params; - } - - location ~ /\.(?!well-known).* { - deny all; - } +```json +{ + "type": "path", + "url": "../LaraCoreKit/packages/core", + "options": { + "versions": { "programmernomad/laracorekit": "dev-main" } + } } ``` -Enable site: - -```bash -sudo ln -s /etc/nginx/sites-available/laracorekit /etc/nginx/sites-enabled/ -sudo nginx -t -sudo systemctl restart nginx -``` - -### 6. SSL Certificate (Let's Encrypt) - -```bash -sudo apt install certbot python3-certbot-nginx -sudo certbot --nginx -d laracorekit.com -d www.laracorekit.com -``` - -### 7. Setup Supervisor (Queue Worker) - -Create `/etc/supervisor/conf.d/laracorekit-worker.conf`: - -```ini -[program:laracorekit-worker] -process_name=%(program_name)s_%(process_num)02d -command=php /var/www/LaraCoreKit/artisan queue:work --sleep=3 --tries=3 --max-time=3600 -autostart=true -autorestart=true -stopasgroup=true -killasgroup=true -user=www-data -numprocs=4 -redirect_stderr=true -stdout_logfile=/var/www/LaraCoreKit/storage/logs/worker.log -stopwaitsecs=3600 -``` - -Start supervisor: - -```bash -sudo supervisorctl reread -sudo supervisorctl update -sudo supervisorctl start laracorekit-worker:* -``` - -### 8. Setup Cron - -Add to crontab (`sudo crontab -e -u www-data`): - -```bash -* * * * * cd /var/www/LaraCoreKit && php artisan schedule:run >> /dev/null 2>&1 -``` - -### 9. Optimize for Production - ```bash -php artisan config:cache -php artisan route:cache -php artisan view:cache -php artisan optimize +composer require programmernomad/laracorekit:dev-main ``` ---- - -## Post-Installation - -### Verify Installation - -```bash -# Check Laravel version -php artisan --version - -# Check installed modules -php artisan module:list - -# Run health checks -php artisan about -``` - -### Create Admin User - -```bash -php artisan filament:user -``` - -### Configure Settings - -1. Login to admin panel: `/admin` -2. Navigate to Settings -3. Configure: - - Site name and description - - SEO defaults - - Supported languages - - Email settings - ---- - -## Troubleshooting - -### Composer Install Fails - -```bash -# Clear Composer cache -composer clear-cache - -# Install with verbose output -composer install -vvv -``` - -### Permission Issues - -```bash -# Linux/macOS -chmod -R 775 storage bootstrap/cache -chown -R www-data:www-data storage bootstrap/cache - -# Or if you're the owner -chmod -R 775 storage bootstrap/cache -chown -R $USER:www-data storage bootstrap/cache -``` - -### Database Connection Errors - -```bash -# Test database connection -php artisan db:show - -# Clear config cache -php artisan config:clear -``` - -### Module Not Loading - -```bash -# Clear all caches -php artisan optimize:clear - -# Dump autoload -composer dump-autoload - -# Check module config -php artisan config:show modules -``` - ---- - -## Next Steps - - Installation complete! Now: - -1. **[Explore Project Structure →](project-structure.md)** -2. **[Learn Module System →](core/modules-system.md)** -3. **[Configure Settings →](features/settings.md)** - ---- - -## Get Help - -- **[Documentation](introduction.md)** -- **[GitHub Issues](https://github.com/ProgrammerNomad/LaraCoreKit/issues)** - - +A development branch can change without a release. Pin and review a tested commit for evaluation; use a reviewed tagged release for production when available. The monorepo host already configures the local path and an explicit dev-main version for CI. diff --git a/docs/introduction.md b/docs/introduction.md index c965a8d..3e43247 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -1,198 +1,24 @@ -# Introduction +# LaraCoreKit ---- -**Supported Stack:** Laravel 13 / Filament 5 / Livewire 4 / Tailwind 4 -**Last Updated:** April 22, 2026 -**Version:** v0.1.0 (unreleased) ---- +LaraCoreKit is an MIT-licensed modular Laravel foundation for a **public website and an admin workspace**. It combines Laravel 13, Filament 5, Livewire 4 and Tailwind CSS 4. -## What is LaraCoreKit? +The reusable package is `programmernomad/laracorekit`, with source in `packages/core`. Its internal modules are Core, Auth, User, Settings, Blog and Media. The repository root hosts the marketing website, documentation viewer, UI showcase and optional demo behavior. -LaraCoreKit is a **production-ready, modular Laravel 13 starter kit** designed for modern full-stack applications. It provides everything you need to build scalable, multilingual web applications with a powerful admin panel, role-based permissions, and a comprehensive UI component library. +## What is implemented -### Why LaraCoreKit? +- Public login, registration when enabled, password recovery and account dashboard. +- Filament administration for users, roles, permissions, blog posts and settings. +- Multilingual blog fields, public blog pages, media attachments and language switching for English, Hindi and Arabic. +- Package discovery, migrations, a configuration/asset installer and interactive administrator creation. +- Module configuration and application-level Blade overrides. -Building modern web applications requires integrating multiple packages, setting up authentication, creating admin panels, and structuring your codebase for long-term maintainability. LaraCoreKit solves these challenges by providing: +## Start here -**Modular Architecture** - Build features as independent modules -**Production-Ready** - Battle-tested code ready for deployment -**Admin Panel** - Beautiful Filament 5 admin interface -**175+ UI Components** - Complete Tailwind CSS component library -**Multilingual** - Built-in support for EN, HI, AR with RTL -**Developer-Friendly** - Clear structure, excellent DX +1. [Choose an installation path](/docs/installation). +2. [Understand package ownership](/docs/core/architecture). +3. [Review production setup](/docs/deployment/production). +4. [Read the upgrade guide](/docs/upgrade-guide). ---- +First create a fresh Laravel 13 application using the [installation guide](/docs/installation), then install the published package from Packagist with `composer require programmernomad/laracorekit:"^0.1"`. There is no mandatory account or installation telemetry. API tokens, enforced email verification, billing and tenancy need additional implementation. -## Core Technologies - -LaraCoreKit is built on modern, industry-standard technologies: - -| Technology | Version | Purpose | -|------------|---------|---------| -| **Laravel** | 13 | Backend framework | -| **Livewire** | 4 | Dynamic frontend components | -| **Tailwind CSS** | 4 | Utility-first styling | -| **Filament** | 5 | Admin panel | -| **Alpine.js** | 3.x | Lightweight JavaScript | -| **Vite** | 5.x | Fast build tool | - ---- - -## Who is LaraCoreKit for? - -### Perfect for: - -- **Developers** building SaaS applications -- **Agencies** needing a reliable starter template -- **Startups** wanting to move fast -- **Teams** requiring a modular codebase -- **Multilingual projects** with RTL support needs - -### Not suitable for: - -- Simple landing pages (use static site generators) -- WordPress-like content management (use Statamic or WordPress) -- Pure API backends (use Laravel API starter) - ---- - -## Key Features at a Glance - -### Authentication & Security -- Laravel Breeze scaffolding -- Email verification -- Two-factor authentication ready -- Sanctum token authentication -- CSRF protection & throttling - -### Module System -- Self-contained feature modules -- Independent routing, migrations, views -- Enable/disable modules easily -- Create custom modules in minutes -- Version and distribute separately - -### Admin Panel (Filament) -- User management -- Role & permission assignment -- Blog content management -- Settings configuration -- Media library - -### Frontend -- 175+ ready-to-use UI components -- Livewire-powered interactivity -- Dark mode support -- Responsive design -- RTL layout support - -### Multilingual Support -- English, Hindi, Arabic out of the box -- JSON-based translations -- RTL layout for Arabic -- Easy to add more languages - ---- - -## What Makes LaraCoreKit Different? - -### 1. **True Modularity** - -Unlike traditional Laravel applications where features are tightly coupled, LaraCoreKit uses a **module-based architecture**. Each feature (Blog, Auth, Media) is a self-contained module with its own: - -- Models & Controllers -- Routes & Middleware -- Views & Components -- Migrations & Seeders -- Translations & Config - -This means you can: -- Enable/disable features without breaking the app -- Distribute modules as Composer packages -- Maintain features independently -- Scale your team around modules - -### 2. **Production-Ready, Not a Tutorial** - -LaraCoreKit isn't a learning project-it's production code used in real applications. It includes: - -- Proper error handling -- Security best practices -- Performance optimization -- SEO configuration -- Testing setup - -### 3. **Developer Experience First** - -Every decision prioritizes developer productivity: - -- Clear, consistent code structure -- Comprehensive documentation -- IDE autocomplete support -- Laravel Pint code formatting -- Telescope debugging - ---- - -## Architecture Overview - -``` -┌─────────────────────────────────────────┐ -│ LaraCoreKit Core │ -│ (Routing, Module Loader, Layouts) │ -└─────────────────────────────────────────┘ - │ - ┌──────────────┼──────────────┐ - │ │ │ -┌───▼───┐ ┌───▼───┐ ┌───▼───┐ -│ Auth │ │ Blog │ │ User │ -│ Module│ │ Module│ │ Module│ -└───────┘ └───────┘ └───────┘ - │ │ │ - │ │ │ -┌───▼──────────────▼──────────────▼───┐ -│ Shared Services & Utilities │ -│ (Permissions, Media, Settings) │ -└──────────────────────────────────────┘ -``` - ---- - -## Getting Started - -Ready to dive in? Here's your path: - -1. **[Quick Start](quick-start.md)** - Get running in 5 minutes -2. **[Installation](installation.md)** - Detailed setup guide -3. **[Project Structure](project-structure.md)** - Understand the codebase -4. **[Module System](core/modules-system.md)** - Learn the killer feature - ---- - -## Demo & Resources - -### Live Demo -**Website:** https://www.laracorekit.com/ - **UI Showcase:** https://www.laracorekit.com/ui-showcase/ - **Admin Panel:** https://www.laracorekit.com/admin - -### GitHub - **Repository:** https://github.com/ProgrammerNomad/LaraCoreKit - **Star the repo** if you find it useful! - -### Support - **Issues:** [GitHub Issues](https://github.com/ProgrammerNomad/LaraCoreKit/issues) - ---- - -## License - -LaraCoreKit is open-source software licensed under the **MIT License**. You are free to use it in commercial projects. - ---- - -## Next Steps - -**[Quick Start Guide →](quick-start.md)** - -Learn how to install and run LaraCoreKit in 5 minutes. +The main project repository is [ProgrammerNomad/LaraCoreKit](https://github.com/ProgrammerNomad/LaraCoreKit). The supporting laracorekit-package repository is only the package-only Composer distribution export; project documentation, demo GIF, screenshots, issues and development remain in the main repository. diff --git a/docs/maintenance-and-distribution-audit.md b/docs/maintenance-and-distribution-audit.md new file mode 100644 index 0000000..accde4e --- /dev/null +++ b/docs/maintenance-and-distribution-audit.md @@ -0,0 +1,101 @@ +# Initial maintenance and distribution audit + +**Historical findings:** this snapshot preceded the package extraction and remediation. See the current README, changelog, package release guide and implementation report for the resulting architecture and validation. Package identity is now `programmernomad/laracorekit`; earlier proposed names below are superseded. + +Reviewed 19 October 2026. This is a repository and dependency review, not a complete security assessment. Versions and advisory counts are a point-in-time snapshot. + +## Release blockers + +1. **Dependency advisories:** `composer audit --locked --format=json` reports advisories against 21 package names, including Laravel, Filament, Livewire, Guzzle and Symfony components. `npm audit --json` reports 13 affected packages: 2 critical, 8 high and 3 moderate. These counts describe dependency advisories, not confirmed exploitable application vulnerabilities. Update compatible dependencies first, then assess remaining advisories individually; do not suppress audit failures to publish. +2. **Predictable seeded accounts:** `database/seeders/DatabaseSeeder.php` always calls `UserSeeder`, which creates privileged demo accounts with known passwords, including a literal `password` for the editor. Move demo users/content into an explicitly enabled demo seeder. Production setup should create its administrator interactively with a unique password. Test that default production seeding creates no demo accounts. +3. **Authentication protection:** `modules/Auth/src/Http/Livewire/Login.php` calls `Auth::attempt` without visible attempt throttling. Add server-side rate limiting to the Livewire action and tests for repeated failures and successful-login reset. Review registration and password recovery similarly. Remove routine email/role debug logging or document its retention. +4. **Insufficient regression coverage:** only two example tests were found in `tests`, and no module `*Test.php` files were found. Cover login, password reset, authorization, uploads, blog publication, module enable/disable behavior and demo restrictions before broad upgrades. +5. **Broken static-analysis prerequisites:** `phpstan.neon.dist` includes Larastan, but neither Larastan nor PHPStan is required in `composer.json`. Select compatible tooling, update obsolete configuration options, then make `composer review` pass. + +## Dependency currency + +Registry checks reported the following examples: + +| Dependency | Locked/installed | Latest reported | +| --- | --- | --- | +| Laravel framework | 13.5.0 | 13.37.0 | +| Filament | 5.5.2 | 5.10.2 | +| Livewire | 4.2.4 | 4.4.7 | +| Media Library | 11.21.0 | 11.23.9 | +| Filament language switch | 4.3.0 | 5.0.0 | +| Spatie Permission | 6.25.0 | 8.3.0 | +| Vite | 6.4.1 | 8.3.4 | +| Laravel Vite plugin | 1.3.0 | 3.2.0 | +| Axios | 1.13.2 | 1.20.0 | + +Latest does not automatically mean compatible. Use separate changes for major upgrades, verify PHP/Node requirements and peer dependencies, and regenerate lockfiles through the package managers. Re-run audit, tests and production asset build after updates. + +## Other confirmed gaps + +- Composer still identifies the project as `laravel/laravel` with Laravel's skeleton description. Give it its own vendor/package name before Packagist submission. +- README says Vite 5 while `package.json` requests Vite 6. README advertises Sanctum API tokens, but Sanctum is not in the root requirements and no implementation references were found outside documentation navigation. Verify the feature or correct the claim. +- README says every module ships tests; the repository scan did not find them. +- Module providers are registered directly in `bootstrap/providers.php`, while a separate configuration-driven loader exists. Establish a single registration contract and test that disabling a module actually disables it; consider how dependent modules behave. +- Test CI runs `composer update`, whereas quality CI installs the lockfile. Add an explicit locked-dependency lane and retain a separately named compatibility lane. +- SQLite test isolation is commented out in `phpunit.xml`. Set a dedicated test database before adding database-mutating tests. +- CI covers PHP 8.3 and SQLite only. Add supported PHP versions and database coverage according to an explicit support policy. +- `minimum-stability: dev` is broader than necessary unless an identified dependency requires it. Prefer stable dependencies after verifying resolution. + +## Recommended Composer distribution + +Start by publishing this repository as a **project** package, for example `programmernomad/laracorekit` (proposed name; availability and ownership must be checked). After publishing, installation becomes: + +```sh +composer create-project programmernomad/laracorekit my-app +``` + +Keep the clone installation documented until the package is available and clean installation is verified. Register the GitHub repository on Packagist once, configure its GitHub update integration, and publish semantic version tags only after release checks pass. Composer derives versions from tags; do not add a manually maintained version field. + +Next, extract reusable functionality into `programmernomad/laracorekit-core`, a library required by the starter project. This is an architectural migration, not a rename: move namespaces, providers, config, views, routes and migrations into a package, define publishable customization points, and test installation into a clean Laravel application. Existing apps need migration/upgrade instructions. Keep demo tooling and showcase content optional. Build on the existing separate demo-module package. + +A project installed by `create-project` is a starting snapshot; future starter changes do not automatically upgrade the generated application. A core library installed with `require` can receive Composer updates. This maintainability benefit is the main reason to extract core. + +## Adoption measurement + +Packagist exposes total, monthly and daily downloads. These are adoption signals, not unique new projects, active sites or developer identities. CI, reinstalls, upgrades and caching affect counts. Core and starter downloads overlap: never sum them as unique users. Existing Git clones are not retroactively counted. + +Recommended initial dashboard: starter downloads, core downloads, GitHub stars/forks, issue response time, release cadence and voluntarily submitted showcase projects. Keep download series separate. Use an optional community/showcase submission for developers who want to identify themselves. Avoid mandatory registration or hidden installation callbacks. + +If active-installation measurement becomes necessary, design a separately reviewed, explicit opt-in telemetry feature: random installation identifier, limited version/environment fields, disclosed retention, disable/delete support, and a documented sampling policy. Do not send domains, emails, source code or secrets by default. Cloned deployments and disabled telemetry still prevent exact counting. + +## Automation rollout + +1. Added `.github/dependabot.yml` proposes weekly Composer, npm and GitHub Actions updates after this change reaches GitHub's default branch. Enable Dependabot security updates and vulnerability alerts in repository settings as well. No automatic merging is configured. +2. Add CI gates for Composer validation, dependency audits, working static analysis, focused tests and frontend build. Use deterministic installs with lockfiles and a separate compatibility-update job. +3. Add a clean-install smoke test that creates a fresh project, uses an isolated database, migrates, builds assets and checks representative public/admin routes. +4. Use a release PR workflow to update changelog/version tags after checks pass; connect tags to Packagist indexing. Keep a human release decision until regression coverage is meaningful. +5. After packages exist, collect Packagist statistics once daily using a scheduled GitHub Action or existing site scheduler. Store dated snapshots in durable storage with deduplication, timeouts and retry limits. A missing package or network failure must not become a zero-download datapoint. Do not create recurring Codex reminders for this application workflow. + +## Sources + +- [Composer create-project and CLI](https://getcomposer.org/doc/03-cli.md#create-project) +- [Composer library publishing and tags](https://getcomposer.org/doc/02-libraries.md) +- [Packagist setup and update integration](https://packagist.org/about) +- [Packagist download statistics API](https://packagist.org/apidoc#package-stats) + +No dependencies were upgraded, package published, telemetry installed, or remote repository settings changed as part of this audit. The Dependabot configuration prepares update proposals; it does not establish that the application is up to date. + + +## Follow-up status - 19 October 2026 + +This audit is **not fully closed**. The historical project/core names above are superseded by the single reusable library `programmernomad/laracorekit`; the website remains separate. + +| Area | Status | +| --- | --- | +| Dependency advisories, safe seeding, authentication throttling, analysis tooling | Implemented; local checks passed. See implementation report. | +| Regression coverage | Expanded to 31 tests / 137 assertions, including upload validation, password-reset flows and disabled-module dependency combinations; passed on both supported test databases. | +| Package extraction, clean installation, docs, actual screenshots | Implemented; GitHub VCS consumer installation verified. | +| PHP matrix, locked/compatible CI, audits, builds, clean-consumer workflow | Configured; remote execution blocked by GitHub account billing lock. | +| Database support matrix | SQLite and isolated MySQL 8.0.45 checks passed. MySQL CI job added; PostgreSQL, MariaDB and SQL Server are outside the verified initial matrix. | +| Responsive header and original logo | Follow-up fixes align controls, remove template BOM, use original red/black SVG and test seven viewport widths. | +| Automated distribution | Daily draft sync PR and manual release-notes PR workflows prepared; await host merge and working Actions. Release tags remain a maintainer decision. | +| Adoption statistics | Optional daily Packagist snapshot command implemented; Packagist publication is complete; enable collection on persistent deployment storage. | +| Packagist, initial tag, production deployment | Tag v0.1.0 and Packagist publication verified; production website deployment remains unverified. | +| Repository security settings | Vulnerability alerts and automated security-fix PRs enabled on both repositories and verified through the GitHub API. | + +See [implementation report](implementation-report.md) for validation evidence and release limitations. diff --git a/docs/modules/best-practices.md b/docs/modules/best-practices.md index 3e5881d..a513e8c 100644 --- a/docs/modules/best-practices.md +++ b/docs/modules/best-practices.md @@ -1,207 +1,9 @@ -# Module Best Practices +# Module best practices ---- -**Supported Stack:** Laravel 13 / Filament 5 / Livewire 4 / Tailwind 4 -**Last Updated:** April 22, 2026 -**Estimated Time:** 8 minutes -**Source Files:** [Module examples](../../modules/) ---- +Keep application-specific code outside vendor. Use unique namespaces, route names and view namespaces for addons. Declare dependencies explicitly and avoid references to demo-host classes or filesystem paths. -Building good modules isn't just about making them work - it's about making them maintainable, testable, and enjoyable for other developers (including future you). +Authorize mutations on the server, validate uploads, rate-limit abuse-sensitive actions and avoid sensitive logs. Preserve migration history and document data changes. Tests should cover clean installation, disabled-module behavior, permissions and upgrades. ---- +Do not assume configuration disables installed dependencies or deletes data. Keep public feature claims aligned with tested behavior. Use release notes and clear support constraints rather than promising every Laravel/database version. -## Do These - -### 1. One Responsibility Per Module - -Each module should handle **one feature domain** only. - -``` - Newsletter module → email subscriptions - Blog module → content management -❌ BlogNewsletter → mixing two concerns -``` - ---- - -### 2. Prefix ALL Database Tables - -```php -// Good - prefix with module name -Schema::create('blog_posts', function (Blueprint $table) { ... }); -Schema::create('blog_categories', function (Blueprint $table) { ... }); - -// ❌ Bad - generic names cause conflicts -Schema::create('posts', ...); -Schema::create('categories', ...); -``` - ---- - -### 3. Always Use Module View Namespaces - -```blade -{{-- Good - explicit namespace --}} -@extends('blog::layouts.base') -@include('blog::partials.card') - -{{-- ❌ Bad - implicit, breaks when moved --}} -@extends('layouts.app') -``` - ---- - -### 4. Put Business Logic in Services - -```php -// Good -class SubscribeController extends Controller -{ - public function __construct(private NewsletterService $newsletter) {} - - public function store(Request $request): JsonResponse - { - $this->newsletter->subscribe($request->email); - return response()->json(['message' => 'Subscribed!']); - } -} - -// ❌ Bad - business logic inside controller -public function store(Request $request) -{ - Subscriber::create(['email' => $request->email]); - Mail::to($request->email)->send(new ConfirmationMail()); - // ... more logic -} -``` - ---- - -### 5. Use `__DIR__` for All Paths - -```php -// Good - relative, portable -$this->loadMigrationsFrom(__DIR__ . '/../database/migrations'); -$this->loadViewsFrom(__DIR__ . '/../views', 'newsletter'); - -// ❌ Bad - absolute path, breaks on different machines -$this->loadMigrationsFrom('/var/www/app/modules/Newsletter/database/migrations'); -``` - ---- - -### 6. Write Tests for Every Module - -``` -tests/ -└── Modules/ - └── Newsletter/ - ├── Unit/ - │ └── SubscriberModelTest.php - └── Feature/ - ├── SubscribeFormTest.php - └── UnsubscribeTest.php -``` - ---- - -### 7. Provide a Seeder for Demo Data - -```php -php artisan db:seed --class=Modules\\Blog\\Database\\Seeders\\BlogSeeder -``` - ---- - -### 8. Document Your Module - -Every module should have a `README.md`: -- What it does -- Installation -- Configuration -- Usage examples -- Available blade components / Livewire components - ---- - -## ❌ Avoid These - -### Don't Import Cross-Module Classes Directly - -```php -// ❌ Bad - tight coupling between modules -use Modules\User\Models\User; -use Modules\Blog\Models\Post; - -class Newsletter extends Model -{ - public function sendToAllBlogReaders() - { - User::whereHas('posts')->each(fn($u) => ...); - } -} -``` - -Instead, use **events** or **contracts**: - -```php -// Good - loose coupling via events -event(new NewPostPublished($post)); - -// In Newsletter module's listener: -class SendNewsletterOnNewPost -{ - public function handle(NewPostPublished $event): void - { - // notify subscribers - } -} -``` - ---- - -### Don't Hardcode Config Values - -```php -// ❌ Bad -$perPage = 12; - -// Good -$perPage = config('blog.posts_per_page', 12); -``` - ---- - -### Don't Skip Validation - -Every user-facing input must be validated: - -```php -// Always validate -$validated = $request->validate([ - 'email' => 'required|email|max:255', -]); -``` - ---- - -## Code Quality Checklist - -Before shipping a module: - -- [ ] Tables are prefixed with module name -- [ ] All views use the module namespace -- [ ] Business logic is in Services, not controllers -- [ ] Tests cover happy paths and edge cases -- [ ] Config values are not hardcoded -- [ ] ServiceProvider uses `__DIR__` relative paths -- [ ] Module has a README -- [ ] Module is listed in `config/modules.php` -- [ ] Namespace added to `composer.json` autoload - ---- - -## Next Steps - -**[Production Setup →](../deployment/production)** +See [installation](/docs/installation) and [package architecture](/docs/core/architecture). diff --git a/docs/modules/create-module.md b/docs/modules/create-module.md index cf18e85..bb2d362 100644 --- a/docs/modules/create-module.md +++ b/docs/modules/create-module.md @@ -1,335 +1,9 @@ -# Create a Module +# Create an addon module ---- -**Supported Stack:** Laravel 13 / Filament 5 / Livewire 4 / Tailwind 4 -**Last Updated:** April 22, 2026 -**Estimated Time:** 15 minutes -**Source Files:** [ServiceProvider example](../../modules/Blog/src/BlogServiceProvider.php) ---- +For an independently reusable addon, create a normal Composer library with its own namespace, service provider, routes, migrations, views, tests and README. The existing laracorekit-demo-module repository is an example of independent distribution. -This guide walks you through creating a complete custom module in LaraCoreKit from scratch. We'll build a **Newsletter** module as the real-world example. +Declare runtime dependencies in require, PSR-4 mappings in autoload and the provider in extra.laravel.providers. Use a Composer path repository during local development. Register admin resources in a custom panel or a documented Filament plugin. ---- +The bundled module switch is for the known modules inside LaraCoreKit. It is not an arbitrary marketplace loader. Do not add application-specific source under vendor or modify the package's composer.json after installation. -## Step 1: Create the Directory Structure - -```bash -mkdir -p modules/Newsletter/src/Http/Livewire -mkdir -p modules/Newsletter/src/Models -mkdir -p modules/Newsletter/src/Filament/Resources -mkdir -p modules/Newsletter/database/migrations -mkdir -p modules/Newsletter/database/seeders -mkdir -p modules/Newsletter/views/newsletter -mkdir -p modules/Newsletter/routes -``` - -Final structure: - -``` -modules/Newsletter/ -├── src/ -│ ├── NewsletterServiceProvider.php -│ ├── Models/ -│ │ └── Subscriber.php -│ └── Http/ -│ └── Livewire/ -│ └── Subscribe.php -├── database/ -│ └── migrations/ -│ └── 2024_01_01_create_subscribers_table.php -├── views/ -│ └── newsletter/ -│ └── subscribe.blade.php -└── routes/ - └── web.php -``` - ---- - -## Step 2: Create the Service Provider - -```php -loadMigrationsFrom(__DIR__ . '/../database/migrations'); - $this->loadViewsFrom(__DIR__ . '/../views', 'newsletter'); - - Livewire::component('newsletter.subscribe', \Modules\Newsletter\Http\Livewire\Subscribe::class); - - $this->loadRoutesFrom(__DIR__ . '/../routes/web.php'); - } -} -``` - ---- - -## Step 3: Create the Migration - -```php -id(); - $table->string('email')->unique(); - $table->string('name')->nullable(); - $table->boolean('is_active')->default(true); - $table->timestamp('confirmed_at')->nullable(); - $table->timestamps(); - }); - } - - public function down(): void - { - Schema::dropIfExists('newsletter_subscribers'); - } -}; -``` - ---- - -## Step 4: Create the Model - -```php - 'boolean', - 'confirmed_at' => 'datetime', - ]; - - public function scopeActive($query) - { - return $query->where('is_active', true); - } - - public function isConfirmed(): bool - { - return $this->confirmed_at !== null; - } -} -``` - ---- - -## Step 5: Create the Livewire Component - -```php -validate([ - 'email' => 'required|email|max:255', - 'name' => 'nullable|string|max:100', - ]); - - try { - Subscriber::firstOrCreate( - ['email' => $this->email], - ['name' => $this->name, 'is_active' => true] - ); - - $this->success = true; - $this->reset(['email', 'name']); - } catch (\Exception $e) { - $this->error = 'Something went wrong. Please try again.'; - } - } - - public function render() - { - return view('newsletter::newsletter.subscribe'); - } -} -``` - ---- - -## Step 6: Create the View - -```blade -{{-- modules/Newsletter/views/newsletter/subscribe.blade.php --}} - - -``` - ---- - -## Step 7: Add Routes - -```php -name('newsletter.subscribe'); -``` - ---- - -## Step 8: Register in Composer Autoload - -Add to `composer.json`: - -```json -{ - "autoload": { - "psr-4": { - "Modules\\Newsletter\\": "modules/Newsletter/src/" - } - } -} -``` - -Then run: - -```bash -composer dump-autoload -``` - ---- - -## Step 9: Enable the Module - -Add to `config/modules.php`: - -```php -'Newsletter' => [ - 'enabled' => true, - 'namespace' => 'Modules\\Newsletter', - 'provider' => 'Modules\\Newsletter\\NewsletterServiceProvider', -], -``` - ---- - -## Step 10: Run the Migration - -```bash -php artisan migrate -``` - -**Expected output:** -``` -Migrating: 2024_01_01_create_subscribers_table -Migrated: 2024_01_01_create_subscribers_table (32.50ms) -``` - ---- - -## Step 11: Use the Component - -In any Blade view: - -```blade -@livewire('newsletter.subscribe') -``` - ---- - -## Verify It Works - -1. Visit `http://localhost:8000/newsletter` -2. Submit the form with an email -3. Check the database: `SELECT * FROM newsletter_subscribers;` - ---- - -## Optional: Add Filament Admin - -Create a resource to manage subscribers from the admin panel: - -```bash -php artisan make:filament-resource Subscriber --model=Modules\\Newsletter\\Models\\Subscriber -``` - -Move the generated file to `modules/Newsletter/src/Filament/Resources/SubscriberResource.php` and update the namespace. - ---- - -## Next Steps - -**[Module Structure →](module-structure)** - -Deep dive into module conventions and best practices. +See [installation](/docs/installation) and [package architecture](/docs/core/architecture). diff --git a/docs/modules/module-structure.md b/docs/modules/module-structure.md index 0eb6ba2..d7724df 100644 --- a/docs/modules/module-structure.md +++ b/docs/modules/module-structure.md @@ -1,143 +1,9 @@ -# Module Structure +# Module structure ---- -**Supported Stack:** Laravel 13 / Filament 5 / Livewire 4 / Tailwind 4 -**Last Updated:** April 22, 2026 -**Source Files:** Example modules in [modules/](../../modules/) ---- +Bundled modules are under `packages/core/modules/{Name}`. Source is in src/, migrations in database/migrations, routes in routes/, and Blade views in views/ where applicable. Providers register their resources explicitly. -Every module in LaraCoreKit follows a consistent, predictable directory structure. Once you learn it for one module, you know it for all. +The package's composer.json owns autoload mappings, including separate factory/seeder namespaces. Website modules Docs and UIShowcase remain under the repository root's modules/ directory. ---- +Not every module has all possible directories or a dedicated test suite. Check actual source and integration tests rather than assuming a module contract is fully implemented. -## Standard Structure - -``` -modules/{ModuleName}/ -├── src/ ← PHP source (PSR-4 autoloaded) -│ ├── {Module}ServiceProvider.php ← REQUIRED: registers everything -│ ├── Models/ ← Eloquent models -│ │ └── {Model}.php -│ ├── Http/ -│ │ ├── Controllers/ ← Traditional controllers -│ │ │ └── {Model}Controller.php -│ │ └── Livewire/ ← Livewire components -│ │ └── {Component}.php -│ ├── Filament/ -│ │ ├── Resources/ ← Filament admin resources -│ │ │ └── {Model}Resource.php -│ │ └── Pages/ ← Custom admin pages -│ └── Services/ ← Business logic services -│ └── {Module}Service.php -├── database/ -│ ├── migrations/ ← Module-specific migrations -│ │ └── *.php -│ └── seeders/ ← Module-specific seeders -│ └── {Module}Seeder.php -├── views/ ← Blade templates -│ └── {module}/ ← Namespaced folder -│ ├── livewire/ -│ │ └── *.blade.php -│ └── layouts/ -│ └── *.blade.php -└── routes/ - ├── web.php ← Frontend routes - └── api.php ← API routes (optional) -``` - ---- - -## Naming Conventions - -| What | Convention | Example | -|------|-----------|---------| -| Module directory | `PascalCase` | `Newsletter` | -| PHP namespace | `Modules\{Name}` | `Modules\Newsletter` | -| Service Provider | `{Name}ServiceProvider` | `NewsletterServiceProvider` | -| View namespace | lowercase | `newsletter::` | -| Livewire component | `{module}.{component}` | `newsletter.subscribe` | -| Database table prefix | `{module}_` | `blog_posts` | -| Config file | `{module}.php` | `newsletter.php` | - ---- - -## What the Service Provider Does - -The ServiceProvider is the **only required file** in every module. It bootstraps everything: - -```php -class BlogServiceProvider extends ServiceProvider -{ - public function boot(): void - { - // Makes migrations run with php artisan migrate - $this->loadMigrationsFrom(__DIR__ . '/../database/migrations'); - - // Enables blog:: view namespace - $this->loadViewsFrom(__DIR__ . '/../views', 'blog'); - - // Registers Livewire components - Livewire::component('blog.blog-list', BlogList::class); - - // Registers routes - $this->loadRoutesFrom(__DIR__ . '/../routes/web.php'); - - // Publishes config (optional) - $this->publishes([ - __DIR__ . '/../config/blog.php' => config_path('blog.php'), - ], 'config'); - } -} -``` - ---- - -## Module Config - -Add optional configuration file: - -``` -modules/Blog/ -└── config/ - └── blog.php -``` - -```php -return [ - 'posts_per_page' => 12, - 'image_width' => 1200, - 'allow_comments' => false, -]; -``` - -Load in ServiceProvider: - -```php -$this->mergeConfigFrom(__DIR__ . '/../config/blog.php', 'blog'); -``` - -Use anywhere: - -```php -config('blog.posts_per_page'); // 12 -``` - ---- - -## Module Dependencies - -Modules can share data through Laravel's service container: - -```php -// Module A registers a service -$this->app->singleton(NewsletterService::class, fn ($app) => new NewsletterService()); - -// Module B resolves it -$service = app(NewsletterService::class); -``` - ---- - -## Next Steps - -**[Publishing Modules →](publishing)** +See [installation](/docs/installation) and [package architecture](/docs/core/architecture). diff --git a/docs/modules/publishing.md b/docs/modules/publishing.md index 3afa46a..7a53036 100644 --- a/docs/modules/publishing.md +++ b/docs/modules/publishing.md @@ -1,184 +1,9 @@ -# Publishing Modules +# Publishing modules ---- -**Supported Stack:** Laravel 13 / Filament 5 / Livewire 4 / Tailwind 4 -**Last Updated:** April 22, 2026 -**Estimated Time:** 12 minutes -**Example:** [Demo Module Package](https://github.com/ProgrammerNomad/laracorekit-demo-module) ---- +Publish addons as Composer libraries with their own repository-root composer.json, version tags, license, docs and tests. Use Laravel provider discovery and namespaced views to avoid requiring manual source copies. -LaraCoreKit modules can be extracted and distributed as standalone **Composer packages**, making them reusable across projects and shareable with the community. +The reusable LaraCoreKit package is maintained in packages/core and must be exported to its own package repository before Packagist submission. Do not submit the website host as the core package. See the package release checklist for the release and subtree-split process. ---- - -## When to Publish a Module - -Consider publishing when your module: -- Solves a generic problem (newsletter, notifications, analytics) -- Is stable and tested -- Has clear documentation -- Has no tight coupling to your app's specific data - ---- - -## Step 1: Prepare the Module - -### 1.1 Create a new GitHub repository - -Name it: `{vendor}/{module-name}` (e.g., `programmernomad/laracorekit-newsletter`) - -### 1.2 Create `composer.json` - -```json -{ - "name": "programmernomad/laracorekit-newsletter", - "description": "Newsletter subscription module for LaraCoreKit", - "type": "library", - "license": "MIT", - "keywords": ["laravel", "laracorekit", "newsletter", "module"], - "authors": [ - { - "name": "Your Name", - "email": "you@laracorekit.com" - } - ], - "require": { - "php": "^8.3", - "laravel/framework": "^13.0", - "livewire/livewire": "^4.0" - }, - "autoload": { - "psr-4": { - "YourVendor\\Newsletter\\": "src/" - } - }, - "extra": { - "laravel": { - "providers": [ - "YourVendor\\Newsletter\\NewsletterServiceProvider" - ] - } - } -} -``` - -### 1.3 Add a README.md - -Explain: -- What the module does -- Installation steps -- Usage examples - ---- - -## Step 2: Directory Structure for a Package - -``` -laracorekit-newsletter/ -├── src/ -│ ├── NewsletterServiceProvider.php -│ ├── Models/ -│ │ └── Subscriber.php -│ └── Http/ -│ └── Livewire/ -│ └── Subscribe.php -├── database/ -│ └── migrations/ -│ └── 2024_01_01_create_subscribers_table.php -├── views/ -│ └── newsletter/ -│ └── subscribe.blade.php -├── config/ -│ └── newsletter.php -├── composer.json -├── README.md -└── LICENSE -``` - ---- - -## Step 3: Update ServiceProvider for Package - -```php -class NewsletterServiceProvider extends ServiceProvider -{ - public function boot(): void - { - // Load migrations - $this->loadMigrationsFrom(__DIR__ . '/../database/migrations'); - - // Load views - $this->loadViewsFrom(__DIR__ . '/../views', 'newsletter'); - - // Publish assets (optional) - $this->publishes([ - __DIR__ . '/../config/newsletter.php' => config_path('newsletter.php'), - __DIR__ . '/../views' => resource_path('views/vendor/newsletter'), - ], 'newsletter'); - - // Merge config - $this->mergeConfigFrom( - __DIR__ . '/../config/newsletter.php', 'newsletter' - ); - - // Register Livewire components - Livewire::component('newsletter.subscribe', Subscribe::class); - } -} -``` - ---- - -## Step 4: Publish to Packagist - -1. Push your code to GitHub -2. Visit [packagist.org](https://packagist.org) -3. Click **"Submit"** and enter your GitHub repo URL -4. Packagist auto-indexes it within minutes - ---- - -## Step 5: Install in Any LaraCoreKit Project - -```bash -composer require programmernomad/laracorekit-newsletter -php artisan migrate -``` - -Use in Blade: - -```blade -@livewire('newsletter.subscribe') -``` - ---- - -## Step 6: Enable Auto-discovery (Already Done) - -Because the `extra.laravel.providers` key is set in `composer.json`, the ServiceProvider is automatically registered by Laravel - no manual registration needed. - ---- - -## Versioning - -Follow **Semantic Versioning**: -- `1.0.0` - Initial stable release -- `1.0.1` - Bug fix -- `1.1.0` - New feature (backward compatible) -- `2.0.0` - Breaking change - ---- - -## Tagging Releases - -```bash -git tag v1.0.0 -git push origin v1.0.0 -``` - ---- - -## Next Steps - -**[Best Practices →](best-practices)** +State compatibility constraints accurately and test a clean consumer. Keep demo code and sample credentials out of release archives. Packagist counts downloads; it does not identify users. +See [installation](/docs/installation) and [package architecture](/docs/core/architecture). diff --git a/docs/package-release.md b/docs/package-release.md new file mode 100644 index 0000000..56644fe --- /dev/null +++ b/docs/package-release.md @@ -0,0 +1,80 @@ +# Publishing the reusable package + +Package name: **`programmernomad/laracorekit`**. Package root: `packages/core`. It provides both public and admin features. The repository root is the demo/documentation host and must not be submitted as the reusable package. + +## Current release + +[v0.1.0 is available on Packagist](https://packagist.org/packages/programmernomad/laracorekit), from standalone package commit `220940d294bcd7d6de84f26d293867d576820e71`. The recommended application install is: + +```bash +composer create-project laravel/laravel my-app "^13.0" +cd my-app +composer require programmernomad/laracorekit:"^0.1" +php artisan laracorekit:install +``` + +Follow [installation](/docs/installation) for database setup, migrations and administrator creation. Packagist registration and the first tag are complete. Never recreate or move a published tag. + +Source remains in `packages/core`; the standalone repository receives package-only exports. The website/demo root is not the library. Review compatibility and release notes before each new tag. + +## Release checks + +```bash +composer validate --strict +composer --working-dir=packages/core validate --strict +composer audit --locked +npm ci +npm audit +npm run build:core +npm run build +composer test +composer phpstan +``` + +Run the documented clean-consumer smoke check as well. Keep the release blocked on unresolved security findings or installation failures. Publish release notes with migration, asset and view-override changes. + +## Adoption statistics + +Packagist exposes download totals and daily/monthly counts through its [statistics API](https://packagist.org/apidoc). They are not unique developers, new projects or active installations. CI and reinstallations affect counts. The package sends no telemetry and does not require registration. + +The host command `php artisan laracorekit:stats` records validated daily download snapshots on the local storage disk under `metrics/packagist/YYYY-MM-DD.json`. Missing packages produce no snapshot; invalid/network responses fail without inventing zeros. Repeated runs on the same UTC day reuse the existing snapshot. + +After registration, set `LARACOREKIT_COLLECT_STATS=true` on the website host and run Laravel's scheduler. The command is scheduled daily at 07:23 in the application's configured timezone. Keep the local storage disk persistent and backed up. The command uses a public API and needs no Packagist token. These snapshots are distribution metrics, not installation telemetry. + +`python tools/package-release.py` builds a package-only review ZIP and checksum manifest under private `storage/app/releases`. The manual **Package Release Preview** GitHub workflow runs checks and uploads the archive for review. Neither publishes to Packagist or pushes a package repository automatically. + +## Ongoing source synchronization + +The distribution repository's **Sync Package Source** workflow checks the public monorepo main branch daily at 08:17 UTC or on manual dispatch. Its maintained template is `.github/package-workflows/sync-source.yml` in the monorepo; the executable copy lives under `.github/workflows` in the distribution repository. + +It validates the monorepo source, builds the package, tests a clean consumer, and opens a draft package-only update PR. It skips when extraction has not reached main yet, nothing has changed, or a prior package-sync PR is waiting for review. It preserves the distribution repository's maintenance workflow and never merges or tags a release. + +The job uses the distribution repository's own short-lived GITHUB_TOKEN, so no cross-repository personal token or Packagist secret is needed. The distribution repository must allow Actions to create pull requests. Review source updates before merging; then create a reviewed release tag for Packagist indexing. + +## Maintainer workflow for future releases + +1. Resolve the GitHub Actions account lock and pass the host PR checks. Review/merge the host extraction before daily source synchronization can read it from main. +2. Review the standalone package-only source export and prebuilt CSS. Keep its Composer name unchanged and omit a manual version field. +3. Run **Prepare Release PR** with the next reviewed version, for example `0.1.1` for a compatible patch. Review and merge its release notes. Do not reuse `0.1.0`. +4. In the package repository, publish a GitHub release with a new semantic tag targeting the reviewed commit. Never move existing tags or tag the demo repository as the core package. +5. Packagist registration is already complete. Verify the GitHub update integration is enabled and the new version appears on [the package page](https://packagist.org/packages/programmernomad/laracorekit). See [integration setup](https://packagist.org/about#how-to-update-packages) if needed; keep API tokens out of source and chat. +6. Test the new version in a fresh Laravel application: + +```bash +composer create-project laravel/laravel my-app "^13.0" +cd my-app +composer require programmernomad/laracorekit:"^0.1" +php artisan laracorekit:install +# Configure the application's .env and its database first. +php artisan migrate +php artisan laracorekit:admin +php artisan storage:link +``` + +7. Verify `/blog`, `/login` and `/admin`, then update the website's version references and deploy the reviewed host. Enable the optional statistics collector on persistent storage only after the public package endpoint works. + +Future updates use reviewed source-sync PRs, then a release-notes PR and a new semantic tag. Packagist's GitHub integration indexes pushed tags; Composer updates remain under each consuming application's control. Download totals are not unique new installations or developer identities. + +The distribution workflow template lives at `.github/package-workflows/prepare-release.yml`; the executable copy lives in the standalone repository. Official references: [Packagist publishing/integration](https://packagist.org/about), [Composer versioning](https://getcomposer.org/doc/02-libraries.md). + +After a release, mirror its changelog section into `packages/core/CHANGELOG.md` in the monorepo before the next source synchronization so that exported release history remains intact. diff --git a/docs/project-structure.md b/docs/project-structure.md index ab7f086..6174fe9 100644 --- a/docs/project-structure.md +++ b/docs/project-structure.md @@ -1,639 +1,46 @@ -# Project Structure +# Project structure ---- -**Supported Stack:** Laravel 13 / Filament 5 / Livewire 4 / Tailwind 4 -**Last Updated:** April 22, 2026 -**Estimated Time:** 10 minutes -**Difficulty:** Beginner to Intermediate ---- +The reusable package and the demo host have separate responsibilities. -Understanding LaraCoreKit's modular structure is essential for efficient development. This guide explains how the codebase is organized and where to find everything. - ---- - -## High-Level Overview - -``` +```text LaraCoreKit/ -├── app/ # Core application code -├── bootstrap/ # Framework bootstrap files -├── config/ # Configuration files -├── database/ # Migrations, seeders, factories -├── modules/ # Feature modules (THE KEY) -├── public/ # Web server document root -├── resources/ # Views, assets, lang files -├── routes/ # Route definitions -├── storage/ # Generated files, logs, cache -├── tests/ # Automated tests -└── vendor/ # Composer dependencies -``` - ---- - -## Core Directories - -### `/app` - Application Core - -Contains base application code that's **not** part of modules. Keep this minimal. - -``` -app/ -├── Console/ -│ └── Kernel.php # Console kernel -├── Exceptions/ -│ └── Handler.php # Exception handler -├── Http/ -│ ├── Controllers/ # Global controllers (minimal) -│ ├── Middleware/ # Global middleware -│ └── Kernel.php # HTTP kernel -├── Models/ -│ └── User.php # Base User model -├── Providers/ -│ ├── AppServiceProvider.php # Application services -│ └── ModuleServiceProvider.php # Loads modules -└── Filament/ - └── Pages/ # Global Filament pages (if any) -``` - -**Key Files:** - -- `Providers/ModuleServiceProvider.php` - Discovers and registers modules -- `Models/User.php` - Base user model (can be extended by User module) -- `Http/Kernel.php` - Registers global middleware - ---- - -### `/config` - Configuration - -All configuration files following Laravel conventions. - -``` -config/ -├── app.php # Application settings -├── auth.php # Authentication config -├── database.php # Database connections -├── filesystems.php # Storage disks -├── modules.php # Module configuration -├── permission.php # Spatie permission config -├── filament.php # Filament admin config -├── cache.php # Cache drivers -├── mail.php # Email settings -├── queue.php # Queue connections -└── services.php # Third-party services -``` - -**Key Configuration Files:** - -#### `config/modules.php` - -Defines enabled modules and their metadata: - -```php -return [ - 'namespace' => 'Modules', - - 'paths' => [ - 'modules' => base_path('modules'), - ], - - 'enabled' => [ - 'Core', - 'Auth', - 'User', - 'Blog', - 'Media', - 'Settings', - ], - - 'scan' => [ - 'enabled' => true, - 'paths' => [ - base_path('modules'), - ], - ], -]; -``` - ---- - -### `/modules` - Feature Modules - -**This is where the magic happens.** Each module is self-contained. - -``` -modules/ -├── Core/ # Base module (required) -│ ├── composer.json -│ └── src/ -│ ├── CoreServiceProvider.php -│ ├── Http/ -│ │ ├── Controllers/ -│ │ └── Middleware/ -│ ├── resources/ -│ │ ├── views/ -│ │ └── lang/ -│ └── routes/ -│ └── web.php -│ -├── Auth/ # Authentication module -│ └── src/ -│ ├── AuthServiceProvider.php -│ ├── Http/ -│ │ ├── Controllers/ -│ │ │ ├── LoginController.php -│ │ │ ├── RegisterController.php -│ │ │ └── PasswordResetController.php -│ │ └── Middleware/ -│ ├── resources/ -│ │ └── views/ -│ │ ├── login.blade.php -│ │ └── register.blade.php -│ └── routes/ -│ -├── Blog/ # Blog module -│ └── src/ -│ ├── BlogServiceProvider.php -│ ├── Models/ -│ │ └── Blog.php -│ ├── Filament/ -│ │ └── Resources/ -│ │ └── BlogResource.php -│ ├── Http/ -│ │ ├── Controllers/ -│ │ └── Livewire/ -│ │ ├── BlogList.php -│ │ └── BlogShow.php -│ ├── Database/ -│ │ ├── migrations/ -│ │ └── seeders/ -│ └── resources/ -│ ├── views/ -│ └── lang/ -│ -├── User/ # User management module -├── Media/ # Media management module -└── Settings/ # Settings module -``` - ---- - -## Module Structure (Standard) - -Every module follows this structure: - -``` -ModuleName/ -├── composer.json # Module metadata -├── README.md # Module documentation -└── src/ - ├── ModuleNameServiceProvider.php # Registers module - │ - ├── Models/ # Eloquent models - │ ├── Post.php - │ └── Category.php - │ - ├── Http/ - │ ├── Controllers/ # Controllers - │ │ └── PostController.php - │ ├── Middleware/ # Module middleware - │ │ └── CheckPostOwner.php - │ └── Livewire/ # Livewire components - │ └── PostForm.php - │ - ├── Filament/ # Filament admin - │ ├── Resources/ - │ │ └── PostResource.php - │ └── Pages/ - │ └── CustomPage.php - │ - ├── Console/ # Artisan commands - │ └── Commands/ - │ └── ImportPosts.php - │ - ├── Database/ - │ ├── migrations/ # Module migrations - │ ├── seeders/ # Module seeders - │ └── factories/ # Model factories - │ - ├── resources/ - │ ├── views/ # Blade views - │ │ ├── index.blade.php - │ │ └── show.blade.php - │ ├── lang/ # Translations - │ │ ├── en.json - │ │ └── hi.json - │ └── assets/ # Module assets (optional) - │ - ├── routes/ - │ ├── web.php # Web routes - │ └── api.php # API routes - │ - ├── config/ - │ └── module-name.php # Module config - │ - └── Tests/ # Module tests - ├── Unit/ - └── Feature/ -``` - ---- - -## Resources - -### `/resources` - Views & Assets - -``` -resources/ -├── views/ -│ ├── layouts/ # Global layouts -│ │ ├── app.blade.php -│ │ ├── guest.blade.php -│ │ └── admin.blade.php -│ ├── components/ # Blade components -│ │ ├── button.blade.php -│ │ └── card.blade.php -│ └── welcome.blade.php # Homepage -│ -├── css/ -│ └── app.css # Tailwind entry point -│ -├── js/ -│ ├── app.js # Vite entry point -│ └── bootstrap.js # Bootstrap JavaScript -│ -└── lang/ # Global translations (optional) - ├── en.json - ├── hi.json - └── ar.json -``` - -**Important:** - -- Module-specific views should live in `modules/{Module}/resources/views/` -- Global layouts and shared components go here -- Tailwind CSS compiles from `resources/css/app.css` - ---- - -## Routes - -### `/routes` - Routing - + packages/core/ programmernomad/laracorekit + composer.json package dependencies and discovery + src/CoreServiceProvider.php configuration and module registration + src/Console/ installer and administrator creation + src/Filament/ default package admin panel + config/laracorekit.php package defaults + modules/ Core, Auth, User, Settings, Media, Blog + resources/dist/ prebuilt public frontend CSS + app/ demo/site application and custom panel + modules/Docs/ website documentation viewer + modules/UIShowcase/ component demonstration application + resources/views/site/ marketing homepage and changelog + resources/views/vendor/core/ host override for shared layout + database/seeders/ safe defaults and guarded demo seeders + docs/ documentation source ``` -routes/ -├── web.php # Web routes -├── api.php # API routes -└── console.php # Console routes (Closure-based commands) -``` - -**How Routes Work:** - -1. **Global routes** in `routes/web.php` -2. **Module routes** in `modules/{Module}/src/routes/web.php` -3. Module routes are registered by `ModuleServiceProvider` - -Example module route registration: - -```php -// modules/Blog/src/BlogServiceProvider.php -public function boot() -{ - $this->loadRoutesFrom(__DIR__.'/routes/web.php'); -} -``` - ---- - -## Database - -### `/database` - Database Files - -``` -database/ -├── migrations/ # Global migrations -│ ├── 2024_01_01_000000_create_users_table.php -│ └── 2024_01_01_000001_create_password_resets_table.php -│ -├── seeders/ # Global seeders -│ ├── DatabaseSeeder.php -│ └── RoleSeeder.php -│ -└── factories/ # Model factories - └── UserFactory.php -``` - -**Note:** - -- Module-specific migrations are in `modules/{Module}/src/Database/migrations/` -- Module migrations are auto-discovered and loaded by the module service provider - ---- - -## Public Assets - -### `/public` - Web Root - -``` -public/ -├── index.php # Application entry point -├── .htaccess # Apache rewrite rules -├── robots.txt # SEO robots file -├── favicon.ico # Site favicon -│ -├── build/ # Vite build output -│ ├── manifest.json -│ └── assets/ -│ -├── storage/ # Symlink to storage/app/public -│ └── uploads/ -│ -├── css/ # Additional CSS (if any) -├── js/ # Additional JS (if any) -├── images/ # Static images -└── fonts/ # Web fonts -``` - -**Key Points:** - -- Never edit files in `public/build/` - they're auto-generated -- Use `php artisan storage:link` to create storage symlink -- Static assets can be accessed via `/images/logo.png` - ---- - -## Storage - -### `/storage` - Generated Files - -``` -storage/ -├── app/ -│ ├── public/ # Publicly accessible files -│ │ └── uploads/ -│ └── private/ # Private files -│ -├── framework/ -│ ├── cache/ # Framework cache -│ ├── sessions/ # Session files -│ └── views/ # Compiled Blade views -│ -└── logs/ - └── laravel.log # Application logs -``` - -**Permissions:** -Storage directory must be writable: - -```bash -chmod -R 775 storage -chmod -R 775 bootstrap/cache -``` - ---- - -## Testing - -### `/tests` - Automated Tests - -``` -tests/ -├── TestCase.php # Base test case -├── CreatesApplication.php # Test trait -│ -├── Feature/ # Feature tests -│ ├── Auth/ -│ │ ├── LoginTest.php -│ │ └── RegisterTest.php -│ └── Blog/ -│ └── BlogCrudTest.php -│ -└── Unit/ # Unit tests - └── Models/ - └── UserTest.php -``` - -**Module Tests:** - -Each module can have its own tests in `modules/{Module}/src/Tests/` - ---- - -## Configuration Files - -### Key Configuration - -#### `composer.json` - -Defines PHP dependencies and PSR-4 autoloading: - -```json -{ - "autoload": { - "psr-4": { - "App\\": "app/", - "Modules\\": "modules/", - "Database\\Seeders\\": "database/seeders/" - } - } -} -``` - -#### `package.json` - -Defines JavaScript dependencies: - -```json -{ - "devDependencies": { - "@tailwindcss/forms": "^0.5.0", - "tailwindcss": "^4.0.0", - "vite": "^5.0.0", - "laravel-vite-plugin": "^1.0.0" - } -} -``` - -#### `vite.config.js` - -Vite build configuration: - -```javascript -import { defineConfig } from 'vite'; -import laravel from 'laravel-vite-plugin'; - -export default defineConfig({ - plugins: [ - laravel({ - input: ['resources/css/app.css', 'resources/js/app.js'], - refresh: true, - }), - ], -}); -``` - -#### `tailwind.config.js` - -TailwindCSS configuration: - -```javascript -export default { - content: [ - './resources/**/*.blade.php', - './resources/**/*.js', - './modules/**/resources/**/*.blade.php', - './vendor/filament/**/*.blade.php', - ], - theme: { - extend: {}, - }, - plugins: [ - require('@tailwindcss/forms'), - ], -} -``` - ---- - -## Important Files - -### Root Directory Files - -``` -.env # Environment configuration (DO NOT COMMIT) -.env.example # Environment template -.gitignore # Git ignore rules -artisan # Artisan CLI tool -composer.json # PHP dependencies -composer.lock # Locked PHP versions -package.json # JavaScript dependencies -package-lock.json # Locked JS versions -phpunit.xml # PHPUnit configuration -README.md # Project readme -``` - ---- - -## File Naming Conventions - -### Controllers - -``` -{Name}Controller.php # Standard controller -{Name}ApiController.php # API controller -``` - -Examples: -- `PostController.php` -- `UserApiController.php` - -### Models - -``` -{SingularName}.php # Model name -``` - -Examples: -- `Post.php` -- `BlogCategory.php` - -### Migrations - -``` -{timestamp}_create_{table}_table.php -{timestamp}_add_{field}_to_{table}_table.php -``` - -Examples: -- `2024_01_01_000000_create_posts_table.php` -- `2024_01_02_000000_add_featured_to_posts_table.php` - -### Blade Views - -``` -{name}.blade.php # Standard view -{name}-{variant}.blade.php # Variant view -``` - -Examples: -- `index.blade.php` -- `show.blade.php` -- `form-create.blade.php` - ---- - -## Module Discovery - -### How Modules Are Loaded - -1. **ModuleServiceProvider** reads `config/modules.php` -2. Scans directories in `paths.modules` -3. Discovers `*ServiceProvider.php` files -4. Auto-registers enabled modules -5. Loads routes, migrations, views, translations - -### Module Registration Order - -Modules are loaded in the order specified in `config/modules.php`: - -```php -'enabled' => [ - 'Core', // 1. Loaded first (provides base functionality) - 'Auth', // 2. Authentication - 'User', // 3. User management - 'Blog', // 4. Blog features - 'Media', // 5. Media management - 'Settings', // 6. Settings last -], -``` - -**Important:** `Core` module must always be first. - ---- - -## Autoloading - -### PSR-4 Autoloading Map - -``` -App\ → app/ -Modules\ → modules/ -Database\Seeders\ → database/seeders/ -``` - -### Refresh Autoloader - -After adding new classes: - -```bash -composer dump-autoload -``` +Composer loads package namespaces and Laravel discovers `LaraCoreKit\Core\CoreServiceProvider`. It registers enabled module providers from `config/laracorekit.php` and the default panel when enabled. The host disables the default panel and provides its own. There is one registration contract; modules are no longer registered individually in the host's `bootstrap/providers.php`. ---- +## Public and admin features -## Next Steps +Auth and Blog register public routes and Livewire components. User, Settings, Blog and Media provide the models, migrations and admin resources. Core supplies the shared layout, locale component and middleware. The homepage, changelog, docs and UI demonstration are website responsibilities and are excluded from the Composer package. -Now that you understand the structure: +The first release bundles functional modules in one package to keep compatibility and releases manageable. Their internal boundaries remain available for future extraction. Installing the bundle installs its PHP dependencies; disabling Blog does not uninstall Media Library or remove database tables. -1. **[Learn Module System →](core/modules-system.md)** -2. **[Create Your First Module →](modules/create-module.md)** -3. **[Explore Configuration →](configuration.md)** +## Application ownership ---- +Keep application logic and view overrides outside `vendor/`. Your app owns its homepage, environment, mail, database, storage, queues and deployment. The installer publishes configuration and prebuilt public CSS. It does not overwrite your routes or create demo accounts. The default admin uses Filament's theme; the host's custom admin theme is separate. -## Quick Reference +The public model namespaces remain `Modules\...` for compatibility with existing code. Applications that already use those namespaces or the package's route names need conflict resolution. Existing applications must review user-model and data compatibility before installation. -| Directory | Purpose | Edit Frequency | -|-----------|---------|----------------| -| `/modules` | Feature modules | | -| `/resources/views` | Blade templates | | -| `/config` | Configuration | | -| `/routes` | Route definitions | | -| `/public` | Static assets | | -| `/app` | Core app code | | -| `/database` | Migrations/Seeders | | -| `/tests` | Automated tests | | +## Extension points ---- +- Publish config with `php artisan vendor:publish --tag=laracorekit-config`. +- Override namespaced Blade views under `resources/views/vendor/{namespace}`. +- Disable the packaged panel and register resources in your own Filament panel. +- Use normal Laravel packages with auto-discovered providers for additional modules. +- Re-publish assets after updates with `php artisan vendor:publish --tag=laracorekit-assets --force`. -**Understanding the structure is the first step to mastering LaraCoreKit!** +See [installation](/docs/installation) and [upgrade notes](/docs/upgrade-guide). diff --git a/docs/quick-start.md b/docs/quick-start.md index 0ccac5d..3d35096 100644 --- a/docs/quick-start.md +++ b/docs/quick-start.md @@ -1,405 +1,31 @@ -# Quick Start +# Quick start ---- -**Supported Stack:** Laravel 13 / Filament 5 / Livewire 4 / Tailwind 4 -**Last Updated:** April 22, 2026 -**Estimated Time:** 5 minutes -**Difficulty:** Beginner ---- +LaraCoreKit is published on Packagist. Choose the core package for your own application, or clone the main GitHub repository to run the website, docs and showcase. Both include public and admin features. -Get LaraCoreKit running locally in just a few commands. This guide assumes you have PHP 8.3+, Composer, and Node.js installed. +## New application with Composer (recommended) ---- - -## Prerequisites - -Before starting, ensure you have: - -- PHP 8.3 or higher -- Composer 2.x -- Node.js 18+ & npm -- MySQL, PostgreSQL, or SQLite -- Git - -### Check your environment: - -```bash -php -v # Should show 8.2+ -composer -V # Should show 2.x -node -v # Should show 18+ -``` - ---- - -## Installation (5 Minutes) - -### Step 1: Clone the Repository - -```bash -git clone https://github.com/ProgrammerNomad/LaraCoreKit.git -cd LaraCoreKit -``` - -**Expected output:** -``` -Cloning into 'LaraCoreKit'... -remote: Enumerating objects: 1523, done. -remote: Counting objects: 100% (1523/1523), done. -``` - ---- - -### Step 2: Install Dependencies - -```bash -composer install -npm install -``` - -**Expected output:** -``` -Installing dependencies from lock file -Package operations: 127 installs, 0 updates, 0 removals - - Installing doctrine/inflector (2.0.8) - - Installing illuminate/contracts (v11.x-dev) - ... -``` - -⏱ **This takes ~2-3 minutes** - ---- - -### Step 3: Environment Setup - -```bash -cp .env.example .env -php artisan key:generate -``` - -**Expected output:** -``` -Application key set successfully. -``` - ---- - -### Step 4: Configure Database - -Edit `.env` file: - -**Option A: SQLite (Easiest - Recommended for local)** - -```env -DB_CONNECTION=sqlite -# DB_DATABASE=database/database.sqlite # Commented out for SQLite -``` - -Create the database file: - -```bash -touch database/database.sqlite -``` - -**Option B: MySQL** - -```env -DB_CONNECTION=mysql -DB_HOST=127.0.0.1 -DB_PORT=3306 -DB_DATABASE=laracorekit -DB_USERNAME=root -DB_PASSWORD=your_password -``` - ---- - -### Step 5: Run Migrations & Seeders - -```bash -php artisan migrate --seed -``` - -**Expected output:** -``` -Migration table created successfully. -Migrating: 2024_01_01_000000_create_users_table -Migrated: 2024_01_01_000000_create_users_table (45.32ms) -... -Seeding: DatabaseSeeder -Seeded: DatabaseSeeder (123.45ms) -Database seeding completed successfully. -``` - -This creates: -- Database tables -- Demo admin user -- Sample blog posts -- Default roles & permissions - ---- - -### Step 6: Build Frontend Assets - -```bash -npm run build -``` - -**Expected output:** -``` -vite v5.0.0 building for production... -✓ 1234 modules transformed. -dist/assets/app-a1b2c3d4.css 123.45 kB -dist/assets/app-a1b2c3d4.js 456.78 kB -✓ built in 3.21s -``` - ---- - -### Step 7: Start Development Server - -```bash -php artisan serve -``` - -**Expected output:** -``` - INFO Server running on [http://127.0.0.1:8000]. - - Press Ctrl+C to stop the server -``` - ---- - -## Verify Installation - -### 1. Visit the Homepage - -Open in browser: **http://localhost:8000** - -You should see the LaraCoreKit landing page. - ---- - -### 2. Create Admin User - -Open a **new terminal** and run: - -```bash -php artisan filament:user -``` - -**Follow the prompts:** - -``` - Name: - > Admin User - - Email address: - > admin@laracorekit.com - - Password: - > ********** - - Success! Admin user created. -``` - ---- - -### 3. Access Admin Panel - -Visit: **http://localhost:8000/admin** - -Login with: -- **Email:** admin@laracorekit.com -- **Password:** (what you set above) - -You should see the Filament admin dashboard. - ---- - -### 4. View UI Components - -Visit: **http://localhost:8000/ui-showcase** - -Explore all 175+ UI components organized by category. - ---- - -## What You Just Installed - -### Modules Included: - -| Module | Description | Admin | Frontend | -|--------|-------------|-------|----------| -| **Core** | Module system, layouts, locale | - | | -| **Auth** | Login, register, email verify | | | -| **User** | User profiles, roles | | | -| **Blog** | Multilingual blog system | | | -| **Settings** | Site configuration | | API | -| **Media** | File uploads, gallery | | | - ---- - -## Next Steps - -### 1. Explore the Codebase +Requires PHP 8.3+ and Composer 2. First create Laravel; the package does not create the application for you. ```bash -# View project structure -tree -L 2 -I 'vendor|node_modules' - -# Or just explore in your code editor -code . +composer create-project laravel/laravel my-app "^13.0" +cd my-app +composer require programmernomad/laracorekit:"^0.1" +php artisan laracorekit:install ``` -### 2. Understand the Module System - -Read: **[Module System Guide](core/modules-system.md)** - -This is LaraCoreKit's killer feature - ---- - -### 3. Create Your First Module - -Follow: **[Create a Module](modules/create-module.md)** - -Learn how to build a custom module step-by-step. - ---- - -### 4. Customize the UI - -- Check out the **[UI Components](frontend/ui-showcase.md)** -- Modify **[Layouts](frontend/layouts.md)** -- Learn **[Livewire Basics](frontend/livewire.md)** - ---- - -### 5. Configure Settings - -Visit: **http://localhost:8000/admin/settings** - -Configure: -- Site name and description -- SEO defaults -- Supported languages -- Email settings - ---- - -## Development Workflow - -### Run in Development Mode +Keep Laravel's generated SQLite database for local evaluation, or configure your database in `.env`. Set `APP_URL=http://127.0.0.1:8000` and configure mail before testing password-reset delivery. Then: ```bash -# Terminal 1: Laravel server +php artisan migrate +php artisan laracorekit:admin +php artisan storage:link php artisan serve - -# Terminal 2: Vite dev server (hot reload) -npm run dev -``` - -**Access at:** http://localhost:8000 - -Changes to CSS/JS will hot-reload automatically. - ---- - -### Useful Commands - -```bash -# Clear all caches -php artisan optimize:clear - -# Run tests -php artisan test - -# Format code (PSR-12) -./vendor/bin/pint - -# Generate IDE helpers -php artisan ide-helper:generate - -# Run migrations fresh -php artisan migrate:fresh --seed -``` - ---- - -## Troubleshooting - -### Issue: "Class not found" errors - -**Solution:** -```bash -composer dump-autoload -php artisan optimize:clear -``` - ---- - -### Issue: Permission denied on storage/logs - -**Solution:** -```bash -chmod -R 775 storage bootstrap/cache ``` ---- - -### Issue: Vite build fails - -**Solution:** -```bash -rm -rf node_modules package-lock.json -npm install -npm run build -``` - ---- - -### Issue: Database connection failed - -**Solution:** - -1. Check `.env` database credentials -2. Ensure database server is running -3. For SQLite, verify file exists: - ```bash - touch database/database.sqlite - ``` - ---- - -## Demo Credentials - -If using the live demo: - -**Website:** https://www.laracorekit.com/ - -**Admin Panel:** https://www.laracorekit.com/admin - -Contact for demo credentials if needed. - ---- - -## Get Help - -- **[Full Documentation](introduction.md)** -- **[GitHub Issues](https://github.com/ProgrammerNomad/LaraCoreKit/issues)** - ---- - -## What's Next? - -Now that you have LaraCoreKit running: - -1. **[Understand Project Structure →](project-structure.md)** -2. **[Learn Module System →](core/modules-system.md)** -3. **[Create Your First Module →](modules/create-module.md)** +Visit `/blog`, `/login` and `/admin` at `http://127.0.0.1:8000`. The administrator command prompts for your own credentials. No sample users are created. Your application's `/` route remains yours; the marketing website, docs, showcase and sample content are not installed by the core. Default package assets are prebuilt, so npm is not required. ---- +## Complete website/demo from GitHub -**Congratulations! You're ready to build something amazing.** +The main repository already contains Laravel. Do not create another Laravel application. Follow [the complete GitHub host commands](/docs/installation#option-b-run-the-complete-github-demodevelopment-host) to clone it, install Composer dependencies, create `.env` and an application key, configure the database, migrate, create an administrator and build assets with Node. `git clone` and `composer install` alone do not finish setup. +Normal seeding creates roles only. For sample content and reset controls on a disposable database, follow [demo setup](/docs/deployment/demo-setup). For a deployed application, follow [production setup](/docs/deployment/production); `php artisan serve` is a local development server. diff --git a/docs/upgrade-guide.md b/docs/upgrade-guide.md new file mode 100644 index 0000000..6e583ea --- /dev/null +++ b/docs/upgrade-guide.md @@ -0,0 +1,27 @@ +# Upgrade guide + +## Migrating an existing LaraCoreKit checkout to the package layout + +Back up the application and database. Deploy source and lockfile together. The functional modules have moved from `modules/{Core,Auth,User,Settings,Media,Blog}` to `packages/core/modules`. Their public `Modules\...` namespaces and migration filenames are preserved. The media migration moved into the package with the same filename so an existing migration record prevents it from being rerun. + +Remove old individual module provider entries and obsolete `config/modules.php`. The package provider reads `config/laracorekit.php`. The host still registers its custom Filament panel and UIShowcase provider. Home and Changelog are now application Livewire components, with views under `resources/views/site`. + +Sample seeders moved into `Database\Seeders`. Normal seeding creates roles only, unless explicit demo mode is enabled. The demo reset package calls the default seeder, which delegates to the guarded DemoSeeder in demo mode. Do not run `migrate:fresh` against an existing customer database. + +```bash +composer install +php artisan optimize:clear +php artisan migrate +php artisan vendor:publish --tag=laracorekit-assets --force +npm ci +npm run build:core +npm run build +``` + +Review your copied view overrides against the package changes and verify authentication, resource permissions, blog publication and uploads in staging before deployment. Any public demo passwords previously used in a real deployment must be replaced. + +## Updating package consumers + +For the published package, use `composer update programmernomad/laracorekit --with-all-dependencies`, review the lockfile and release notes, run migrations and republish package assets. Application view overrides are preserved but may need manual changes. Minor releases before 1.0 can include breaking changes; pin a tested minor series. + +The migration does not automatically turn the demo host into a minimal customer app. For a clean application use the package installation path. diff --git a/modules/Auth/src/AuthServiceProvider.php b/modules/Auth/src/AuthServiceProvider.php deleted file mode 100644 index 8a71d51..0000000 --- a/modules/Auth/src/AuthServiceProvider.php +++ /dev/null @@ -1,27 +0,0 @@ -loadViewsFrom(__DIR__ . '/../views', 'auth'); - - \Illuminate\Support\Facades\Route::middleware('web') - ->group(__DIR__ . '/../routes/web.php'); - - Livewire::component('auth.login', \Modules\Auth\Http\Livewire\Login::class); - Livewire::component('auth.register', \Modules\Auth\Http\Livewire\Register::class); - Livewire::component('auth.forgot-password', \Modules\Auth\Http\Livewire\ForgotPassword::class); - Livewire::component('auth.dashboard', \Modules\Auth\Http\Livewire\Dashboard::class); - } -} diff --git a/modules/Blog/src/BlogServiceProvider.php b/modules/Blog/src/BlogServiceProvider.php deleted file mode 100644 index 1436cc9..0000000 --- a/modules/Blog/src/BlogServiceProvider.php +++ /dev/null @@ -1,31 +0,0 @@ -loadMigrationsFrom(__DIR__ . '/../database/migrations'); - - // Load views - $this->loadViewsFrom(__DIR__ . '/../views', 'blog'); - - // Register Livewire components - Livewire::component('blog.blog-list', \Modules\Blog\Http\Livewire\BlogList::class); - Livewire::component('blog.blog-detail', \Modules\Blog\Http\Livewire\BlogDetail::class); - - // Load routes - \Illuminate\Support\Facades\Route::middleware('web') - ->group(__DIR__ . '/../routes/web.php'); - } -} diff --git a/modules/Core/views/layouts/app.blade.php b/modules/Core/views/layouts/app.blade.php deleted file mode 100644 index 2ffaa6d..0000000 --- a/modules/Core/views/layouts/app.blade.php +++ /dev/null @@ -1,299 +0,0 @@ - - - - - - - - @php - $pageTitle = trim((string)($title ?? '')) ?: 'LaraCoreKit - Modular Laravel Starter Kit with Admin Panel, UI Components & Multilingual Support'; - $pageDescription = trim((string)($metaDescription ?? '')) ?: 'Build production-ready Laravel apps in minutes with LaraCoreKit. Includes Filament admin, 175+ UI components, multilingual support, and modular architecture.'; - $pageKeywords = trim((string)($metaKeywords ?? '')) ?: 'Laravel starter kit, Laravel admin panel, Filament, Livewire, Laravel boilerplate, Laravel template, multilingual Laravel, Laravel UI components, Laravel modular architecture'; - $pageRobots = trim((string)($robots ?? '')) ?: 'index, follow'; - $pageOgTitle = trim((string)($ogTitle ?? '')) ?: $pageTitle; - $pageOgDesc = trim((string)($ogDescription ?? '')) ?: $pageDescription; - $pageOgImage = trim((string)($ogImage ?? '')) ?: asset('images/og-preview.png'); - $pageOgType = trim((string)($ogType ?? '')) ?: 'website'; - @endphp - - {{ $pageTitle }} - - - - - - - - - - - - - - - - - - - - - - - - - - - @if(isset($structuredData) && trim((string)$structuredData) !== '') - {!! $structuredData !!} - @else - - @endif - - - - - - @vite(['resources/css/app.css', 'resources/js/app.js']) - @livewireStyles - - -
- - - - -
- {{ $slot }} -
- - - -
- - @livewireScripts - - - - diff --git a/modules/Core/views/livewire/home.blade.php b/modules/Core/views/livewire/home.blade.php deleted file mode 100644 index 3cf23ec..0000000 --- a/modules/Core/views/livewire/home.blade.php +++ /dev/null @@ -1,823 +0,0 @@ -
- -
-
-
-

- {{ __('LaraCoreKit') }} -

-

- {{ __('Build Production-Ready Laravel Apps in Minutes with Modular Architecture') }} -

-

- {{ __('Production-ready Laravel 13 starter with Filament Admin, Livewire, Multilingual Support (EN/HI/AR), Role-Based Permissions, and Modern UI') }} -

- -
-
-
- - -
-
-
- {{ __('Built with') }}: - - {{-- Laravel --}} - - - Laravel 13 - - - {{-- Livewire --}} - - - Livewire 4 - - - {{-- Filament (no simpleicon — use custom SVG) --}} - - - - - Filament 5 - - - {{-- TailwindCSS --}} - - - TailwindCSS 4 - - - {{-- Alpine.js --}} - - - Alpine.js 3 - - - {{-- PHP --}} - - - PHP 8.3 - - - {{-- Open Source badge --}} - - - - - {{ __('Open Source & Free') }} - -
-
-
- - -
-
-
- {{ __('Quick Start') }} -

- {{ __('Up and Running in 5 Minutes') }} -

-

- {{ __('No complex setup. Works out of the box.') }} -

-

- - {{ __('Works on Windows, Mac & Linux') }} -

-
- -
- -
- - - - bash - - -
- -
# Clone the repository
-git clone https://github.com/ProgrammerNomad/LaraCoreKit.git
-cd LaraCoreKit
-
-# Install dependencies
-composer install
-npm install
-
-# Setup environment
-cp .env.example .env
-php artisan key:generate
-
-# Setup database & seed demo data
-php artisan migrate --seed
-
-# Build frontend assets
-npm run build
-
-# Start development server
-php artisan serve
-
- - -
-
- - -
-
-
-

- {{ __('What is LaraCoreKit?') }} -

-
-
-

- {{ __('LaraCoreKit is a production-ready Laravel 13 starter kit designed for developers who want to build modern web applications quickly without reinventing the wheel.') }} -

-

- {{ __('It includes everything you need: Filament admin panel, Livewire components, multilingual support (English, Hindi, Arabic with RTL), role-based permissions, 175+ UI components, and a modular architecture that scales with your project.') }} -

-

- {{ __('Who is it for?') }} {{ __('Developers building SaaS applications, admin dashboards, multilingual websites, e-commerce platforms, or any Laravel project that needs a solid foundation.') }} -

-
-
-
- - -
-
-
-

- {{ __('Powerful Features') }} -

-

- {{ __('Everything you need to build modern web applications') }} -

-
- -
- -
-
- - - -
-

{{ __('Enterprise-Grade Role & Permission System') }}

-

{{ __('Complete RBAC with Spatie Permission package integrated with Filament') }}

-
- - -
-
- - - -
-

{{ __('Multilingual Support') }}

-

{{ __('JSON-based translations in English, Hindi, and Arabic with RTL support') }}

-
- - -
-
- - - -
-

{{ __('Filament Admin Panel') }}

-

{{ __('Beautiful admin interface with dark mode, resources, and custom pages') }}

-
- - -
-
- - - -
-

{{ __('Livewire 4 + Alpine.js') }}

-

{{ __('Reactive frontend components without writing JavaScript') }}

-
- - -
-
- - - -
-

{{ __('TailwindCSS 4') }}

-

{{ __('Modern utility-first CSS framework with custom design tokens') }}

-
- - -
-
- - - -
-

{{ __('Launch Faster with Pre-Built Architecture') }}

-

{{ __('SQLite for local dev, MySQL/PostgreSQL for production, with seeded data') }}

-
-
-
-
- - -
-
-
-

- {{ __('What Can You Build?') }} -

-

- {{ __('LaraCoreKit adapts to your vision') }} -

-
- -
- {{-- SaaS Dashboard --}} -
-
- -
-

{{ __('SaaS Dashboard') }}

-

{{ __('Multi-tenant SaaS with admin panel, user management, and subscription billing') }}

-
- - {{-- Admin Panel --}} -
-
- -
-

{{ __('Admin Panel') }}

-

{{ __('Content management system with Filament, CRUD operations, and advanced filters') }}

-
- - {{-- Multilingual Website --}} -
-
- -
-

{{ __('Multilingual Website') }}

-

{{ __('International websites with EN/HI/AR support, RTL layout, and locale switching') }}

-
- - {{-- Blog Platform --}} -
-
- -
-

{{ __('Blog Platform') }}

-

{{ __('SEO-optimized blog with categories, tags, rich text editor, and social sharing') }}

-
- - {{-- Portfolio Website --}} -
-
- -
-

{{ __('Portfolio Website') }}

-

{{ __('Showcase projects with media library, contact forms, and dynamic components') }}

-
- - {{-- E-commerce (Coming Soon) --}} -
-
- {{ __('Coming Soon') }} -
-
- -
-

{{ __('E-commerce Platform') }}

-

{{ __('Full online store with product management, cart, checkout, and payment gateways') }}

-
-
-
-
- - -
-
-
-

- {{ __('Why Not Plain Laravel?') }} -

-

- {{ __('See what you get out of the box') }} -

-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{{ __('Feature') }}{{ __('Plain Laravel') }}{{ __('LaraCoreKit') }}
{{ __('Authentication System') }}{{ __('Manual setup') }}
{{ __('Admin Panel') }}{{ __('Build from scratch') }}Filament 5
{{ __('Multilingual Support') }}{{ __('Manual implementation') }}EN/HI/AR + RTL
{{ __('UI Components') }}{{ __('From scratch') }}175+ Components
{{ __('Role & Permissions') }}{{ __('Complex setup') }}
{{ __('Dark Mode') }}{{ __('Manual CSS') }}
{{ __('Time to Production') }}2-4 {{ __('weeks') }}5 {{ __('minutes') }}
-
-
-
- - -
-
-
-

- {{ __('What Can You Build?') }} -

-

- {{ __('LaraCoreKit adapts to your vision') }} -

-
- -
- {{-- SaaS Dashboard --}} -
-
- -
-

{{ __('SaaS Dashboard') }}

-

{{ __('Multi-tenant SaaS with admin panel, user management, and subscription billing') }}

-
- - {{-- Admin Panel --}} -
-
- -
-

{{ __('Admin Panel') }}

-

{{ __('Content management system with Filament, CRUD operations, and advanced filters') }}

-
- - {{-- Multilingual Website --}} -
-
- -
-

{{ __('Multilingual Website') }}

-

{{ __('International websites with EN/HI/AR support, RTL layout, and locale switching') }}

-
- - {{-- Blog Platform --}} -
-
- -
-

{{ __('Blog Platform') }}

-

{{ __('SEO-optimized blog with categories, tags, rich text editor, and social sharing') }}

-
- - {{-- Portfolio Website --}} -
-
- -
-

{{ __('Portfolio Website') }}

-

{{ __('Showcase projects with media library, contact forms, and dynamic components') }}

-
- - {{-- E-commerce (Coming Soon) --}} -
-
- {{ __('Coming Soon') }} -
-
- -
-

{{ __('E-commerce Platform') }}

-

{{ __('Full online store with product management, cart, checkout, and payment gateways') }}

-
-
-
-
- - -
-
-
-

- {{ __('Why Not Plain Laravel?') }} -

-

- {{ __('See what you get out of the box') }} -

-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{{ __('Feature') }}{{ __('Plain Laravel') }}{{ __('LaraCoreKit') }}
{{ __('Authentication System') }}{{ __('Manual setup') }}
{{ __('Admin Panel') }}{{ __('Build from scratch') }}Filament 5
{{ __('Multilingual Support') }}{{ __('Manual implementation') }}EN/HI/AR + RTL
{{ __('UI Components') }}{{ __('From scratch') }}175+ Components
{{ __('Role & Permissions') }}{{ __('Complex setup') }}
{{ __('Dark Mode') }}{{ __('Manual CSS') }}
{{ __('Time to Production') }}2-4 {{ __('weeks') }}5 {{ __('minutes') }}
-
-
-
- - - - - - @if($latestPosts->isNotEmpty()) -
-
-
-
-

- {{ __('Latest Articles') }} -

-

- {{ __('Discover our latest insights and tutorials') }} -

-
- - {{ __('View all') }} >> - -
- -
- @foreach($latestPosts as $blog) - - @endforeach -
-
-
- @endif - - -
-
-
-

- {{ __('Frequently Asked Questions') }} -

-

- {{ __('Everything you need to know') }} -

-
- -
- {{-- FAQ 1 --}} -
- -
-
- {{ __('LaraCoreKit is a production-ready Laravel 13 starter kit with Filament admin panel, Livewire components, multilingual support, 175+ UI components, and role-based permissions. It helps you build modern web applications faster.') }} -
-
-
- - {{-- FAQ 2 --}} -
- -
-
- {{ __('Yes! LaraCoreKit is 100% free and open-source under the MIT License. You can use it for personal or commercial projects without any restrictions.') }} -
-
-
- - {{-- FAQ 3 --}} -
- -
-
- {{ __('Yes! LaraCoreKit includes built-in support for English, Hindi, and Arabic with RTL (right-to-left) layout support. You can easily add more languages using Laravel JSON translation files.') }} -
-
-
- - {{-- FAQ 4 --}} -
- -
-
- {{ __('Absolutely! LaraCoreKit includes authentication, authorization with roles & permissions, Filament admin panel, and modular architecture - perfect for SaaS applications. Many developers use it as their SaaS foundation.') }} -
-
-
- - {{-- FAQ 5 --}} -
- -
-
- {{ __('LaraCoreKit is built with Laravel 13, Livewire 4, Filament 5, TailwindCSS 4, Alpine.js 3, and PHP 8.3. All modern, well-maintained technologies.') }} -
-
-
- - {{-- FAQ 6 --}} -
- -
-
- {{ __('Simply clone the repository, run composer install and npm install, set up your .env file, migrate the database, and start building. Full installation guide is in the Quick Start section above.') }} -
-
-
-
-
-
- - -
-
-

- {{ __('Start Building Your Laravel App in Minutes') }} -

-

- {{ __('100% Open Source. MIT Licensed. Free Forever.') }} -

- -
-
- - - -
- - diff --git a/modules/Docs/src/DocsServiceProvider.php b/modules/Docs/src/DocsServiceProvider.php index 4399b18..456eb94 100644 --- a/modules/Docs/src/DocsServiceProvider.php +++ b/modules/Docs/src/DocsServiceProvider.php @@ -2,6 +2,7 @@ namespace Modules\Docs; +use Illuminate\Support\Facades\Route; use Illuminate\Support\ServiceProvider; class DocsServiceProvider extends ServiceProvider @@ -14,10 +15,10 @@ public function register(): void public function boot(): void { // Load views - $this->loadViewsFrom(__DIR__ . '/../views', 'docs'); + $this->loadViewsFrom(__DIR__.'/../views', 'docs'); // Load routes - \Illuminate\Support\Facades\Route::middleware('web') - ->group(__DIR__ . '/../routes/web.php'); + Route::middleware('web') + ->group(__DIR__.'/../routes/web.php'); } } diff --git a/modules/Docs/src/Http/Controllers/DocsController.php b/modules/Docs/src/Http/Controllers/DocsController.php index 0482c75..61e4380 100644 --- a/modules/Docs/src/Http/Controllers/DocsController.php +++ b/modules/Docs/src/Http/Controllers/DocsController.php @@ -5,6 +5,7 @@ use Illuminate\Http\Request; use Illuminate\Routing\Controller; use Illuminate\Support\Facades\File; +use Illuminate\Support\Str; use Parsedown; class DocsController extends Controller @@ -16,6 +17,8 @@ class DocsController extends Controller ['title' => 'Introduction', 'slug' => 'introduction'], ['title' => 'Quick Start', 'slug' => 'quick-start'], ['title' => 'Installation', 'slug' => 'installation'], + ['title' => 'Package Release', 'slug' => 'package-release'], + ['title' => 'Upgrade Guide', 'slug' => 'upgrade-guide'], ['title' => 'Project Structure', 'slug' => 'project-structure'], ['title' => 'Configuration', 'slug' => 'configuration'], ], @@ -64,7 +67,7 @@ class DocsController extends Controller 'API' => [ 'icon' => '', 'items' => [ - ['title' => 'API Auth (Sanctum)', 'slug' => 'api/sanctum'], + ['title' => 'Optional API (Sanctum)', 'slug' => 'api/sanctum'], ['title' => 'Endpoints', 'slug' => 'api/endpoints'], ['title' => 'Authentication', 'slug' => 'api/authentication'], ], @@ -109,29 +112,29 @@ class DocsController extends Controller public function show(Request $request, string $page = 'introduction') { $docsPath = base_path('docs'); - $filePath = $docsPath . '/' . $page . '.md'; + abort_unless(preg_match('/\A[a-z0-9]+(?:[\/-][a-z0-9]+)*\z/', $page), 404); + $filePath = $docsPath.'/'.$page.'.md'; - if (!File::exists($filePath)) { + if (! File::exists($filePath)) { // Try index.md fallback - $filePath = $docsPath . '/' . $page . '/index.md'; - if (!File::exists($filePath)) { + $filePath = $docsPath.'/'.$page.'/index.md'; + if (! File::exists($filePath)) { abort(404, 'Documentation page not found.'); } } $markdown = File::get($filePath); - $parsedown = new Parsedown(); + $parsedown = new Parsedown; $parsedown->setSafeMode(false); $content = $parsedown->text($markdown); // CRITICAL: Escape PHP open/close tags inside code blocks to prevent PHP's parser // from interpreting PHP open and close tags in documentation code examples as actual PHP tags. // This must be done BEFORE passing content to Blade's {!! $content !!}. - $content = str_replace('<' . '?php', '<?php', $content); - $content = str_replace('<' . '?=', '<?=', $content); - $content = str_replace('?' . '>', '?>', $content); - + $content = str_replace('<'.'?php', '<?php', $content); + $content = str_replace('<'.'?=', '<?=', $content); + $content = str_replace('?'.'>', '?>', $content); // Extract title from H1 or filename preg_match('/]*>(.*?)<\/h1>/i', $content, $matches); @@ -152,7 +155,7 @@ public function show(Request $request, string $page = 'introduction') // Find prev/next pages $allPages = $this->getAllPageSlugs(); $currentIndex = array_search($page, $allPages); - $prevPage = ($currentIndex > 0) ? $this->findPageBySlug($allPages[$currentIndex - 1]) : null; + $prevPage = ($currentIndex !== false && $currentIndex > 0) ? $this->findPageBySlug($allPages[$currentIndex - 1]) : null; $nextPage = ($currentIndex !== false && $currentIndex < count($allPages) - 1) ? $this->findPageBySlug($allPages[$currentIndex + 1]) : null; // Flat array of all pages for search (pre-computed to avoid Blade arrow-function parsing issues) @@ -164,18 +167,60 @@ public function show(Request $request, string $page = 'introduction') } return view('docs::show', [ - 'content' => $content, - 'title' => $title, - 'page' => $page, - 'sidebar' => $this->sidebar, - 'meta' => $meta, - 'breadcrumb' => $breadcrumb, - 'prevPage' => $prevPage, - 'nextPage' => $nextPage, + 'content' => $content, + 'title' => $title, + 'page' => $page, + 'sidebar' => $this->sidebar, + 'meta' => $meta, + 'breadcrumb' => $breadcrumb, + 'prevPage' => $prevPage, + 'nextPage' => $nextPage, 'searchPages' => $searchPages, + 'description' => Str::limit(preg_replace('/\s+/', ' ', strip_tags($content)), 155), ]); } + public function publishedPages(): array + { + return array_values(array_filter($this->getAllPageSlugs(), fn (string $slug): bool => is_file(base_path('docs/'.$slug.'.md')) || is_file(base_path('docs/'.$slug.'/index.md')) + )); + } + + public function source(string $page) + { + abort_unless(in_array($page, $this->publishedPages(), true), 404); + $path = base_path('docs/'.$page.'.md'); + if (! is_file($path)) { + $path = base_path('docs/'.$page.'/index.md'); + } + + return response(file_get_contents($path), 200) + ->header('Content-Type', 'text/plain; charset=UTF-8') + ->header('X-Content-Type-Options', 'nosniff'); + } + + public function machineIndex() + { + $lines = [ + '# LaraCoreKit', '', + '> MIT-licensed Laravel 13 foundation for both public frontend and Filament 5 administration.', '', + 'Package: programmernomad/laracorekit. Source: packages/core in the GitHub monorepo.', + 'Status: standalone Packagist release pending. Install directly from the GitHub package repository using the documented Composer VCS setup.', + 'Includes Auth, User, Settings, Blog, Media and shared Core infrastructure.', + 'The demo website, docs viewer, showcase and demo accounts are not part of the package.', + 'API tokens, enforced email verification, billing and tenancy are not bundled.', '', + '## Documentation', '', + ]; + foreach ($this->publishedPages() as $slug) { + $page = $this->findPageBySlug($slug); + $lines[] = '- ['.$page['title'].']('.url('/docs/'.$slug).'): Markdown source at '.url('/docs-source/'.$slug); + } + $lines[] = ''; + $lines[] = 'Source: https://github.com/ProgrammerNomad/LaraCoreKit'; + + return response(implode("\n", $lines)."\n", 200)->header('Content-Type', 'text/plain; charset=UTF-8'); + } + protected function buildBreadcrumb(string $page): array { $parts = explode('/', $page); @@ -183,13 +228,14 @@ protected function buildBreadcrumb(string $page): array if (count($parts) > 1) { $crumbs[] = [ 'title' => ucwords($parts[0]), - 'slug' => null, + 'slug' => null, ]; } $crumbs[] = [ 'title' => ucwords(str_replace('-', ' ', end($parts))), - 'slug' => $page, + 'slug' => $page, ]; + return $crumbs; } @@ -201,6 +247,7 @@ protected function getAllPageSlugs(): array $slugs[] = $item['slug']; } } + return $slugs; } @@ -213,6 +260,7 @@ protected function findPageBySlug(string $slug): ?array } } } + return null; } } diff --git a/modules/Docs/views/show.blade.php b/modules/Docs/views/show.blade.php index b95626a..4408dd7 100644 --- a/modules/Docs/views/show.blade.php +++ b/modules/Docs/views/show.blade.php @@ -3,8 +3,9 @@ + {{ $title ?? 'Documentation' }} - LaraCoreKit - + @@ -12,15 +13,15 @@ - - + + - - + + @@ -154,13 +155,14 @@
- +
Docs
+
-