cytonnToDoApp Svelte Themes

Cytonntodoapp

Simple ToDo App in Laravel + Svelte using Sanctum API

Laravel + Svelte ToDo App

Environment: WSL Ubuntu Backend: Laravel (php 8.4) Frontend: Svelte Database: MySQL

Setup 1 - sudo apt update

2 - Install php 8.4, includes composer /bin/bash -c "$(curl -fsSL https://php.new/install/linux/8.4)"

3 - Install Node, make sure to check nvm version on github curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash

source ~/.bashrc

nvm install v24.14.1

4 - Install and Start MySQL

sudo apt install mysql-server

sudo systemctl start mysql.service

5 - Create User and Grant Privilege

sudo mysql

CREATE USER 'john'@'localhost' IDENTIFIED BY 'password';

CREATE DATABASE IF NOT EXISTS cytonn_to_do_app;

GRANT ALL PRIVILEGES ON cytonn_to_do_app.* TO 'john'@'localhost';

FLUSH PRIVILEGES;

6 - Create Laravel Project

laravel new backend

starter kit - none; testing framework - pest; laravel boost - no; database driver - mysql; run migrations - no; npm install - yes;

DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=cytonn_to_do_app DB_USERNAME=john DB_PASSWORD=password

7 - Sanctum API

php artisan install:api

8 - Configure CORS

php artisan config:publish cors

'paths' => ['api/', 'sanctum/csrf-cookie'], [ 'allowed_methods' => [''], 'allowed_origins' => ['http://127.0.0.1:5173'], 'allowed_origins_patterns' => [], 'allowed_headers' => ['*'], 'exposed_headers' => [], 'max_age' => 0, 'supports_credentials' => true, ]

9 - Create Sveltekit Project, following shadcn init (https://shadcn-svelte.com/docs/installation/sveltekit)

npx sv create frontend --add tailwindcss

npx shadcn-svelte@latest init

10 - Migrations

php artisan make:migration create_todo_tables

php artisan migrate

11 - Models

php artisan make:model Task

php artisan make:model TaskLog

php artisan make:model TaskReport

12 - Controllers

php artisan make:controller TaskController

php artisan make:controller ReportController

13 - Routes

// Public routes Route::post('/register', [AuthController::class, 'register']); Route::post('/login', [AuthController::class, 'login']);

// Protected routes Route::middleware('auth:sanctum')->group(function () {

... });

14 - Seeders

php artisan db:seed

15 - Auth

class User extends Authenticatable { /** @use HasFactory */ use HasFactory, Notifiable, HasApiTokens; ... }

php artisan make:controller AuthController

$user = User::where('email', $request->input('email'))->first(); $token = $user->createToken('auth_token')->plainTextToken;

interface AuthState { token: string | null; isAuthenticated: boolean; user: UserData | null; isLoading: boolean; error: string | null; }

interface UserData { id: number; email: string; name: string; }

let csrfToken: string | null = null;

16 - MySQL Data

mysql> USE cytonn_to_do_app; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A

Database changed mysql> SELECT * FROM users;

| id | name | email | email_verified_at | password | remember_token | created_at | updated_at | +----+-----------------+---------------------------+---------------------+--------------------------------------------------------------+----------------+---------------------+---------------------+ | 1 | Daniel Njaramba | danielnjaramba8@gmail.com | 2026-03-31 18:45:15 | $2y$12$B0WvYLF9mfHtg1pTRcse8.F/e7JnolrgR6JcTW94e6wqq158IEFFm | C4SWfUaScX | 2026-03-31 18:45:16 | 2026-03-31 18:45:16 |

1 row in set (0.00 sec)

mysql> SELECT * FROM tasks; +----+---------+------------------+------------+----------+-------------+---------------------+---------------------+ | id | user_id | title | due_date | priority | status | created_at | updated_at | +----+---------+------------------+------------+----------+-------------+---------------------+---------------------+ | 1 | 1 | Task 1 - Mar 31 | 2026-03-31 | high | pending | 2026-03-31 00:00:00 | 2026-03-31 00:00:00 | | 2 | 1 | Task 2 - Mar 31 | 2026-03-31 | high | done | 2026-03-31 00:00:00 | 2026-03-31 00:00:00 | | 3 | 1 | Task 3 - Mar 31 | 2026-03-31 | medium | in_progress | 2026-03-31 00:00:00 | 2026-03-31 00:00:00 | | 4 | 1 | Task 4 - Mar 31 | 2026-03-31 | low | in_progress | 2026-03-31 00:00:00 | 2026-03-31 00:00:00 | | 5 | 1 | Task 5 - Mar 31 | 2026-03-31 | medium | pending | 2026-03-31 00:00:00 | 2026-03-31 00:00:00 | | 6 | 1 | Task 6 - Mar 31 | 2026-03-31 | high | pending | 2026-03-31 00:00:00 | 2026-03-31 00:00:00 | | 7 | 1 | Task 1 - Mar 30 | 2026-03-30 | low | pending | 2026-03-30 00:00:00 | 2026-03-30 00:00:00 | | 8 | 1 | Task 2 - Mar 30 | 2026-03-30 | low | pending | 2026-03-30 00:00:00 | 2026-03-30 00:00:00 | | 9 | 1 | Task 3 - Mar 30 | 2026-03-30 | medium | in_progress | 2026-03-30 00:00:00 | 2026-03-30 00:00:00 | | 10 | 1 | Task 4 - Mar 30 | 2026-03-30 | low | in_progress | 2026-03-30 00:00:00 | 2026-03-30 00:00:00 | | 11 | 1 | Task 5 - Mar 30 | 2026-03-30 | low | in_progress | 2026-03-30 00:00:00 | 2026-03-30 00:00:00 |

mysql> SELECT * FROM task_logs; +----+---------+-----------+------+---------------------+------------+ | id | task_id | action | data | created_at | updated_at | +----+---------+-----------+------+---------------------+------------+ | 1 | 1 | created | NULL | 2026-03-31 00:00:00 | NULL | | 2 | 2 | completed | NULL | 2026-03-31 00:00:00 | NULL | | 3 | 3 | created | NULL | 2026-03-31 00:00:00 | NULL | | 4 | 4 | created | NULL | 2026-03-31 00:00:00 | NULL | | 5 | 5 | created | NULL | 2026-03-31 00:00:00 | NULL | | 6 | 6 | created | NULL | 2026-03-31 00:00:00 | NULL | | 7 | 7 | created | NULL | 2026-03-30 00:00:00 | NULL | | 8 | 8 | created | NULL | 2026-03-30 00:00:00 | NULL | | 9 | 9 | created | NULL | 2026-03-30 00:00:00 | NULL | | 10 | 10 | created | NULL | 2026-03-30 00:00:00 | NULL | | 11 | 11 | created | NULL | 2026-03-30 00:00:00 | NULL | | 12 | 12 | created | NULL | 2026-03-30 00:00:00 | NULL | | 13 | 13 | completed | NULL | 2026-03-30 00:00:00 | NULL | | 14 | 14 | completed | NULL | 2026-03-30 00:00:00 | NULL | | 15 | 15 | completed | NULL | 2026-03-30 00:00:00 | NULL | | 16 | 16 | created | NULL | 2026-03-30 00:00:00 | NULL |

mysql> SELECT * FROM task_reports; +----+---------+-------------+-----------------+-----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+---------------------+ | id | user_id | report_date | tasks_completed | completion_rate | summary | created_at | updated_at | +----+---------+-------------+-----------------+-----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+---------------------+ | 1 | 1 | 2026-03-31 | 1 | 0.17 | {"low": {"done": 0, "pending": 0, "in_progress": 1}, "high": {"done": 1, "pending": 2, "in_progress": 0}, "medium": {"done": 0, "pending": 1, "in_progress": 1}} | 2026-03-31 18:45:16 | 2026-03-31 18:45:16 | | 2 | 1 | 2026-03-30 | 3 | 0.30 | {"low": {"done": 2, "pending": 2, "in_progress": 3}, "high": {"done": 1, "pending": 0, "in_progress": 0}, "medium": {"done": 0, "pending": 1, "in_progress": 1}} | 2026-03-31 18:45:16 | 2026-03-31 18:45:16 | | 3 | 1 | 2026-03-29 | 6 | 0.67 | {"low": {"done": 4, "pending": 0, "in_progress": 1}, "high": {"done": 2, "pending": 2, "in_progress": 0}, "medium": {"done": 0, "pending": 0, "in_progress": 0}} | 2026-03-31 18:45:16 | 2026-03-31 18:45:16 | | 4 | 1 | 2026-03-28 | 3 | 0.50 | {"low": {"done": 1, "pending": 2, "in_progress": 1}, "high": {"done": 2, "pending": 0, "in_progress": 0}, "medium": {"done": 0, "pending": 0, "in_progress": 0}} | 2026-03-31 18:45:16 | 2026-03-31 18:45:16 | | 5 | 1 | 2026-03-27 | 0 | 0.00 | {"low": {"done": 0, "pending": 4, "in_progress": 0}, "high": {"done": 0, "pending": 1, "in_progress": 0}, "medium": {"done": 0, "pending": 1, "in_progress": 1}} | 2026-03-31 18:45:16 | 2026-03-31 18:45:16 | | 6 | 1 | 2026-03-26 | 1 | 0.14 | {"low": {"done": 1, "pending": 1, "in_progress": 2}, "high": {"done": 0, "pending": 1, "in_progress": 0}, "medium": {"done": 0, "pending": 0, "in_progress": 2}} | 2026-03-31 18:45:16 | 2026-03-31 18:45:16 | | 7 | 1 | 2026-03-25 | 2 | 0.25 | {"low": {"done": 1, "pending": 1, "in_progress": 1}, "high": {"done": 1, "pending": 0, "in_progress": 1}, "medium": {"done": 0, "pending": 2, "in_progress": 1}} | 2026-03-31 18:45:16 | 2026-03-31 18:45:16 | | 8 | 1 | 2026-03-24 | 3 | 0.43 | {"low": {"done": 2, "pending": 1, "in_progress": 0}, "high": {"done": 0, "pending": 1, "in_progress": 1}, "medium": {"done": 1, "pending": 0, "in_progress": 1}} | 2026-03-31 18:45:17 | 2026-03-31 18:45:17 | | 9 | 1 | 2026-03-23 | 2 | 0.29 | {"low": {"done": 0, "pending": 0, "in_progress": 1}, "high": {"done": 1, "pending": 2, "in_progress": 0}, "medium": {"done": 1, "pending": 0, "in_progress": 2}} | 2026-03-31 18:45:17 | 2026-03-31 18:45:17 | | 10 | 1 | 2026-03-22 | 2 | 0.33 | {"low": {"done": 1, "pending": 1, "in_progress": 0}, "high": {"done": 1, "pending": 0, "in_progress": 1}, "medium": {"done": 0, "pending": 1, "in_progress": 1}} | 2026-03-31 18:45:17 | 2026-03-31 18:45:17 | | 11 | 1 | 2026-03-21 | 3 | 0.50 | {"low": {"done": 0, "pending": 1, "in_progress": 0}, "high": {"done": 3, "pending": 0, "in_progress": 0}, "medium": {"done": 0, "pending": 0, "in_progress": 2}} | 2026-03-31 18:45:17 | 2026-03-31 18:45:17 | +----+---------+-------------+-----------------+-----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+---------------------+ 11 rows in set (0.01 sec)

Top categories

Loading Svelte Themes