Initial commit
This commit is contained in:
commit
737e705755
59 changed files with 1563 additions and 0 deletions
24
.editorconfig
Normal file
24
.editorconfig
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[*.{yml,yaml}]
|
||||
indent_size = 2
|
||||
|
||||
[*.{js,jsx,ts,tsx,vue}]
|
||||
indent_size = 2
|
||||
|
||||
[*.json]
|
||||
indent_size = 2
|
||||
|
||||
[docker-compose.yml]
|
||||
indent_size = 2
|
||||
76
.env.example
Normal file
76
.env.example
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
APP_NAME="Core PHP App"
|
||||
APP_ENV=local
|
||||
APP_KEY=
|
||||
APP_DEBUG=true
|
||||
APP_TIMEZONE=UTC
|
||||
APP_URL=http://localhost
|
||||
|
||||
APP_LOCALE=en_GB
|
||||
APP_FALLBACK_LOCALE=en_GB
|
||||
APP_FAKER_LOCALE=en_GB
|
||||
|
||||
APP_MAINTENANCE_DRIVER=file
|
||||
|
||||
BCRYPT_ROUNDS=12
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
LOG_STACK=single
|
||||
LOG_DEPRECATIONS_CHANNEL=null
|
||||
LOG_LEVEL=debug
|
||||
|
||||
DB_CONNECTION=sqlite
|
||||
# DB_HOST=127.0.0.1
|
||||
# DB_PORT=3306
|
||||
# DB_DATABASE=core
|
||||
# DB_USERNAME=root
|
||||
# DB_PASSWORD=
|
||||
|
||||
SESSION_DRIVER=database
|
||||
SESSION_LIFETIME=120
|
||||
SESSION_ENCRYPT=false
|
||||
SESSION_PATH=/
|
||||
SESSION_DOMAIN=null
|
||||
|
||||
BROADCAST_CONNECTION=log
|
||||
FILESYSTEM_DISK=local
|
||||
QUEUE_CONNECTION=database
|
||||
|
||||
CACHE_STORE=database
|
||||
CACHE_PREFIX=
|
||||
|
||||
MEMCACHED_HOST=127.0.0.1
|
||||
|
||||
REDIS_CLIENT=phpredis
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_MAILER=log
|
||||
MAIL_HOST=127.0.0.1
|
||||
MAIL_PORT=2525
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
MAIL_ENCRYPTION=null
|
||||
MAIL_FROM_ADDRESS="hello@example.com"
|
||||
MAIL_FROM_NAME="${APP_NAME}"
|
||||
|
||||
AWS_ACCESS_KEY_ID=
|
||||
AWS_SECRET_ACCESS_KEY=
|
||||
AWS_DEFAULT_REGION=us-east-1
|
||||
AWS_BUCKET=
|
||||
AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||
|
||||
VITE_APP_NAME="${APP_NAME}"
|
||||
|
||||
# Core PHP Framework
|
||||
CORE_CACHE_DISCOVERY=true
|
||||
|
||||
# CDN Configuration (optional)
|
||||
CDN_ENABLED=false
|
||||
CDN_DRIVER=bunny
|
||||
BUNNYCDN_API_KEY=
|
||||
BUNNYCDN_STORAGE_ZONE=
|
||||
BUNNYCDN_PULL_ZONE=
|
||||
|
||||
# Flux Pro (optional)
|
||||
FLUX_LICENSE_KEY=
|
||||
12
.gemini/settings.json
Normal file
12
.gemini/settings.json
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"$schema": "https://schema.gemini.google.dev/settings.json",
|
||||
"codeAssist": {
|
||||
"enabled": true,
|
||||
"contextFiles": [
|
||||
"GEMINI.md",
|
||||
"CLAUDE.md",
|
||||
"composer.json",
|
||||
"config/core.php"
|
||||
]
|
||||
}
|
||||
}
|
||||
11
.gitattributes
vendored
Normal file
11
.gitattributes
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
* text=auto eol=lf
|
||||
|
||||
*.blade.php diff=html
|
||||
*.css diff=css
|
||||
*.html diff=html
|
||||
*.md diff=markdown
|
||||
*.php diff=php
|
||||
|
||||
/.github export-ignore
|
||||
CHANGELOG.md export-ignore
|
||||
.styleci.yml export-ignore
|
||||
4
.github/FUNDING.yml
vendored
Normal file
4
.github/FUNDING.yml
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# GitHub Sponsors configuration
|
||||
# Support Trees for the Future through our fundraiser
|
||||
|
||||
custom: ["https://donate.trees.org/-/NPMMSVUP?member=SWZTDDWH"]
|
||||
83
.github/copilot-instructions.md
vendored
Normal file
83
.github/copilot-instructions.md
vendored
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
# GitHub Copilot Instructions
|
||||
|
||||
## Project Overview
|
||||
|
||||
This is a Laravel application using the Core PHP Framework - a modular monolith architecture with event-driven module registration.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Module System
|
||||
- Modules live in `app/Mod/{ModuleName}/`
|
||||
- Each module has a `Boot.php` class with event listeners
|
||||
- Events: `WebRoutesRegistering`, `ApiRoutesRegistering`, `AdminPanelBooting`
|
||||
|
||||
### Example Boot.php
|
||||
```php
|
||||
<?php
|
||||
|
||||
namespace App\Mod\Blog;
|
||||
|
||||
use Core\Events\WebRoutesRegistering;
|
||||
use Core\Events\ApiRoutesRegistering;
|
||||
|
||||
class Boot
|
||||
{
|
||||
public static array $listens = [
|
||||
WebRoutesRegistering::class => 'onWebRoutes',
|
||||
ApiRoutesRegistering::class => 'onApiRoutes',
|
||||
];
|
||||
|
||||
public function onWebRoutes(WebRoutesRegistering $event): void
|
||||
{
|
||||
$event->routes(fn() => require __DIR__.'/Routes/web.php');
|
||||
$event->views('blog', __DIR__.'/Views');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Coding Standards
|
||||
|
||||
### Language
|
||||
- Use UK English (colour, organisation, centre, behaviour)
|
||||
- No American spellings (color, organization, center, behavior)
|
||||
|
||||
### PHP Style
|
||||
- PSR-12 with Laravel conventions
|
||||
- Strict types: `declare(strict_types=1);`
|
||||
- Type hints on all parameters and return types
|
||||
- Final classes by default unless inheritance is intended
|
||||
|
||||
### Naming
|
||||
- Models: singular PascalCase (`Post`, `Comment`)
|
||||
- Tables: plural snake_case (`posts`, `comments`)
|
||||
- Controllers: `{Model}Controller`
|
||||
- Livewire: `{Feature}Page`, `{Feature}Modal`
|
||||
|
||||
### Testing
|
||||
- Use Pest, not PHPUnit directly
|
||||
- Feature tests for HTTP/Livewire
|
||||
- Unit tests for services/utilities
|
||||
|
||||
## UI Framework
|
||||
|
||||
- **Livewire 3** for reactive components
|
||||
- **Flux Pro** for UI components (not vanilla Alpine)
|
||||
- **Tailwind CSS** for styling
|
||||
- **Font Awesome Pro** for icons (not Heroicons)
|
||||
|
||||
## Key Packages
|
||||
|
||||
| Package | Purpose |
|
||||
|---------|---------|
|
||||
| `host-uk/core` | Core framework, events, modules |
|
||||
| `host-uk/core-admin` | Admin panel, modals |
|
||||
| `host-uk/core-api` | REST API, rate limiting |
|
||||
| `host-uk/core-mcp` | AI agent tools (MCP) |
|
||||
|
||||
## Don't
|
||||
|
||||
- Don't use Heroicons (use Font Awesome Pro)
|
||||
- Don't use vanilla Alpine components (use Flux Pro)
|
||||
- Don't create controllers for Livewire pages
|
||||
- Don't use American English spellings
|
||||
- Don't add unnecessary abstractions
|
||||
29
.github/dependabot.yml
vendored
Normal file
29
.github/dependabot.yml
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
version: 2
|
||||
|
||||
updates:
|
||||
- package-ecosystem: composer
|
||||
directory: /
|
||||
schedule:
|
||||
interval: weekly
|
||||
open-pull-requests-limit: 5
|
||||
labels:
|
||||
- dependencies
|
||||
- php
|
||||
|
||||
- package-ecosystem: npm
|
||||
directory: /
|
||||
schedule:
|
||||
interval: weekly
|
||||
open-pull-requests-limit: 5
|
||||
labels:
|
||||
- dependencies
|
||||
- javascript
|
||||
|
||||
- package-ecosystem: github-actions
|
||||
directory: /
|
||||
schedule:
|
||||
interval: monthly
|
||||
open-pull-requests-limit: 3
|
||||
labels:
|
||||
- dependencies
|
||||
- ci
|
||||
62
.github/package-workflows/README.md
vendored
Normal file
62
.github/package-workflows/README.md
vendored
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
# Package Workflows
|
||||
|
||||
These workflow templates are for **library packages** (host-uk/core, host-uk/core-api, etc.), not application projects.
|
||||
|
||||
## README Badges
|
||||
|
||||
Add these badges to your package README (replace `{package}` with your package name):
|
||||
|
||||
```markdown
|
||||
[](https://github.com/host-uk/{package}/actions/workflows/ci.yml)
|
||||
[](https://codecov.io/gh/host-uk/{package})
|
||||
[](https://packagist.org/packages/host-uk/{package})
|
||||
[](https://packagist.org/packages/host-uk/{package})
|
||||
[](LICENSE)
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Copy the relevant workflows to your library's `.github/workflows/` directory:
|
||||
|
||||
```bash
|
||||
# In your library repo
|
||||
mkdir -p .github/workflows
|
||||
cp path/to/core-template/.github/package-workflows/ci.yml .github/workflows/
|
||||
cp path/to/core-template/.github/package-workflows/release.yml .github/workflows/
|
||||
```
|
||||
|
||||
## Workflows
|
||||
|
||||
### ci.yml
|
||||
- Runs on push/PR to main
|
||||
- Tests against PHP 8.2, 8.3, 8.4
|
||||
- Tests against Laravel 11 and 12
|
||||
- Runs Pint linting
|
||||
- Runs Pest tests
|
||||
|
||||
### release.yml
|
||||
- Triggers on version tags (v*)
|
||||
- Generates changelog using git-cliff
|
||||
- Creates GitHub release
|
||||
|
||||
## Requirements
|
||||
|
||||
For these workflows to work, your package needs:
|
||||
|
||||
1. **cliff.toml** - Copy from core-template root
|
||||
2. **Pest configured** - `composer require pestphp/pest --dev`
|
||||
3. **Pint configured** - `composer require laravel/pint --dev`
|
||||
4. **CODECOV_TOKEN** - Add to repo secrets for coverage uploads
|
||||
5. **FUNDING.yml** - Copy `.github/FUNDING.yml` for sponsor button
|
||||
|
||||
## Recommended composer.json scripts
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"lint": "pint",
|
||||
"test": "pest",
|
||||
"test:coverage": "pest --coverage"
|
||||
}
|
||||
}
|
||||
```
|
||||
55
.github/package-workflows/ci.yml
vendored
Normal file
55
.github/package-workflows/ci.yml
vendored
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
# CI workflow for library packages (host-uk/core-*, etc.)
|
||||
# Copy this to .github/workflows/ci.yml in library repos
|
||||
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
php: [8.2, 8.3, 8.4]
|
||||
laravel: [11.*, 12.*]
|
||||
exclude:
|
||||
- php: 8.2
|
||||
laravel: 12.*
|
||||
|
||||
name: PHP ${{ matrix.php }} / Laravel ${{ matrix.laravel }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite
|
||||
coverage: pcov
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
composer require "laravel/framework:${{ matrix.laravel }}" --no-interaction --no-update
|
||||
composer update --prefer-dist --no-interaction --no-progress
|
||||
|
||||
- name: Run Pint
|
||||
run: vendor/bin/pint --test
|
||||
|
||||
- name: Run tests
|
||||
run: vendor/bin/pest --ci --coverage --coverage-clover coverage.xml
|
||||
|
||||
- name: Upload coverage to Codecov
|
||||
if: matrix.php == '8.3' && matrix.laravel == '12.*'
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
files: coverage.xml
|
||||
fail_ci_if_error: false
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
40
.github/package-workflows/release.yml
vendored
Normal file
40
.github/package-workflows/release.yml
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# Release workflow for library packages
|
||||
# Copy this to .github/workflows/release.yml in library repos
|
||||
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
name: Create Release
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Generate changelog
|
||||
id: changelog
|
||||
uses: orhun/git-cliff-action@v3
|
||||
with:
|
||||
config: cliff.toml
|
||||
args: --latest --strip header
|
||||
env:
|
||||
OUTPUT: CHANGELOG.md
|
||||
|
||||
- name: Create release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
body_path: CHANGELOG.md
|
||||
generate_release_notes: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
68
.github/workflows/ci.yml
vendored
Normal file
68
.github/workflows/ci.yml
vendored
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
if: github.event.repository.visibility == 'public'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
php: [8.2, 8.3, 8.4]
|
||||
|
||||
name: PHP ${{ matrix.php }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite
|
||||
coverage: pcov
|
||||
|
||||
- name: Install dependencies
|
||||
run: composer install --prefer-dist --no-interaction --no-progress
|
||||
|
||||
- name: Run Pint
|
||||
run: vendor/bin/pint --test
|
||||
|
||||
- name: Run tests
|
||||
run: vendor/bin/pest --ci --coverage --coverage-clover coverage.xml
|
||||
|
||||
- name: Upload coverage to Codecov
|
||||
if: matrix.php == '8.3'
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
files: coverage.xml
|
||||
fail_ci_if_error: false
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
assets:
|
||||
if: github.event.repository.visibility == 'public'
|
||||
runs-on: ubuntu-latest
|
||||
name: Assets
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: npm
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Build assets
|
||||
run: npm run build
|
||||
38
.github/workflows/release.yml
vendored
Normal file
38
.github/workflows/release.yml
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
release:
|
||||
if: github.event.repository.visibility == 'public'
|
||||
runs-on: ubuntu-latest
|
||||
name: Create Release
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Generate changelog
|
||||
id: changelog
|
||||
uses: orhun/git-cliff-action@v4
|
||||
with:
|
||||
config: cliff.toml
|
||||
args: --latest --strip header
|
||||
env:
|
||||
OUTPUT: CHANGELOG.md
|
||||
|
||||
- name: Create release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
body_path: CHANGELOG.md
|
||||
generate_release_notes: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
24
.gitignore
vendored
Normal file
24
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
.DS_Store
|
||||
/.phpunit.cache
|
||||
/node_modules
|
||||
/public/build
|
||||
/public/hot
|
||||
/public/storage
|
||||
/storage/*.key
|
||||
/storage/pail
|
||||
/vendor
|
||||
.env
|
||||
.env.backup
|
||||
.env.production
|
||||
.phpactor.json
|
||||
.phpunit.result.cache
|
||||
Homestead.json
|
||||
Homestead.yaml
|
||||
auth.json
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
/.fleet
|
||||
/.idea
|
||||
/.nova
|
||||
/.vscode
|
||||
/.zed
|
||||
124
AGENTS.md
Normal file
124
AGENTS.md
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
# AI Agent Instructions
|
||||
|
||||
> For Jules, Devin, and other autonomous coding agents.
|
||||
|
||||
## Quick Start
|
||||
|
||||
1. This is a Laravel 12 + Livewire 3 application
|
||||
2. Modules go in `app/Mod/{Name}/Boot.php`
|
||||
3. Use UK English (colour, not color)
|
||||
4. Run `vendor/bin/pint --dirty` before committing
|
||||
5. Run `vendor/bin/pest` to test
|
||||
|
||||
## Architecture
|
||||
|
||||
**Modular monolith** - Features are self-contained modules that register via events.
|
||||
|
||||
### Creating a Module
|
||||
|
||||
```bash
|
||||
php artisan make:mod {Name} --all
|
||||
```
|
||||
|
||||
Or manually create `app/Mod/{Name}/Boot.php`:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Mod\{Name};
|
||||
|
||||
use Core\Events\WebRoutesRegistering;
|
||||
|
||||
class Boot
|
||||
{
|
||||
public static array $listens = [
|
||||
WebRoutesRegistering::class => 'onWebRoutes',
|
||||
];
|
||||
|
||||
public function onWebRoutes(WebRoutesRegistering $event): void
|
||||
{
|
||||
$event->routes(fn() => require __DIR__.'/Routes/web.php');
|
||||
$event->views('{name}', __DIR__.'/Views');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Task Checklist
|
||||
|
||||
When implementing features:
|
||||
|
||||
- [ ] Create module in `app/Mod/{Name}/`
|
||||
- [ ] Add `Boot.php` with event listeners
|
||||
- [ ] Create routes in `Routes/web.php` or `Routes/api.php`
|
||||
- [ ] Create Livewire components in `Livewire/`
|
||||
- [ ] Create Blade views in `Views/`
|
||||
- [ ] Add migrations in `Migrations/`
|
||||
- [ ] Write tests in `Tests/`
|
||||
- [ ] Run `vendor/bin/pint --dirty`
|
||||
- [ ] Run `vendor/bin/pest`
|
||||
|
||||
## File Locations
|
||||
|
||||
| What | Where |
|
||||
|------|-------|
|
||||
| Models | `app/Mod/{Name}/Models/` |
|
||||
| Livewire | `app/Mod/{Name}/Livewire/` |
|
||||
| Views | `app/Mod/{Name}/Views/` |
|
||||
| Routes | `app/Mod/{Name}/Routes/` |
|
||||
| Migrations | `app/Mod/{Name}/Migrations/` |
|
||||
| Tests | `app/Mod/{Name}/Tests/` |
|
||||
| Services | `app/Mod/{Name}/Services/` |
|
||||
|
||||
## Critical Rules
|
||||
|
||||
1. **UK English** - colour, organisation, centre (never American spellings)
|
||||
2. **Strict types** - `declare(strict_types=1);` in every PHP file
|
||||
3. **Type hints** - All parameters and return types
|
||||
4. **Flux Pro** - Use Flux components, not vanilla Alpine
|
||||
5. **Font Awesome** - Use FA icons, not Heroicons
|
||||
6. **Pest** - Write tests using Pest syntax, not PHPUnit
|
||||
|
||||
## Example Livewire Component
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Mod\Blog\Livewire;
|
||||
|
||||
use App\Mod\Blog\Models\Post;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
|
||||
class PostListPage extends Component
|
||||
{
|
||||
use WithPagination;
|
||||
|
||||
public function render(): View
|
||||
{
|
||||
return view('blog::posts.index', [
|
||||
'posts' => Post::latest()->paginate(10),
|
||||
]);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Testing Example
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use App\Mod\Blog\Models\Post;
|
||||
|
||||
it('displays posts on the index page', function () {
|
||||
$posts = Post::factory()->count(3)->create();
|
||||
|
||||
$this->get('/blog')
|
||||
->assertOk()
|
||||
->assertSee($posts->first()->title);
|
||||
});
|
||||
```
|
||||
66
CLAUDE.md
Normal file
66
CLAUDE.md
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
# Core PHP Framework Project
|
||||
|
||||
## Architecture
|
||||
|
||||
Modular monolith using Core PHP Framework. Modules live in `app/Mod/{Name}/Boot.php`.
|
||||
|
||||
**Event-driven registration:**
|
||||
```php
|
||||
class Boot
|
||||
{
|
||||
public static array $listens = [
|
||||
WebRoutesRegistering::class => 'onWebRoutes',
|
||||
ApiRoutesRegistering::class => 'onApiRoutes',
|
||||
AdminPanelBooting::class => 'onAdminPanel',
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
composer run dev # Dev server (if configured)
|
||||
php artisan serve # Laravel dev server
|
||||
npm run dev # Vite
|
||||
./vendor/bin/pint --dirty # Format changed files
|
||||
php artisan test # All tests
|
||||
php artisan make:mod Blog # Create module
|
||||
```
|
||||
|
||||
## Module Structure
|
||||
|
||||
```
|
||||
app/Mod/Blog/
|
||||
├── Boot.php # Event listeners
|
||||
├── Models/ # Eloquent models
|
||||
├── Routes/
|
||||
│ ├── web.php # Web routes
|
||||
│ └── api.php # API routes
|
||||
├── Views/ # Blade templates
|
||||
├── Livewire/ # Livewire components
|
||||
├── Migrations/ # Database migrations
|
||||
└── Tests/ # Module tests
|
||||
```
|
||||
|
||||
## Packages
|
||||
|
||||
| Package | Purpose |
|
||||
|---------|---------|
|
||||
| `host-uk/core` | Core framework, events, module discovery |
|
||||
| `host-uk/core-admin` | Admin panel, Livewire modals |
|
||||
| `host-uk/core-api` | REST API, scopes, rate limiting, webhooks |
|
||||
| `host-uk/core-mcp` | Model Context Protocol for AI agents |
|
||||
|
||||
## Conventions
|
||||
|
||||
- UK English (colour, organisation, centre)
|
||||
- PSR-12 coding style (Laravel Pint)
|
||||
- Pest for testing
|
||||
- Livewire + Flux Pro for UI
|
||||
|
||||
## License
|
||||
|
||||
- `Core\` namespace and vendor packages: EUPL-1.2 (copyleft)
|
||||
- `app/Mod/*`, `app/Website/*`: Your choice (no copyleft)
|
||||
|
||||
See LICENSE for full details.
|
||||
122
GEMINI.md
Normal file
122
GEMINI.md
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
# Core PHP Framework - AI Assistant Context
|
||||
|
||||
> For Gemini Code Assist, Jules, and other Google AI tools.
|
||||
|
||||
## Project Type
|
||||
|
||||
Laravel 12 application using Core PHP Framework - a modular monolith with event-driven architecture.
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
app/
|
||||
├── Mod/ # Feature modules (your code)
|
||||
│ └── {Name}/
|
||||
│ ├── Boot.php # Event listeners
|
||||
│ ├── Models/
|
||||
│ ├── Routes/
|
||||
│ ├── Views/
|
||||
│ └── Livewire/
|
||||
├── Core/ # Local framework overrides (EUPL-1.2)
|
||||
└── Providers/
|
||||
|
||||
config/core.php # Framework configuration
|
||||
```
|
||||
|
||||
## Module Pattern
|
||||
|
||||
Every module has a `Boot.php` with static `$listens` array:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Mod\Shop;
|
||||
|
||||
use Core\Events\WebRoutesRegistering;
|
||||
use Core\Events\ApiRoutesRegistering;
|
||||
use Core\Events\AdminPanelBooting;
|
||||
|
||||
class Boot
|
||||
{
|
||||
public static array $listens = [
|
||||
WebRoutesRegistering::class => 'onWebRoutes',
|
||||
ApiRoutesRegistering::class => 'onApiRoutes',
|
||||
AdminPanelBooting::class => 'onAdminPanel',
|
||||
];
|
||||
|
||||
public function onWebRoutes(WebRoutesRegistering $event): void
|
||||
{
|
||||
$event->routes(fn() => require __DIR__.'/Routes/web.php');
|
||||
$event->views('shop', __DIR__.'/Views');
|
||||
}
|
||||
|
||||
public function onApiRoutes(ApiRoutesRegistering $event): void
|
||||
{
|
||||
$event->routes(fn() => require __DIR__.'/Routes/api.php');
|
||||
}
|
||||
|
||||
public function onAdminPanel(AdminPanelBooting $event): void
|
||||
{
|
||||
$event->navigation('Shop', 'shop.admin.index', 'shopping-cart');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Code Style Requirements
|
||||
|
||||
### Language: UK English
|
||||
- colour (not color)
|
||||
- organisation (not organization)
|
||||
- centre (not center)
|
||||
- behaviour (not behavior)
|
||||
- licence (noun), license (verb)
|
||||
|
||||
### PHP Standards
|
||||
- `declare(strict_types=1);` in all files
|
||||
- Full type hints (parameters + return types)
|
||||
- PSR-12 formatting (use Laravel Pint)
|
||||
- Pest for testing
|
||||
|
||||
### Naming Conventions
|
||||
| Type | Convention | Example |
|
||||
|------|------------|---------|
|
||||
| Model | Singular PascalCase | `Product` |
|
||||
| Table | Plural snake_case | `products` |
|
||||
| Controller | `{Model}Controller` | `ProductController` |
|
||||
| Livewire Page | `{Feature}Page` | `ProductListPage` |
|
||||
| Livewire Modal | `{Feature}Modal` | `EditProductModal` |
|
||||
|
||||
## UI Stack
|
||||
|
||||
- **Livewire 3** - Server-side reactivity
|
||||
- **Flux Pro** - UI component library (NOT vanilla Alpine)
|
||||
- **Tailwind CSS** - Utility-first styling
|
||||
- **Font Awesome Pro** - Icons (NOT Heroicons)
|
||||
|
||||
## Common Commands
|
||||
|
||||
```bash
|
||||
php artisan make:mod Blog --all # Create module with all features
|
||||
php artisan serve # Development server
|
||||
vendor/bin/pint --dirty # Format changed files
|
||||
vendor/bin/pest # Run tests
|
||||
```
|
||||
|
||||
## Packages
|
||||
|
||||
| Package | Namespace | Purpose |
|
||||
|---------|-----------|---------|
|
||||
| host-uk/core | `Core\` | Framework core |
|
||||
| host-uk/core-admin | `Core\Admin\` | Admin panel |
|
||||
| host-uk/core-api | `Core\Api\` | REST API |
|
||||
| host-uk/core-mcp | `Core\Mcp\` | AI agent tools |
|
||||
|
||||
## Avoid
|
||||
|
||||
- American English spellings
|
||||
- Heroicons (use Font Awesome)
|
||||
- Vanilla Alpine components (use Flux)
|
||||
- Over-engineering / premature abstraction
|
||||
- PHPUnit syntax (use Pest)
|
||||
108
LICENSE
Normal file
108
LICENSE
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
Core PHP Framework Template
|
||||
===========================
|
||||
|
||||
Copyright (c) 2026 Host UK / Snider
|
||||
|
||||
This project uses a dual-licensing approach:
|
||||
|
||||
|
||||
1. CORE FRAMEWORK CODE (EUPL-1.2)
|
||||
---------------------------------
|
||||
|
||||
The Core PHP Framework packages (host-uk/core, host-uk/core-admin,
|
||||
host-uk/core-api, host-uk/core-mcp) and any code within the `Core\`
|
||||
namespace are licensed under the European Union Public Licence v1.2
|
||||
(EUPL-1.2).
|
||||
|
||||
The full EUPL-1.2 license text is available at:
|
||||
https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
|
||||
|
||||
And in the Core PHP Framework repository:
|
||||
https://github.com/host-uk/core-php/blob/main/LICENSE
|
||||
|
||||
|
||||
2. APPLICATION CODE EXCEPTION
|
||||
-----------------------------
|
||||
|
||||
As the copyright holder, we grant the following additional permission:
|
||||
|
||||
Code you create within the following directories is EXEMPT from the
|
||||
EUPL-1.2 copyleft requirements and may be licensed under any terms
|
||||
you choose (including proprietary licenses):
|
||||
|
||||
app/Mod/ - Your feature modules
|
||||
app/Website/ - Your website/domain modules
|
||||
app/Service/ - Your service classes
|
||||
database/ - Your migrations, seeders, factories
|
||||
resources/ - Your views, assets, translations
|
||||
routes/ - Your route definitions
|
||||
tests/ - Your test files
|
||||
config/ - Your configuration files (except config/core.php)
|
||||
|
||||
This exception applies ONLY to original code you create in these
|
||||
directories. It does NOT apply to:
|
||||
|
||||
- Modified copies of Core framework code
|
||||
- Code that extends or overrides the `Core\` namespace
|
||||
- Derivative works of the Core framework itself
|
||||
|
||||
|
||||
3. CORE NAMESPACE MODIFICATIONS
|
||||
-------------------------------
|
||||
|
||||
If you create local overrides or extensions within the `Core\` namespace
|
||||
(e.g., in `app/Core/`), those modifications ARE subject to EUPL-1.2 and
|
||||
its copyleft requirements.
|
||||
|
||||
We encourage you to submit such modifications as pull requests to:
|
||||
https://github.com/host-uk/core-php
|
||||
|
||||
This requirement constitutes the consideration for the license grant
|
||||
herein. The Core PHP Framework is not provided without cost; rather,
|
||||
the license fee is paid in kind through the contribution of improvements
|
||||
to the community. By using this software, you acknowledge and agree that
|
||||
modifications to the Core\ namespace shall be made available to the
|
||||
community under the same terms, ensuring that all users benefit from
|
||||
collective improvements. This reciprocal obligation is a fundamental
|
||||
condition of the license grant and not merely a request.
|
||||
|
||||
|
||||
4. SUMMARY
|
||||
----------
|
||||
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ Location │ License │ Copyleft Required? │
|
||||
├─────────────────────────────────────────────────────────────────────┤
|
||||
│ vendor/host-uk/* │ EUPL-1.2 │ Yes │
|
||||
│ app/Core/* │ EUPL-1.2 │ Yes (submit as PR) │
|
||||
│ Core\ namespace │ EUPL-1.2 │ Yes │
|
||||
├─────────────────────────────────────────────────────────────────────┤
|
||||
│ app/Mod/* │ Your choice │ No │
|
||||
│ app/Website/* │ Your choice │ No │
|
||||
│ app/Service/* │ Your choice │ No │
|
||||
│ database/* │ Your choice │ No │
|
||||
│ resources/* │ Your choice │ No │
|
||||
│ routes/* │ Your choice │ No │
|
||||
│ tests/* │ Your choice │ No │
|
||||
└─────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
|
||||
5. WARRANTY DISCLAIMER
|
||||
----------------------
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
6. QUESTIONS
|
||||
------------
|
||||
|
||||
If you have questions about licensing, contact: hello@host.uk.com
|
||||
|
||||
For the full EUPL-1.2 text, see:
|
||||
https://github.com/host-uk/core-php/blob/main/LICENSE
|
||||
138
README.md
Normal file
138
README.md
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
# Core PHP Framework Project
|
||||
|
||||
[](https://github.com/host-uk/core-template/actions/workflows/ci.yml)
|
||||
[](https://codecov.io/gh/host-uk/core-template)
|
||||
[](https://packagist.org/packages/host-uk/core-template)
|
||||
[](https://laravel.com)
|
||||
[](LICENSE)
|
||||
|
||||
A modular monolith Laravel application built with Core PHP Framework.
|
||||
|
||||
## Features
|
||||
|
||||
- **Core Framework** - Event-driven module system with lazy loading
|
||||
- **Admin Panel** - Livewire-powered admin interface with Flux UI
|
||||
- **REST API** - Scoped API keys, rate limiting, webhooks, OpenAPI docs
|
||||
- **MCP Tools** - Model Context Protocol for AI agent integration
|
||||
|
||||
## Requirements
|
||||
|
||||
- PHP 8.2+
|
||||
- Composer 2.x
|
||||
- SQLite (default) or MySQL/PostgreSQL
|
||||
- Node.js 18+ (for frontend assets)
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
# Clone or create from template
|
||||
git clone https://github.com/host-uk/core-template.git my-project
|
||||
cd my-project
|
||||
|
||||
# Install dependencies
|
||||
composer install
|
||||
npm install
|
||||
|
||||
# Configure environment
|
||||
cp .env.example .env
|
||||
php artisan key:generate
|
||||
|
||||
# Set up database
|
||||
touch database/database.sqlite
|
||||
php artisan migrate
|
||||
|
||||
# Start development server
|
||||
php artisan serve
|
||||
```
|
||||
|
||||
Visit: http://localhost:8000
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
app/
|
||||
├── Console/ # Artisan commands
|
||||
├── Http/ # Controllers & Middleware
|
||||
├── Models/ # Eloquent models
|
||||
├── Mod/ # Your custom modules
|
||||
└── Providers/ # Service providers
|
||||
|
||||
config/
|
||||
└── core.php # Core framework configuration
|
||||
|
||||
routes/
|
||||
├── web.php # Public web routes
|
||||
├── api.php # REST API routes
|
||||
└── console.php # Artisan commands
|
||||
```
|
||||
|
||||
## Creating Modules
|
||||
|
||||
```bash
|
||||
# Create a new module with all features
|
||||
php artisan make:mod Blog --all
|
||||
|
||||
# Create module with specific features
|
||||
php artisan make:mod Shop --web --api --admin
|
||||
```
|
||||
|
||||
Modules follow the event-driven pattern:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
namespace App\Mod\Blog;
|
||||
|
||||
use Core\Events\WebRoutesRegistering;
|
||||
use Core\Events\ApiRoutesRegistering;
|
||||
use Core\Events\AdminPanelBooting;
|
||||
|
||||
class Boot
|
||||
{
|
||||
public static array $listens = [
|
||||
WebRoutesRegistering::class => 'onWebRoutes',
|
||||
ApiRoutesRegistering::class => 'onApiRoutes',
|
||||
AdminPanelBooting::class => 'onAdminPanel',
|
||||
];
|
||||
|
||||
public function onWebRoutes(WebRoutesRegistering $event): void
|
||||
{
|
||||
$event->routes(fn() => require __DIR__.'/Routes/web.php');
|
||||
$event->views('blog', __DIR__.'/Views');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Core Packages
|
||||
|
||||
| Package | Description |
|
||||
|---------|-------------|
|
||||
| `host-uk/core` | Core framework components |
|
||||
| `host-uk/core-admin` | Admin panel & Livewire modals |
|
||||
| `host-uk/core-api` | REST API with scopes & webhooks |
|
||||
| `host-uk/core-mcp` | Model Context Protocol tools |
|
||||
|
||||
## Flux Pro (Optional)
|
||||
|
||||
This template uses the free Flux UI components. If you have a Flux Pro license:
|
||||
|
||||
```bash
|
||||
# Configure authentication
|
||||
composer config http-basic.composer.fluxui.dev your-email your-license-key
|
||||
|
||||
# Add the repository
|
||||
composer config repositories.flux-pro composer https://composer.fluxui.dev
|
||||
|
||||
# Install Flux Pro
|
||||
composer require livewire/flux-pro
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
- [Core PHP Framework](https://github.com/host-uk/core-php)
|
||||
- [Getting Started Guide](https://host-uk.github.io/core-php/guide/)
|
||||
- [Architecture](https://host-uk.github.io/core-php/architecture/)
|
||||
|
||||
## License
|
||||
|
||||
EUPL-1.2 (European Union Public Licence)
|
||||
0
app/Http/Controllers/.gitkeep
Normal file
0
app/Http/Controllers/.gitkeep
Normal file
0
app/Mod/.gitkeep
Normal file
0
app/Mod/.gitkeep
Normal file
0
app/Models/.gitkeep
Normal file
0
app/Models/.gitkeep
Normal file
24
app/Providers/AppServiceProvider.php
Normal file
24
app/Providers/AppServiceProvider.php
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register any application services.
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap any application services.
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
15
artisan
Executable file
15
artisan
Executable file
|
|
@ -0,0 +1,15 @@
|
|||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
use Symfony\Component\Console\Input\ArgvInput;
|
||||
|
||||
define('LARAVEL_START', microtime(true));
|
||||
|
||||
// Register the Composer autoloader...
|
||||
require __DIR__.'/vendor/autoload.php';
|
||||
|
||||
// Bootstrap Laravel and handle the command...
|
||||
$status = (require_once __DIR__.'/bootstrap/app.php')
|
||||
->handleCommand(new ArgvInput);
|
||||
|
||||
exit($status);
|
||||
26
bootstrap/app.php
Normal file
26
bootstrap/app.php
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Foundation\Application;
|
||||
use Illuminate\Foundation\Configuration\Exceptions;
|
||||
use Illuminate\Foundation\Configuration\Middleware;
|
||||
|
||||
return Application::configure(basePath: dirname(__DIR__))
|
||||
->withProviders([
|
||||
// Core PHP Framework
|
||||
\Core\LifecycleEventProvider::class,
|
||||
\Core\Website\Boot::class,
|
||||
\Core\Front\Boot::class,
|
||||
\Core\Mod\Boot::class,
|
||||
])
|
||||
->withRouting(
|
||||
web: __DIR__.'/../routes/web.php',
|
||||
api: __DIR__.'/../routes/api.php',
|
||||
commands: __DIR__.'/../routes/console.php',
|
||||
health: '/up',
|
||||
)
|
||||
->withMiddleware(function (Middleware $middleware) {
|
||||
\Core\Front\Boot::middleware($middleware);
|
||||
})
|
||||
->withExceptions(function (Exceptions $exceptions) {
|
||||
//
|
||||
})->create();
|
||||
2
bootstrap/cache/.gitignore
vendored
Normal file
2
bootstrap/cache/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
*
|
||||
!.gitignore
|
||||
5
bootstrap/providers.php
Normal file
5
bootstrap/providers.php
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
App\Providers\AppServiceProvider::class,
|
||||
];
|
||||
48
cliff.toml
Normal file
48
cliff.toml
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
# git-cliff configuration
|
||||
# https://git-cliff.org
|
||||
|
||||
[changelog]
|
||||
header = """
|
||||
# Changelog\n
|
||||
All notable changes to this project will be documented in this file.\n
|
||||
"""
|
||||
body = """
|
||||
{% if version %}\
|
||||
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
|
||||
{% else %}\
|
||||
## [Unreleased]
|
||||
{% endif %}\
|
||||
{% for group, commits in commits | group_by(attribute="group") %}
|
||||
### {{ group | striptags | trim | upper_first }}
|
||||
{% for commit in commits %}
|
||||
- {% if commit.scope %}**{{ commit.scope }}:** {% endif %}\
|
||||
{{ commit.message | upper_first }}\
|
||||
{% endfor %}
|
||||
{% endfor %}\n
|
||||
"""
|
||||
footer = """
|
||||
<!-- generated by git-cliff -->
|
||||
"""
|
||||
trim = true
|
||||
|
||||
[git]
|
||||
conventional_commits = true
|
||||
filter_unconventional = true
|
||||
split_commits = false
|
||||
commit_parsers = [
|
||||
{ message = "^feat", group = "Features" },
|
||||
{ message = "^fix", group = "Bug Fixes" },
|
||||
{ message = "^doc", group = "Documentation" },
|
||||
{ message = "^perf", group = "Performance" },
|
||||
{ message = "^refactor", group = "Refactor" },
|
||||
{ message = "^style", group = "Styling" },
|
||||
{ message = "^test", group = "Testing" },
|
||||
{ message = "^chore\\(release\\)", skip = true },
|
||||
{ message = "^chore\\(deps.*\\)", skip = true },
|
||||
{ message = "^chore|^ci", group = "Miscellaneous" },
|
||||
{ body = ".*security", group = "Security" },
|
||||
]
|
||||
protect_breaking_commits = false
|
||||
filter_commits = false
|
||||
topo_order = false
|
||||
sort_commits = "oldest"
|
||||
78
composer.json
Normal file
78
composer.json
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
{
|
||||
"name": "host-uk/core-template",
|
||||
"type": "project",
|
||||
"description": "Core PHP Framework - Project Template",
|
||||
"keywords": ["laravel", "core-php", "modular", "framework", "template"],
|
||||
"license": "EUPL-1.2",
|
||||
"require": {
|
||||
"php": "^8.2",
|
||||
"laravel/framework": "^12.0",
|
||||
"laravel/tinker": "^2.10",
|
||||
"livewire/flux": "^2.0",
|
||||
"livewire/livewire": "^3.0",
|
||||
"host-uk/core": "dev-main",
|
||||
"host-uk/core-admin": "dev-main",
|
||||
"host-uk/core-api": "dev-main",
|
||||
"host-uk/core-mcp": "dev-main"
|
||||
},
|
||||
"require-dev": {
|
||||
"fakerphp/faker": "^1.23",
|
||||
"laravel/pail": "^1.2",
|
||||
"laravel/pint": "^1.18",
|
||||
"laravel/sail": "^1.41",
|
||||
"mockery/mockery": "^1.6",
|
||||
"nunomaduro/collision": "^8.6",
|
||||
"pestphp/pest": "^3.0",
|
||||
"pestphp/pest-plugin-laravel": "^3.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"App\\": "app/",
|
||||
"Database\\Factories\\": "database/factories/",
|
||||
"Database\\Seeders\\": "database/seeders/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Tests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
"type": "vcs",
|
||||
"url": "https://github.com/host-uk/core-php.git"
|
||||
}
|
||||
],
|
||||
"scripts": {
|
||||
"post-autoload-dump": [
|
||||
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
|
||||
"@php artisan package:discover --ansi"
|
||||
],
|
||||
"post-update-cmd": [
|
||||
"@php artisan vendor:publish --tag=laravel-assets --ansi --force"
|
||||
],
|
||||
"post-root-package-install": [
|
||||
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
|
||||
],
|
||||
"post-create-project-cmd": [
|
||||
"@php artisan key:generate --ansi",
|
||||
"@php -r \"file_exists('database/database.sqlite') || touch('database/database.sqlite');\"",
|
||||
"@php artisan migrate --graceful --ansi"
|
||||
]
|
||||
},
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"dont-discover": []
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"optimize-autoloader": true,
|
||||
"preferred-install": "dist",
|
||||
"sort-packages": true,
|
||||
"allow-plugins": {
|
||||
"php-http/discovery": true
|
||||
}
|
||||
},
|
||||
"minimum-stability": "stable",
|
||||
"prefer-stable": true
|
||||
}
|
||||
24
config/core.php
Normal file
24
config/core.php
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Core PHP Framework Configuration
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
'module_paths' => [
|
||||
app_path('Core'),
|
||||
app_path('Mod'),
|
||||
app_path('Website'),
|
||||
],
|
||||
|
||||
'services' => [
|
||||
'cache_discovery' => env('CORE_CACHE_DISCOVERY', true),
|
||||
],
|
||||
|
||||
'cdn' => [
|
||||
'enabled' => env('CDN_ENABLED', false),
|
||||
'driver' => env('CDN_DRIVER', 'bunny'),
|
||||
],
|
||||
];
|
||||
0
database/factories/.gitkeep
Normal file
0
database/factories/.gitkeep
Normal file
0
database/migrations/.gitkeep
Normal file
0
database/migrations/.gitkeep
Normal file
16
database/seeders/DatabaseSeeder.php
Normal file
16
database/seeders/DatabaseSeeder.php
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class DatabaseSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Seed the application's database.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
// Core modules handle their own seeding
|
||||
}
|
||||
}
|
||||
16
package.json
Normal file
16
package.json
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^10.4.20",
|
||||
"axios": "^1.7.4",
|
||||
"laravel-vite-plugin": "^2.1.0",
|
||||
"postcss": "^8.4.47",
|
||||
"tailwindcss": "^4.1.18",
|
||||
"vite": "^7.3.1"
|
||||
}
|
||||
}
|
||||
33
phpunit.xml
Normal file
33
phpunit.xml
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
|
||||
bootstrap="vendor/autoload.php"
|
||||
colors="true"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="Unit">
|
||||
<directory>tests/Unit</directory>
|
||||
</testsuite>
|
||||
<testsuite name="Feature">
|
||||
<directory>tests/Feature</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<source>
|
||||
<include>
|
||||
<directory>app</directory>
|
||||
</include>
|
||||
</source>
|
||||
<php>
|
||||
<env name="APP_ENV" value="testing"/>
|
||||
<env name="APP_MAINTENANCE_DRIVER" value="file"/>
|
||||
<env name="BCRYPT_ROUNDS" value="4"/>
|
||||
<env name="CACHE_STORE" value="array"/>
|
||||
<env name="DB_CONNECTION" value="sqlite"/>
|
||||
<env name="DB_DATABASE" value=":memory:"/>
|
||||
<env name="MAIL_MAILER" value="array"/>
|
||||
<env name="PULSE_ENABLED" value="false"/>
|
||||
<env name="QUEUE_CONNECTION" value="sync"/>
|
||||
<env name="SESSION_DRIVER" value="array"/>
|
||||
<env name="TELESCOPE_ENABLED" value="false"/>
|
||||
</php>
|
||||
</phpunit>
|
||||
6
postcss.config.js
Normal file
6
postcss.config.js
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
||||
21
public/.htaccess
Normal file
21
public/.htaccess
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<IfModule mod_rewrite.c>
|
||||
<IfModule mod_negotiation.c>
|
||||
Options -MultiViews -Indexes
|
||||
</IfModule>
|
||||
|
||||
RewriteEngine On
|
||||
|
||||
# Handle Authorization Header
|
||||
RewriteCond %{HTTP:Authorization} .
|
||||
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
|
||||
|
||||
# Redirect Trailing Slashes If Not A Folder...
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteCond %{REQUEST_URI} (.+)/$
|
||||
RewriteRule ^ %1 [L,R=301]
|
||||
|
||||
# Send Requests To Front Controller...
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^ index.php [L]
|
||||
</IfModule>
|
||||
17
public/index.php
Normal file
17
public/index.php
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
define('LARAVEL_START', microtime(true));
|
||||
|
||||
// Determine if the application is in maintenance mode...
|
||||
if (file_exists($maintenance = __DIR__.'/../storage/framework/maintenance.php')) {
|
||||
require $maintenance;
|
||||
}
|
||||
|
||||
// Register the Composer autoloader...
|
||||
require __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
// Bootstrap Laravel and handle the request...
|
||||
(require_once __DIR__.'/../bootstrap/app.php')
|
||||
->handleRequest(Request::capture());
|
||||
2
public/robots.txt
Normal file
2
public/robots.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
User-agent: *
|
||||
Disallow:
|
||||
3
resources/css/app.css
Normal file
3
resources/css/app.css
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
1
resources/js/app.js
Normal file
1
resources/js/app.js
Normal file
|
|
@ -0,0 +1 @@
|
|||
import './bootstrap';
|
||||
3
resources/js/bootstrap.js
vendored
Normal file
3
resources/js/bootstrap.js
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
import axios from 'axios';
|
||||
window.axios = axios;
|
||||
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
||||
65
resources/views/welcome.blade.php
Normal file
65
resources/views/welcome.blade.php
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Core PHP Framework</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
|
||||
min-height: 100vh;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
}
|
||||
.container {
|
||||
text-align: center;
|
||||
padding: 2rem;
|
||||
}
|
||||
h1 {
|
||||
font-size: 3rem;
|
||||
margin-bottom: 0.5rem;
|
||||
background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
.version {
|
||||
color: #888;
|
||||
font-size: 0.9rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
.links {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
a {
|
||||
color: #667eea;
|
||||
text-decoration: none;
|
||||
padding: 0.75rem 1.5rem;
|
||||
border: 1px solid #667eea;
|
||||
border-radius: 0.5rem;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
a:hover {
|
||||
background: #667eea;
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Core PHP Framework</h1>
|
||||
<p class="version">Laravel {{ Illuminate\Foundation\Application::VERSION }} | PHP {{ PHP_VERSION }}</p>
|
||||
<div class="links">
|
||||
<a href="https://github.com/host-uk/core-php">Documentation</a>
|
||||
<a href="/admin">Admin Panel</a>
|
||||
<a href="/api/docs">API Docs</a>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
5
routes/api.php
Normal file
5
routes/api.php
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
// API routes are registered via Core modules
|
||||
3
routes/console.php
Normal file
3
routes/console.php
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<?php
|
||||
|
||||
// Console commands are registered via Core modules
|
||||
7
routes/web.php
Normal file
7
routes/web.php
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::get('/', function () {
|
||||
return view('welcome');
|
||||
});
|
||||
3
storage/app/.gitignore
vendored
Normal file
3
storage/app/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
*
|
||||
!public/
|
||||
!.gitignore
|
||||
2
storage/app/public/.gitignore
vendored
Normal file
2
storage/app/public/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
*
|
||||
!.gitignore
|
||||
9
storage/framework/.gitignore
vendored
Normal file
9
storage/framework/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
compiled.php
|
||||
config.php
|
||||
down
|
||||
events.scanned.php
|
||||
maintenance.php
|
||||
routes.php
|
||||
routes.scanned.php
|
||||
schedule-*
|
||||
services.json
|
||||
3
storage/framework/cache/.gitignore
vendored
Normal file
3
storage/framework/cache/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
*
|
||||
!data/
|
||||
!.gitignore
|
||||
2
storage/framework/cache/data/.gitignore
vendored
Normal file
2
storage/framework/cache/data/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
*
|
||||
!.gitignore
|
||||
2
storage/framework/sessions/.gitignore
vendored
Normal file
2
storage/framework/sessions/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
*
|
||||
!.gitignore
|
||||
2
storage/framework/testing/.gitignore
vendored
Normal file
2
storage/framework/testing/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
*
|
||||
!.gitignore
|
||||
2
storage/framework/views/.gitignore
vendored
Normal file
2
storage/framework/views/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
*
|
||||
!.gitignore
|
||||
2
storage/logs/.gitignore
vendored
Normal file
2
storage/logs/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
*
|
||||
!.gitignore
|
||||
11
tailwind.config.js
Normal file
11
tailwind.config.js
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
content: [
|
||||
"./resources/**/*.blade.php",
|
||||
"./resources/**/*.js",
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
};
|
||||
0
tests/Feature/.gitkeep
Normal file
0
tests/Feature/.gitkeep
Normal file
10
tests/TestCase.php
Normal file
10
tests/TestCase.php
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
|
||||
|
||||
abstract class TestCase extends BaseTestCase
|
||||
{
|
||||
//
|
||||
}
|
||||
0
tests/Unit/.gitkeep
Normal file
0
tests/Unit/.gitkeep
Normal file
11
vite.config.js
Normal file
11
vite.config.js
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
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,
|
||||
}),
|
||||
],
|
||||
});
|
||||
Loading…
Add table
Reference in a new issue