Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
035dfed
chore: update composer package name and description
MahdiiMax Aug 22, 2026
852c2ef
refactor: cast model attributes to enums and extract task filter scope
MahdiiMax Aug 22, 2026
f5eead3
fix: return empty 204 responses and support per_page pagination
MahdiiMax Aug 22, 2026
fd6e1f7
test: cover per_page limits, no-content deletes, and enum casts
MahdiiMax Aug 22, 2026
38743af
docs: document per_page parameter and 204 status code
MahdiiMax Aug 22, 2026
facae61
Merge pull request #8 from MahdiiMax/refactor/code-cleanup
MahdiiMax Aug 22, 2026
f7f75ef
feat: add sortable fields whitelist and sort scope to tasks
MahdiiMax Aug 24, 2026
cfa168a
feat: validate sort parameter against allowed fields
MahdiiMax Aug 24, 2026
32228ae
feat: add task statistics endpoint and wire sorting into task listing
MahdiiMax Aug 24, 2026
9bf2f54
feat: register stats route
MahdiiMax Aug 24, 2026
56dc485
test: cover task statistics and sorting behavior
MahdiiMax Aug 24, 2026
60057b0
docs: update OpenAPI spec with statistics endpoint and sorting
MahdiiMax Aug 24, 2026
14886b1
docs: document statistics endpoint and sort parameter
MahdiiMax Aug 24, 2026
3748231
Merge pull request #9 from MahdiiMax/feature/stats-and-sorting
MahdiiMax Aug 24, 2026
071e76f
chore: add larastan as dev dependency
MahdiiMax Aug 28, 2026
a9f3d30
chore: configure phpstan at level 5
MahdiiMax Aug 28, 2026
0ba3506
Revert "chore: configure phpstan at level 5"
MahdiiMax Aug 28, 2026
9896c24
Revert "chore: add larastan as dev dependency"
MahdiiMax Aug 28, 2026
a5d218f
ci: add GitHub Actions pipeline with Pest Postgres matrix
MahdiiMax Aug 28, 2026
37f4f2c
ci: run workflows on PHP 8.5 to match locked dependencies
MahdiiMax Aug 28, 2026
03e10be
ci: run tests against PostgreSQL via per-matrix PHPUnit config
MahdiiMax Aug 28, 2026
200d309
ci: run pest directly to avoid duplicate configuration flag
MahdiiMax Aug 28, 2026
d20dae2
Merge pull request #10 from MahdiiMax/ci/pipeline
MahdiiMax Aug 28, 2026
48192b1
docs: add changelog
MahdiiMax Aug 29, 2026
1f1d1fa
docs: refresh README for v1.2.0 features and testing
MahdiiMax Aug 29, 2026
fea75a3
Merge pull request #11 from MahdiiMax/docs/release-docs
MahdiiMax Aug 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
name: CI

on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]

jobs:
pint:
name: Code Style
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: "8.5"
extensions: mbstring, xml, ctype, json, bcmath, pdo, pgsql
tools: composer:v2
coverage: none
- uses: actions/cache@v4
with:
path: vendor
key: composer-${{ runner.os }}-${{ hashFiles('**/composer.lock') }}
- run: composer install --no-progress --prefer-dist
- run: vendor/bin/pint --test

test:
name: Tests (${{ matrix.db }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- db: SQLite
connection: sqlite
config: phpunit.xml
- db: PostgreSQL
connection: pgsql
config: phpunit.pgsql.xml

services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_DB: testing
POSTGRES_USER: root
POSTGRES_PASSWORD: password
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5

env:
DB_CONNECTION: ${{ matrix.connection }}

steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: "8.5"
extensions: mbstring, xml, ctype, json, bcmath, pdo, pgsql, sqlite3
tools: composer:v2
coverage: none
- uses: actions/cache@v4
with:
path: vendor
key: composer-${{ runner.os }}-${{ hashFiles('**/composer.lock') }}
- run: composer install --no-progress --prefer-dist
- run: cp .env.example .env
- run: php artisan key:generate
- run: vendor/bin/pest --configuration=${{ matrix.config }}
62 changes: 62 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/),
and this project adheres to [Semantic Versioning](https://semver.org/).

## [1.2.0] - 2026-08-28

### Added

- `GET /tasks/stats` endpoint with aggregate counts by status/priority,
overdue, due-today, and completed-this-week
- Sorting support on the task listing via a whitelisted `?sort=` parameter
(`-` prefix for descending order)
- `per_page` pagination control (1–100, default 10)
- Continuous integration pipeline (Pint + Pest suite, including a PostgreSQL
matrix) via GitHub Actions
- CI status badge in the README
- Project `color` cast to the `ProjectColor` enum

### Changed

- PHPUnit config split into `phpunit.xml` (SQLite) and `phpunit.pgsql.xml`
(PostgreSQL) for the driver matrix
- Composer package renamed from `laravel/laravel` to `mahdiimax/taskify`
- Task `status`, `priority`, and `due_date` cast to enums / datetime
- Task filtering extracted into a reusable `filter()` query scope using
driver-aware `whereLike()`

### Fixed

- Delete endpoints return a proper empty `204 No Content` response
- Redundant manual `Hash::make()` removed in favor of the `hashed` cast
- Eager loading added to prevent N+1 queries on task resources

## [1.1.0] - 2026-08-14

### Added

- Projects: full CRUD with soft delete & restore
- Color-coded projects via the `ProjectColor` enum
- `project_id` on tasks, with filtering by project scoped to the owner
- Exposed `project_id` in the task resource

## [1.0.0] - 2026-08-06

### Added

- Sanctum token authentication (24h expiry, logout revocation)
- Full task CRUD with soft delete & restore (`trashed` / `restore`)
- Task filtering by `status` / `priority` and case-insensitive `search`
- Per-user task isolation via policies
- Rate limiting (auth 5/min, API 60/min)
- Interactive OpenAPI docs via Scramble
- Pest feature tests: auth, revocation, token expiry, filtering, rate limits
- PostgreSQL + Docker / pgAdmin setup

[Unreleased]: https://github.com/MahdiiMax/taskify/compare/1.1.0...develop
[1.2.0]: https://github.com/MahdiiMax/taskify/compare/1.1.0...1.2.0
[1.1.0]: https://github.com/MahdiiMax/taskify/compare/1.0.0...1.1.0
[1.0.0]: https://github.com/MahdiiMax/taskify/releases/tag/1.0.0
14 changes: 11 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<img src="https://img.shields.io/badge/Sanctum-Auth-000000?style=for-the-badge" alt="Sanctum">
<img src="https://img.shields.io/badge/API-v1-0ea5e9?style=for-the-badge" alt="API v1">
<img src="https://img.shields.io/badge/License-MIT-yellow?style=for-the-badge" alt="MIT">
<img src="https://img.shields.io/github/actions/workflow/status/MahdiiMax/taskify/ci.yml?branch=main&style=for-the-badge" alt="CI">
</p>


Expand All @@ -21,10 +22,12 @@

- 🔐 **Sanctum token auth** — 24-hour token expiry, revocable via logout
- 📝 **Full CRUD** with soft delete & restore
- 🔍 **Smart filtering** — exact `status`/`priority` filters + case-insensitive search
- 🔍 **Smart filtering** — exact `status`/`priority`/`project_id` filters + case-insensitive search, plus `?sort=` ordering and `?per_page=` pagination
- 📊 **Statistics** — `GET /tasks/stats` aggregates by status/priority, overdue, due-today, and completed-this-week
- 👤 **Per-user isolation** — tasks and projects are private to their owner
- 📁 **Projects** — organize tasks into color-coded projects with full CRUD, soft delete & restore
- 🚦 **Rate limiting** — auth (5/min) & API (60/min)
- ✅ **CI pipeline** — Pint style checks + Pest test suite across SQLite & PostgreSQL
- 📚 **Interactive docs** via Scramble
- 🗃️ **PostgreSQL** + Docker setup included

Expand Down Expand Up @@ -105,10 +108,10 @@ composer test # or: php artisan test

The suite runs on in-memory SQLite — no DB server needed. ⚠️ *SQLite is more lenient than PostgreSQL; run the suite against real Postgres before release to catch driver-specific issues.*

If you want to run tests in your own PostgreSQL server:
Run the suite against a real PostgreSQL server (adjust the credentials in `phpunit.pgsql.xml` to match your database):

```bash
php artisan test --env=pgsql
vendor/bin/pest --configuration=phpunit.pgsql.xml
```


Expand All @@ -130,6 +133,7 @@ php artisan test --env=pgsql

tests/
├── Feature/Api/V1/ # AuthTest, TaskTest, ProjectTest
└── phpunit.pgsql.xml # PostgreSQL test configuration (CI)


## 📜 API Reference
Expand Down Expand Up @@ -186,6 +190,7 @@ Tokens are issued by `login`, live **24 hours**, and are revoked by `logout`.
| PUT/PATCH | `/tasks/{task}` | Update a task |
| DELETE | `/tasks/{task}` | Soft delete a task |
| GET | `/tasks/trashed` | List soft-deleted tasks |
| GET | `/tasks/stats` | Aggregate statistics for your tasks |
| POST | `/tasks/{task}/restore` | Restore a soft-deleted task |

#### Task Fields
Expand All @@ -207,6 +212,8 @@ Tokens are issued by `login`, live **24 hours**, and are revoked by `logout`.
| `priority` | `?priority=high` | exact match |
| `search` | `?search=buy milk` | case-insensitive partial match on title/description |
| `project_id` | `?project_id=3` | exact match (your projects only) |
| `per_page` | `?per_page=25` | page size 1–100, default 10 |
| `sort` | `?sort=-due_date,title` | whitelist: title, status, priority, due_date, created_at · `-` prefix = descending |

Invalid `status`/`priority` values → `422`.

Expand Down Expand Up @@ -236,6 +243,7 @@ Invalid `status`/`priority` values → `422`.
| --- | --- |
| `200` | Success |
| `201` | Created |
| `204` | Deleted (empty response body) |
| `400` | Already authenticated (on login/register) |
| `401` | Unauthenticated / expired or revoked token |
| `403` | Forbidden (another user's resource) |
Expand Down
Loading
Loading