For Developers
Local setup
cp .env.example .env
composer setup # installs deps, generates app key, runs migrations, builds assets
php artisan user:create admin@example.com "Admin User" password123
php artisan serve
Docker setup
cp .env.example .env
# Edit .env: set APP_KEY, APP_ENV=production, APP_DEBUG=false
docker compose up -d --build
docker compose exec app php artisan migrate --force
docker compose exec app php artisan user:create admin@example.com "Admin User" password123
CLI commands
User management
php artisan user:create {email} {name} {password} # Create a user
php artisan user:toggle {email} # Enable or disable a user
php artisan user:purge {email} --force # Delete all data for a user (irreversible)
php artisan user:password {email} # Reset password; outputs new password
Disabled users cannot log in, but their tasks remain. An account can be re-enabled. API keys for disabled users are rejected by the API middleware.
API keys
php artisan apikey:create {email} # Generate a key — printed once, note it immediately
php artisan apikey:invalidate {key} # Permanently invalidate a key (cannot be re-enabled)
Keys are stored hashed; there is no way to retrieve a key after creation.
Maintenance
php artisan tasks:move-overdue # Reschedule all overdue incomplete tasks to today
Database management
| Path | Used by | |
|---|---|---|
| Production | database/database.sqlite |
.env |
| Test | database/test-database.sqlite |
.env.testing |
Always specify the environment when running artisan commands against a specific database:
# Production
php artisan migrate:fresh --force
# Test database
php artisan migrate:fresh --force --env=testing
php artisan user:create test@example.com "Test" password123 --env=testing
The testing connection is defined in config/database.php and always points to the test database file regardless of .env.
Architecture notes
No deletion — Tasks and projects are never deleted, only archived. Use status = archived to hide things.
Status values — incomplete, done, archived. These are the only valid values; enforced at the migration level.
Authorization — Tasks and projects are private by default. Visibility is limited to the creator and explicitly assigned users. Look for the ->where('creator_id') / ->orWhereHas('assignments') pattern in TaskController and ProjectController.
Change logging — All creates and updates write a record to change_logs. The Activity view (/changelogs) surfaces this per-task, per-project, per-tag, or per-user.
File storage — Attachments use the private disk. Downloads are proxied through TaskAttachmentController::download() to enforce authorization.
Auth split — Session-based auth for web routes, hashed-token auth for API routes. The auth.api middleware (app/Http/Middleware/AuthenticateApiKey.php) validates bearer tokens against bcrypt hashes in api_keys and checks the user's enabled status.
Adding pages to Other Links
Drop any Markdown file into storage/app/other-links/. It will:
- Appear as a link in the Other Links nav dropdown (desktop) and collapsible section (mobile)
- Be accessible at
/other-links/{filename}(filename including extension) - Use the filename (minus extension, with
-and_replaced by spaces) as the page title
The nav is populated by app/View/Composers/NavigationComposer.php, which shares $otherLinksFiles to all views using the navigation layout. Symlinks are supported.
Contributing to documentation
The docs live in docs/ and are built with MkDocs Material.
To preview changes locally:
pip install mkdocs-material
cd docs
mkdocs serve
Then open http://localhost:8000. The nav is defined in docs/mkdocs.yml — update it when adding new pages.
If you document something that others running Task Fiend would find useful, please consider contributing it back.