11 Commits
Author SHA1 Message Date
paperbenni d1981673a2 remove redundant justfile recipe 2026-10-30 09:53:07 +01:00
paperbenni 84f5f0c788 rename readme 2026-10-30 09:45:34 +01:00
paperbenni d2bd589c96 init AI slop readmes 2026-10-30 09:43:48 +01:00
paperbenni 97e2c9e192 init justfile 2026-10-30 09:43:43 +01:00
paperbenni 23f9154eb6 remove unused dep 2026-10-30 09:43:27 +01:00
paperbenni 9ddcc0adb5 compat shim with modern composer 2026-10-30 09:41:48 +01:00
paperbenni a2ed9a9838 add dev user sheed 2026-10-30 09:40:42 +01:00
paperbenni 937004a48c fix migration incompatibility 2026-10-30 09:40:22 +01:00
paperbenni bd6e311a73 correct stale test 2026-10-30 09:39:28 +01:00
paperbenni a628dc1424 init docker stuff 2026-10-30 09:39:05 +01:00
paperbenni 7fa56f7584 init mise toml 2026-10-30 09:37:04 +01:00
14 changed files with 392 additions and 88 deletions
+2
View File
@@ -0,0 +1,2 @@
*
!Dockerfile
+39
View File
@@ -0,0 +1,39 @@
APP_NAME=Pollux
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost:8000
LOG_CHANNEL=stack
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=pollux
DB_USERNAME=pollux
DB_PASSWORD=secret
BROADCAST_DRIVER=log
CACHE_DRIVER=file
SESSION_DRIVER=file
SESSION_LIFETIME=120
QUEUE_DRIVER=sync
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
+12
View File
@@ -0,0 +1,12 @@
FROM composer:2.8 AS composer
FROM php:7.4-cli
RUN apt-get update \
&& apt-get install -y --no-install-recommends libonig-dev libzip-dev \
&& docker-php-ext-install -j"$(nproc)" mbstring pdo_mysql zip \
&& rm -rf /var/lib/apt/lists/*
COPY --from=composer /usr/bin/composer /usr/bin/composer
WORKDIR /var/www
+96
View File
@@ -0,0 +1,96 @@
# Pollux
Pollux is a small Laravel 5.6 bookkeeping application for managing bookings,
projects, people, targets, and reports.
## Local development
The application targets PHP 7.4 and MySQL 5.7. Those old runtimes are run in
Docker so they do not have to be installed on the host. [mise](https://mise.jdx.dev/)
manages the host-side tools: Just and Node 10 (required by the old Laravel Mix 2
asset pipeline).
### Prerequisites
- Docker with Compose v2 (`docker compose`)
- [mise](https://mise.jdx.dev/)
### First run
```sh
mise install
just setup
just up
```
Then open <http://localhost:8000>. A development login is created automatically:
- **Email:** `dev@pollux.local`
- **Password:** `password`
`just setup` builds the PHP image, installs Composer dependencies, creates `.env`
from `.env.docker.example`, generates `APP_KEY`, starts MySQL, runs migrations,
and loads the constant and demo data.
### Everyday commands
| Command | Description |
| --- | --- |
| `just up` | Start the app and database in the foreground |
| `just up -d` | Start the app and database in the background |
| `just down` | Stop the app and database |
| `just logs` | Follow container logs |
| `just artisan <command>` | Run an Artisan command |
| `just composer <command>` | Run a Composer command |
| `just shell` | Open a shell in the app container |
| `just db` | Open a MySQL shell |
| `just migrate` | Run migrations |
| `just seed` | Add the demo/test dataset to an existing database |
| `just seed-real` | Recreate the database and load the full dataset from `database/seeds/data/real` |
| `just fresh` | Drop and recreate the database, then load demo data |
| `just test` | Run PHPUnit |
| `just assets` | Install npm packages and build frontend assets |
| `just watch` | Rebuild frontend assets on change |
Run `just --list` to see the full list.
### Database
MySQL is exposed on host port **3307** so it does not clash with a local MySQL
on 3306. The database is `pollux` with username `pollux` and password `secret`.
The app container connects to the `db` service on port 3306.
Data lives in the Docker volume `pollux_mysql-data`. `just down` keeps the data;
use `docker compose down -v` if you want to remove it as well.
### Frontend assets
Node 10 is pinned in `mise.toml` because Laravel Mix 2 and `node-sass` do not run
on current Node versions. Prebuilt assets are committed, so `just assets` is not
needed just to run the application.
### Tests
```sh
just test
```
## Legacy compatibility notes
This project uses several old dependencies, so a few small compatibility fixes
are included:
- `phpdocumentor/phpdocumentor` 2.* was removed from `require-dev`. It requires
Symfony 2.x, conflicts with Laravel 5.6, and was never present in
`composer.lock`.
- `scripts/patch-package-manifest.php` runs after Composer's autoload dump. It
adds Composer 2 support to Laravel 5.6's package discovery, which otherwise
fails with `Undefined index: name`.
- `fzaninotto/faker` was updated to 1.9.2 for PHP 7.4 compatibility.
- `bookings.note` is created as `TEXT` because the full dataset in
`database/seeds/data/real` contains notes longer than the default
191-character string length.
## License
Pollux is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).
+45
View File
@@ -0,0 +1,45 @@
name: pollux
services:
app:
build: .
working_dir: /var/www
user: "${UID:-1000}:${GID:-1000}"
environment:
HOME: /tmp
COMPOSER_HOME: /tmp/composer
APP_URL: http://localhost:8000
DB_CONNECTION: mysql
DB_HOST: db
DB_PORT: "3306"
DB_DATABASE: pollux
DB_USERNAME: pollux
DB_PASSWORD: secret
volumes:
- .:/var/www
ports:
- "8000:8000"
depends_on:
db:
condition: service_healthy
command: php artisan serve --host=0.0.0.0 --port=8000
db:
image: mysql:5.7
environment:
MYSQL_DATABASE: pollux
MYSQL_USER: pollux
MYSQL_PASSWORD: secret
MYSQL_ROOT_PASSWORD: root
volumes:
- mysql-data:/var/lib/mysql
ports:
- "3307:3306"
healthcheck:
test: ["CMD-SHELL", "mysqladmin ping -h 127.0.0.1 -uroot -proot --silent"]
interval: 5s
timeout: 5s
retries: 20
volumes:
mysql-data:
+2 -2
View File
@@ -22,8 +22,7 @@
"fzaninotto/faker": "^1.4", "fzaninotto/faker": "^1.4",
"mockery/mockery": "^1.0", "mockery/mockery": "^1.0",
"nunomaduro/collision": "^2.0", "nunomaduro/collision": "^2.0",
"phpunit/phpunit": "^7.0", "phpunit/phpunit": "^7.0"
"phpdocumentor/phpdocumentor": "2.*"
}, },
"autoload": { "autoload": {
"files": [ "files": [
@@ -57,6 +56,7 @@
], ],
"post-autoload-dump": [ "post-autoload-dump": [
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
"@php scripts/patch-package-manifest.php",
"@php artisan package:discover" "@php artisan package:discover"
] ]
}, },
Generated
+24 -18
View File
@@ -1,7 +1,7 @@
{ {
"_readme": [ "_readme": [
"This file locks the dependencies of your project to a known state", "This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "68e5550c8775420cfdaef12858446b78", "content-hash": "68e5550c8775420cfdaef12858446b78",
@@ -1118,12 +1118,12 @@
"version": "1.25.0", "version": "1.25.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/briannesbitt/Carbon.git", "url": "https://github.com/CarbonPHP/carbon.git",
"reference": "cbcf13da0b531767e39eb86e9687f5deba9857b4" "reference": "cbcf13da0b531767e39eb86e9687f5deba9857b4"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/cbcf13da0b531767e39eb86e9687f5deba9857b4", "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/cbcf13da0b531767e39eb86e9687f5deba9857b4",
"reference": "cbcf13da0b531767e39eb86e9687f5deba9857b4", "reference": "cbcf13da0b531767e39eb86e9687f5deba9857b4",
"shasum": "" "shasum": ""
}, },
@@ -2604,12 +2604,12 @@
"version": "v2.5.1", "version": "v2.5.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/vlucas/phpdotenv.git", "url": "https://github.com/phpdotenv/phpdotenv.git",
"reference": "8abb4f9aa89ddea9d52112c65bbe8d0125e2fa8e" "reference": "8abb4f9aa89ddea9d52112c65bbe8d0125e2fa8e"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/8abb4f9aa89ddea9d52112c65bbe8d0125e2fa8e", "url": "https://api.github.com/repos/phpdotenv/phpdotenv/zipball/8abb4f9aa89ddea9d52112c65bbe8d0125e2fa8e",
"reference": "8abb4f9aa89ddea9d52112c65bbe8d0125e2fa8e", "reference": "8abb4f9aa89ddea9d52112c65bbe8d0125e2fa8e",
"shasum": "" "shasum": ""
}, },
@@ -2656,12 +2656,12 @@
"version": "v3.2.0", "version": "v3.2.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/barryvdh/laravel-debugbar.git", "url": "https://github.com/fruitcake/laravel-debugbar.git",
"reference": "5b68f3972083a7eeec0d6f161962fcda71a127c0" "reference": "5b68f3972083a7eeec0d6f161962fcda71a127c0"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/5b68f3972083a7eeec0d6f161962fcda71a127c0", "url": "https://api.github.com/repos/fruitcake/laravel-debugbar/zipball/5b68f3972083a7eeec0d6f161962fcda71a127c0",
"reference": "5b68f3972083a7eeec0d6f161962fcda71a127c0", "reference": "5b68f3972083a7eeec0d6f161962fcda71a127c0",
"shasum": "" "shasum": ""
}, },
@@ -2836,16 +2836,16 @@
}, },
{ {
"name": "fzaninotto/faker", "name": "fzaninotto/faker",
"version": "v1.8.0", "version": "v1.9.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/fzaninotto/Faker.git", "url": "https://github.com/fzaninotto/Faker.git",
"reference": "f72816b43e74063c8b10357394b6bba8cb1c10de" "reference": "848d8125239d7dbf8ab25cb7f054f1a630e68c2e"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/fzaninotto/Faker/zipball/f72816b43e74063c8b10357394b6bba8cb1c10de", "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/848d8125239d7dbf8ab25cb7f054f1a630e68c2e",
"reference": "f72816b43e74063c8b10357394b6bba8cb1c10de", "reference": "848d8125239d7dbf8ab25cb7f054f1a630e68c2e",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2854,12 +2854,12 @@
"require-dev": { "require-dev": {
"ext-intl": "*", "ext-intl": "*",
"phpunit/phpunit": "^4.8.35 || ^5.7", "phpunit/phpunit": "^4.8.35 || ^5.7",
"squizlabs/php_codesniffer": "^1.5" "squizlabs/php_codesniffer": "^2.9.2"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.8-dev" "dev-master": "1.9-dev"
} }
}, },
"autoload": { "autoload": {
@@ -2882,7 +2882,12 @@
"faker", "faker",
"fixtures" "fixtures"
], ],
"time": "2018-07-12T10:23:15+00:00" "support": {
"issues": "https://github.com/fzaninotto/Faker/issues",
"source": "https://github.com/fzaninotto/Faker/tree/v1.9.2"
},
"abandoned": true,
"time": "2020-12-11T09:56:16+00:00"
}, },
{ {
"name": "hamcrest/hamcrest-php", "name": "hamcrest/hamcrest-php",
@@ -4431,12 +4436,12 @@
"version": "1.3.0", "version": "1.3.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/webmozart/assert.git", "url": "https://github.com/webmozarts/assert.git",
"reference": "0df1908962e7a3071564e857d86874dad1ef204a" "reference": "0df1908962e7a3071564e857d86874dad1ef204a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a", "url": "https://api.github.com/repos/webmozarts/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a",
"reference": "0df1908962e7a3071564e857d86874dad1ef204a", "reference": "0df1908962e7a3071564e857d86874dad1ef204a",
"shasum": "" "shasum": ""
}, },
@@ -4479,11 +4484,12 @@
], ],
"aliases": [], "aliases": [],
"minimum-stability": "dev", "minimum-stability": "dev",
"stability-flags": [], "stability-flags": {},
"prefer-stable": true, "prefer-stable": true,
"prefer-lowest": false, "prefer-lowest": false,
"platform": { "platform": {
"php": "^7.1.3" "php": "^7.1.3"
}, },
"platform-dev": [] "platform-dev": {},
"plugin-api-version": "2.6.0"
} }
@@ -25,8 +25,9 @@ class CreateBookingsTable extends Migration
// The name of the person or company which the booking belongs to // The name of the person or company which the booking belongs to
$table->string('person_or_company'); $table->string('person_or_company');
// An additional note to the booking // An additional note to the booking. The real dataset contains
$table->string('note')->nullable(); // notes longer than the 191-character default string length.
$table->text('note')->nullable();
$table->timestamps(); $table->timestamps();
}); });
+25
View File
@@ -0,0 +1,25 @@
<?php
use Illuminate\Database\Seeder;
class DevUserSeeder extends Seeder
{
/**
* Create a local development login.
*
* Email: dev@pollux.local
* Password: password
*
* @return void
*/
public function run()
{
App\User::updateOrCreate(
['email' => 'dev@pollux.local'],
[
'name' => 'Dev User',
'password' => bcrypt('password'),
]
);
}
}
+103
View File
@@ -0,0 +1,103 @@
set shell := ["bash", "-uc"]
# Keep files created by containers owned by the host user.
export UID := `id -u`
export GID := `id -g`
default:
@just --list
# First-time setup: build, install PHP deps, create .env, migrate and seed.
setup:
#!/usr/bin/env bash
set -euo pipefail
if [ ! -f .env ]; then
cp .env.docker.example .env
fi
docker compose build
docker compose run --rm --no-deps app composer install
if ! grep -q '^APP_KEY=base64:' .env; then
docker compose run --rm --no-deps app php artisan key:generate --force
fi
docker compose up -d --wait db
docker compose run --rm app php artisan migrate --force
# Only seed the demo data on a fresh database.
if [ "$(docker compose exec -T db mysql -N -B -upollux -psecret pollux -e 'SELECT COUNT(*) FROM scopes' 2>/dev/null || echo 0)" = "0" ]; then
docker compose run --rm app php artisan db:seed --class=ConstantsSeeder --force
docker compose run --rm app php artisan db:seed --class=TestDataSeeder --force
else
echo "Database already seeded; skipping demo data."
fi
docker compose run --rm app php artisan db:seed --class=DevUserSeeder --force
echo "Setup complete. Run 'just up', then open http://localhost:8000"
echo "Login: dev@pollux.local / password"
# Start the app and database in the foreground. Use `just up -d` for background.
up *args:
docker compose up --build {{args}}
# Stop the app and database.
down:
docker compose down
# Tail logs. Optionally pass a service name: just logs app
logs *args:
docker compose logs -f {{args}}
# Run an artisan command: just artisan route:list
artisan *args:
docker compose run --rm app php artisan {{args}}
# Run a composer command: just composer require foo/bar
composer *args:
docker compose run --rm app composer {{args}}
# Open a shell in the app container.
shell:
docker compose run --rm app bash
# Open a MySQL shell.
db:
docker compose up -d --wait db
docker compose exec db mysql -upollux -psecret pollux
# Run migrations.
migrate:
docker compose run --rm app php artisan migrate
# Add the demo/test dataset to an existing database.
seed:
docker compose run --rm app php artisan db:seed --class=TestDataSeeder
# Recreate the database and load the full dataset from database/seeds/data/real.
seed-real:
docker compose run --rm app php artisan migrate:fresh
docker compose run --rm app php artisan db:seed --force
docker compose run --rm app php artisan db:seed --class=DevUserSeeder --force
# Recreate the database and load test data.
fresh:
docker compose run --rm app php artisan migrate:fresh
docker compose run --rm app php artisan db:seed --class=ConstantsSeeder
docker compose run --rm app php artisan db:seed --class=TestDataSeeder
docker compose run --rm app php artisan db:seed --class=DevUserSeeder
# Run the test suite.
test *args:
docker compose run --rm --no-deps app vendor/bin/phpunit {{args}}
# Build frontend assets (uses the mise-pinned Node 10).
assets:
mise exec -- npm install
mise exec -- npm run dev
# Watch frontend assets.
watch:
mise exec -- npm run watch
+7
View File
@@ -0,0 +1,7 @@
[tools]
# Old Laravel Mix 2 / node-sass toolchain; use Node 10 for asset builds.
node = "10.24.1"
just = "1.59.0"
[env]
COMPOSE_PROJECT_NAME = "pollux"
-65
View File
@@ -1,65 +0,0 @@
<p align="center"><img src="https://laravel.com/assets/img/components/logo-laravel.svg"></p>
<p align="center">
<a href="https://travis-ci.org/laravel/framework"><img src="https://travis-ci.org/laravel/framework.svg" alt="Build Status"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://poser.pugx.org/laravel/framework/d/total.svg" alt="Total Downloads"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://poser.pugx.org/laravel/framework/v/stable.svg" alt="Latest Stable Version"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://poser.pugx.org/laravel/framework/license.svg" alt="License"></a>
</p>
## About Laravel
Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel attempts to take the pain out of development by easing common tasks used in the majority of web projects, such as:
- [Simple, fast routing engine](https://laravel.com/docs/routing).
- [Powerful dependency injection container](https://laravel.com/docs/container).
- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.
- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).
- Database agnostic [schema migrations](https://laravel.com/docs/migrations).
- [Robust background job processing](https://laravel.com/docs/queues).
- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).
Laravel is accessible, yet powerful, providing tools needed for large, robust applications.
## Learning Laravel
Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of any modern web application framework, making it a breeze to get started learning the framework.
If you're not in the mood to read, [Laracasts](https://laracasts.com) contains over 1100 video tutorials on a range of topics including Laravel, modern PHP, unit testing, JavaScript, and more. Boost the skill level of yourself and your entire team by digging into our comprehensive video library.
## Laravel Sponsors
We would like to extend our thanks to the following sponsors for helping fund on-going Laravel development. If you are interested in becoming a sponsor, please visit the Laravel [Patreon page](https://patreon.com/taylorotwell):
- **[Vehikl](https://vehikl.com/)**
- **[Tighten Co.](https://tighten.co)**
- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)**
- **[Cubet Techno Labs](https://cubettech.com)**
- **[British Software Development](https://www.britishsoftware.co)**
- **[Webdock, Fast VPS Hosting](https://www.webdock.io/en)**
- [UserInsights](https://userinsights.com)
- [Fragrantica](https://www.fragrantica.com)
- [SOFTonSOFA](https://softonsofa.com/)
- [User10](https://user10.com)
- [Soumettre.fr](https://soumettre.fr/)
- [CodeBrisk](https://codebrisk.com)
- [1Forge](https://1forge.com)
- [TECPRESSO](https://tecpresso.co.jp/)
- [Runtime Converter](http://runtimeconverter.com/)
- [WebL'Agence](https://weblagence.com/)
- [Invoice Ninja](https://www.invoiceninja.com)
- [iMi digital](https://www.imi-digital.de/)
- [Earthlink](https://www.earthlink.ro/)
- [Steadfast Collective](https://steadfastcollective.com/)
## Contributing
Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).
## Security Vulnerabilities
If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed.
## License
The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).
+33
View File
@@ -0,0 +1,33 @@
<?php
/*
* Laravel 5.6's PackageManifest predates Composer 2. Composer 2 stores the
* installed package list under a "packages" key, which makes Laravel's
* package:discover command fail with "Undefined index: name".
*
* This script adds support for both formats to the vendored framework file.
* Composer runs it before package:discover, so it is safe to run repeatedly.
*/
$file = __DIR__.'/../vendor/laravel/framework/src/Illuminate/Foundation/PackageManifest.php';
if (! file_exists($file)) {
fwrite(STDERR, "PackageManifest.php not found; skipping Composer 2 patch.\n");
exit(0);
}
$contents = file_get_contents($file);
if (strpos($contents, "\$packages = \$packages['packages'] ?? \$packages;") !== false) {
exit(0);
}
$needle = '$packages = json_decode($this->files->get($path), true);';
$replacement = $needle."\n\n \$packages = \$packages['packages'] ?? \$packages;";
if (strpos($contents, $needle) === false) {
fwrite(STDERR, "Could not find PackageManifest build() snippet; skipping patch.\n");
exit(0);
}
file_put_contents($file, str_replace($needle, $replacement, $contents));
+1 -1
View File
@@ -16,6 +16,6 @@ class ExampleTest extends TestCase
{ {
$response = $this->get('/'); $response = $this->get('/');
$response->assertStatus(200); $response->assertRedirect('/bookings');
} }
} }