Initial commit

This commit is contained in:
Snider 2026-01-26 18:40:00 +00:00 committed by GitHub
commit c19612d751
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
45 changed files with 772 additions and 0 deletions

76
.env.example Normal file
View 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=

11
.gitattributes vendored Normal file
View 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

23
.gitignore vendored Normal file
View file

@ -0,0 +1,23 @@
/.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

108
LICENSE Normal file
View 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: [your contact info]
For the full EUPL-1.2 text, see:
https://github.com/host-uk/core-php/blob/main/LICENSE

132
README.md Normal file
View file

@ -0,0 +1,132 @@
# Core PHP Framework Project
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)

View file

0
app/Mod/.gitkeep Normal file
View file

0
app/Models/.gitkeep Normal file
View file

View 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
View 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);

23
bootstrap/app.php Normal file
View file

@ -0,0 +1,23 @@
<?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 Packages
\Core\CoreServiceProvider::class,
])
->withRouting(
web: __DIR__.'/../routes/web.php',
api: __DIR__.'/../routes/api.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
//
})
->withExceptions(function (Exceptions $exceptions) {
//
})->create();

2
bootstrap/cache/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
*
!.gitignore

5
bootstrap/providers.php Normal file
View file

@ -0,0 +1,5 @@
<?php
return [
App\Providers\AppServiceProvider::class,
];

72
composer.json Normal file
View file

@ -0,0 +1,72 @@
{
"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": "^1.0",
"host-uk/core-admin": "^1.0",
"host-uk/core-api": "^1.0",
"host-uk/core-mcp": "^1.0"
},
"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",
"phpunit/phpunit": "^11.5"
},
"autoload": {
"psr-4": {
"App\\": "app/",
"Database\\Factories\\": "database/factories/",
"Database\\Seeders\\": "database/seeders/"
}
},
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/"
}
},
"repositories": [],
"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
View 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'),
],
];

View file

View file

View 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
View 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": "^1.2.0",
"postcss": "^8.4.47",
"tailwindcss": "^3.4.13",
"vite": "^6.0.0"
}
}

33
phpunit.xml Normal file
View 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
View file

@ -0,0 +1,6 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};

21
public/.htaccess Normal file
View 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
View 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
View file

@ -0,0 +1,2 @@
User-agent: *
Disallow:

3
resources/css/app.css Normal file
View file

@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

1
resources/js/app.js Normal file
View file

@ -0,0 +1 @@
import './bootstrap';

3
resources/js/bootstrap.js vendored Normal file
View file

@ -0,0 +1,3 @@
import axios from 'axios';
window.axios = axios;
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

View 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
View file

@ -0,0 +1,5 @@
<?php
use Illuminate\Support\Facades\Route;
// API routes are registered via Core modules

3
routes/console.php Normal file
View file

@ -0,0 +1,3 @@
<?php
// Console commands are registered via Core modules

7
routes/web.php Normal file
View file

@ -0,0 +1,7 @@
<?php
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return view('welcome');
});

3
storage/app/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
*
!public/
!.gitignore

2
storage/app/public/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
*
!.gitignore

9
storage/framework/.gitignore vendored Normal file
View 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
View file

@ -0,0 +1,3 @@
*
!data/
!.gitignore

View file

@ -0,0 +1,2 @@
*
!.gitignore

2
storage/framework/sessions/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
*
!.gitignore

2
storage/framework/testing/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
*
!.gitignore

2
storage/framework/views/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
*
!.gitignore

2
storage/logs/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
*
!.gitignore

11
tailwind.config.js Normal file
View 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
View file

10
tests/TestCase.php Normal file
View 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
View file

11
vite.config.js Normal file
View 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,
}),
],
});