
docfunc is a personal blog built on Laravel 13, Livewire 4, and Tailwind CSS 4, used as a Laravel learning playground and powered by CKEditor 5 for authoring, Algolia for full-text search, and AWS S3 for image uploads.
- Posts — CKEditor 5 authoring with Shiki syntax highlighting, S3 image uploads, soft deletes with mass-prune, RSS feed via
spatie/laravel-feed, and Algolia full-text search. - Comments — Hierarchical threads with queued email and database notifications.
- Authentication — Login, registration, email verification, and account deletion via signed mail.
- WebAuthn passkeys — Register, manage, and sign in with passkeys.
- Tags & Categories — Tag input via Tagify with many-to-many tags and per-post categories.
- oEmbed — Twitter and YouTube oEmbed proxy endpoints.
- Bot protection — Cloudflare Turnstile on public forms.
- Settings — Cached application settings via a
Settingmodel and service.
- PHP
^8.4 - Laravel 13
- Laravel Octane 2
- Laravel Sanctum 4
- Laravel Scout 10
- Livewire 4 with
livewire/blaze - Tailwind CSS 4 (via
@tailwindcss/vite) and@tailwindcss/typography - Vite 8
- TypeScript 5
- CKEditor 5
- Shiki
- Tagify (
@yaireo/tagify) @simplewebauthn/browser
- Algolia
- AWS S3
- Cloudflare Turnstile
- Bref (AWS Lambda)
- PHP
^8.4 - Composer
- Node.js and npm
Note
SQLite is the default database. Any Laravel-supported database (MySQL, PostgreSQL, etc.) works with a few env tweaks.
Clone the repository:
git clone https://github.com/YilanBoy/docfunc.git
cd docfuncInstall PHP dependencies:
composer installCopy the example env file:
cp .env.example .envGenerate the application key:
php artisan key:generateCreate the SQLite database file (skip if you're not using the default SQLite driver):
touch database/database.sqliteRun migrations:
php artisan migrateInstall JavaScript dependencies:
npm installStart the Vite dev server (or npm run build for a production bundle):
npm run devStart the Laravel dev server:
php artisan serveNote
composer create-project would auto-run env copy, key generation, and migrations via composer scripts. A plain git clone does not, which is why these steps are spelled out.
- Database — defaults to SQLite (
database/database.sqlite). Switch viaDB_CONNECTIONand the standardDB_*vars in.env. - Mail — defaults to
MAIL_MAILER=log. Set SMTP vars for real delivery. - Filesystem & S3 —
FILESYSTEM_DISK=localby default. CKEditor image uploads use S3; setAWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AWS_DEFAULT_REGION,AWS_BUCKET. - Algolia / Scout — set
ALGOLIA_APP_ID,ALGOLIA_SECRET.SCOUT_PREFIXnamespaces indexes per environment. - Cloudflare Turnstile — set
CAPTCHA_SITE_KEYandCAPTCHA_SECRET_KEY. Default values in.env.exampleare Cloudflare's "always pass" test keys. - Octane —
OCTANE_SERVERacceptsswoole,roadrunner, orfrankenphp. Default in.env.exampleisswoole.
php artisan serve— dev server.npm run dev— Vite dev server with HMR.php artisan octane:start— production-style server (usesOCTANE_SERVER).php artisan pail— tail application logs.php artisan ide-helper:generateandphp artisan ide-helper:models— generate IDE autocomplete metadata.
The project uses Pest 4 (with pest-plugin-browser powered by Playwright), Larastan/PHPStan at level 5, and Laravel Pint. The one-shot CI script runs all three:
composer ciOr run them individually:
php artisan test --parallel # or: vendor/bin/pest --parallel
vendor/bin/phpstan analyse --memory-limit=2G
vendor/bin/pint --parallelNote
Tests run against an in-memory SQLite database with Scout's collection driver (configured in phpunit.xml).
docfunc runs on Laravel Octane, which supports three application servers — Swoole, RoadRunner, and FrankenPHP. Pick one via OCTANE_SERVER and start it with:
php artisan octane:start --server=$OCTANE_SERVER --host=0.0.0.0 --port=8000Note
Install Swoole via PECL (pecl install swoole) or apt (sudo add-apt-repository ppa:ondrej/php then sudo apt-get install php8.4-swoole). For the other servers, see https://roadrunner.dev and https://frankenphp.dev.
Octane worker (/etc/supervisor/conf.d/docfunc-octane-worker.conf):
[program:docfunc-octane-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/docfunc/artisan octane:start --server=<swoole|roadrunner|frankenphp> --host=0.0.0.0 --port=8000
autostart=true
autorestart=true
user=www-data
redirect_stderr=true
stdout_logfile=/var/log/supervisor/docfunc-octane-worker.log
stopwaitsecs=3600
Queue worker (/etc/supervisor/conf.d/docfunc-queue-worker.conf):
[program:docfunc-queue-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/docfunc/artisan queue:work --sleep=3 --tries=3 --max-time=3600
autostart=true
autorestart=true
user=www-data
numprocs=1
redirect_stderr=true
stdout_logfile=/var/log/supervisor/docfunc-queue-worker.log
stopwaitsecs=3600
Edit the crontab:
crontab -eAdd the following entry to run the Laravel scheduler every minute:
* * * * * cd /var/www/docfunc && php artisan schedule:run >> /dev/null 2>&1
The project bundles bref/bref and bref/laravel-bridge for AWS Lambda. Production runs as Lambda function docfunc-production-web in us-west-2. See https://bref.sh for setup.
- Tests (
.github/workflows/tests.yaml) — runs on PRs and pushes tomain, matrix over PHP 8.4 and 8.5; runs PHPStan, Pint (--test), and Pest with coverage uploaded to Codecov; sends status to Telegram. - Maintenance toggle (
.github/workflows/maintenance-mode-toggle.yaml) — manual dispatch; togglesMAINTENANCE_MODEon thedocfunc-production-webLambda function.