{"id":50334238,"url":"https://github.com/rricajos/php-task-manager","last_synced_at":"2026-05-29T12:09:50.038Z","repository":{"id":360664157,"uuid":"1251031600","full_name":"rricajos/php-task-manager","owner":"rricajos","description":"CLI + REST API task manager built with PHP 8.x, SQLite, JWT auth, and design patterns","archived":false,"fork":false,"pushed_at":"2026-05-27T11:23:09.000Z","size":87,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-27T11:31:08.623Z","etag":null,"topics":["cli","design-patterns","jwt-auth","php","php8","phpunit","rest-api","sqlite","task-manager"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rricajos.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-27T07:21:53.000Z","updated_at":"2026-05-27T11:23:14.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/rricajos/php-task-manager","commit_stats":null,"previous_names":["rricajos/php-task-manager"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/rricajos/php-task-manager","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rricajos%2Fphp-task-manager","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rricajos%2Fphp-task-manager/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rricajos%2Fphp-task-manager/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rricajos%2Fphp-task-manager/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rricajos","download_url":"https://codeload.github.com/rricajos/php-task-manager/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rricajos%2Fphp-task-manager/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33650845,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-29T02:00:06.066Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","design-patterns","jwt-auth","php","php8","phpunit","rest-api","sqlite","task-manager"],"created_at":"2026-05-29T12:09:49.501Z","updated_at":"2026-05-29T12:09:50.033Z","avatar_url":"https://github.com/rricajos.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PHP Task Manager\n\n[![CI](https://github.com/rricajos/php-task-manager/actions/workflows/ci.yml/badge.svg)](https://github.com/rricajos/php-task-manager/actions/workflows/ci.yml)\n[![PHP Version](https://img.shields.io/badge/PHP-8.1%2B-777BB4?logo=php\u0026logoColor=white)](https://www.php.net/)\n[![PHPStan](https://img.shields.io/badge/PHPStan-Level%206-brightgreen)](https://phpstan.org/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Tests](https://img.shields.io/badge/tests-93%20passed-brightgreen)](https://github.com/rricajos/php-task-manager/actions)\n\nA task manager with **CLI** and **REST API** interfaces, built with PHP 8.x, SQLite, JWT authentication, and design patterns. Supports multi-user isolation, pagination, sorting, due dates, and streaming export.\n\n## Features\n\n- **Two interfaces**: Interactive CLI menu + REST API with JWT auth\n- **Multi-user isolation**: Each user sees only their own tasks\n- **Task editing**: Update title, description, priority, and due dates via PUT endpoint\n- **Due dates**: Optional fecha_vencimiento with overdue detection\n- **Pagination and sorting**: Configurable page size, sort field, and direction\n- **Priority/status filtering**: Filter tasks by prioridad (alta/media/baja) and estado\n- **Streaming export**: JSON and CSV export streamed directly (no temp files in API mode)\n- **PHP 8.x**: Enums, readonly, constructor promotion, match, named arguments, union types\n- **Design patterns**: Singleton, Repository, Strategy, Dependency Injection\n- **Security**: JWT (HMAC-SHA256), bcrypt password hashing, prepared statements\n- **Testing**: 93 PHPUnit tests (unit + integration)\n- **CI/CD**: GitHub Actions with PHP 8.1/8.2/8.3 matrix, PHPStan static analysis, PHP-CS-Fixer\n- **Docker**: Containerized deployment with docker-compose\n- **Environment config**: .env support for JWT_SECRET, JWT_TTL, DB_PATH\n- **API docs**: OpenAPI 3.0 specification included\n\n## Quick Start\n\n### With Composer\n\n```bash\ngit clone https://github.com/rricajos/php-task-manager.git\ncd php-task-manager\ncomposer install\n```\n\n### With Docker\n\n```bash\n# Start the API server\ndocker compose up -d api\n\n# Or build and run manually\ndocker build -t php-task-manager .\ndocker run -p 8080:8080 php-task-manager\n```\n\n### CLI\n\n```bash\nphp app.php\n\n# Or with Docker\ndocker compose run --rm cli\n```\n\n### REST API\n\n```bash\nphp -S localhost:8080 api.php\n```\n\nThen register and get a token:\n\n```bash\n# Register\ncurl -X POST http://localhost:8080/auth/register \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"username\": \"admin\", \"password\": \"secret123\"}'\n\n# Login\ncurl -X POST http://localhost:8080/auth/login \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"username\": \"admin\", \"password\": \"secret123\"}'\n\n# Create task (use token from login response)\ncurl -X POST http://localhost:8080/tasks \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Authorization: Bearer \u003ctoken\u003e\" \\\n  -d '{\"title\": \"Learn PHP 8\", \"priority\": \"alta\", \"due_date\": \"2026-12-31\"}'\n\n# Update task\ncurl -X PUT http://localhost:8080/tasks/1 \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Authorization: Bearer \u003ctoken\u003e\" \\\n  -d '{\"title\": \"Master PHP 8\", \"priority\": \"media\"}'\n\n# List tasks with pagination and sorting\ncurl \"http://localhost:8080/tasks?page=1\u0026per_page=10\u0026sort=prioridad\u0026order=asc\" \\\n  -H \"Authorization: Bearer \u003ctoken\u003e\"\n```\n\n### Tests\n\n```bash\ncomposer test\n```\n\n### Static Analysis and Code Style\n\n```bash\ncomposer analyse        # Run PHPStan (level 6)\ncomposer cs-check       # Check code style (dry run)\ncomposer cs-fix         # Auto-fix code style\n```\n\n## API Endpoints\n\n| Method | Route | Description | Auth |\n|--------|-------|-------------|------|\n| `POST` | `/auth/register` | Register user | No |\n| `POST` | `/auth/login` | Login (get JWT) | No |\n| `GET` | `/auth/me` | Get authenticated user profile | Yes |\n| `GET` | `/tasks` | List tasks (paginated, filterable, sortable) | Yes |\n| `GET` | `/tasks/{id}` | Get task by ID | Yes |\n| `POST` | `/tasks` | Create task | Yes |\n| `PUT` | `/tasks/{id}` | Update task (title, description, priority, due_date) | Yes |\n| `PATCH` | `/tasks/{id}/complete` | Mark as completed | Yes |\n| `DELETE` | `/tasks/{id}` | Delete task | Yes |\n| `GET` | `/tasks/search?q=keyword` | Search tasks (paginated) | Yes |\n| `GET` | `/tasks/stats` | Statistics | Yes |\n| `GET` | `/tasks/export?format=json\\|csv` | Export tasks (streaming download) | Yes |\n\n### Pagination Parameters\n\nAll list endpoints support the following query parameters:\n\n| Parameter | Default | Description |\n|-----------|---------|-------------|\n| `page` | `1` | Page number |\n| `per_page` | `20` | Results per page (max 100) |\n| `sort` | `fecha_creacion` | Sort field (`fecha_creacion`, `prioridad`, `titulo`, `estado`) |\n| `order` | `DESC` | Sort direction (`ASC` or `DESC`) |\n| `status` | `todas` | Filter by status (`pendiente`, `completada`, `todas`) |\n| `priority` | _(none)_ | Filter by priority (`alta`, `media`, `baja`) |\n\nFull API documentation available in [openapi.yaml](openapi.yaml) -- view it in [Swagger Editor](https://editor.swagger.io/).\n\n## Environment Variables\n\nConfigure via `.env` file or system environment:\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `JWT_SECRET` | `super_secret_key_change_me` | Secret key for signing JWT tokens (change in production) |\n| `JWT_TTL` | `86400` | JWT token lifetime in seconds (default: 24 hours) |\n| `DB_PATH` | `data/tasks.db` | Path to the SQLite database file |\n\n## Architecture\n\n```\nphp-task-manager/\n├── app.php                  # CLI entry point\n├── api.php                  # REST API entry point\n├── openapi.yaml             # OpenAPI 3.0 spec\n├── composer.json\n├── phpunit.xml\n├── phpstan.neon             # PHPStan static analysis config\n├── .php-cs-fixer.php        # PHP-CS-Fixer code style config\n├── .env                     # Environment variables (not committed)\n├── Dockerfile               # Container image definition\n├── docker-compose.yml       # Multi-service orchestration\n├── data/\n│   └── tasks.db             # SQLite database (auto-created)\n├── src/\n│   ├── ApiController.php    # REST controller (user-scoped)\n│   ├── AppException.php     # Custom exception hierarchy\n│   ├── AuthService.php      # Registration, login, JWT, profile\n│   ├── Database.php         # Singleton PDO connection\n│   ├── ExportService.php    # Strategy: JSON + CSV exporters (file + streaming)\n│   ├── JsonResponse.php     # HTTP response helper (paginated support)\n│   ├── Router.php           # HTTP router with path params\n│   ├── Task.php             # Entity with Priority/Status enums, due dates\n│   ├── TaskRepository.php   # Data access layer (user-scoped)\n│   └── TaskService.php      # Business logic + validation + pagination\n├── tests/\n│   ├── Unit/\n│   │   ├── TaskTest.php          # Entity, enums, factory tests\n│   │   ├── TaskServiceTest.php   # Validation, CRUD, search tests\n│   │   └── ExportServiceTest.php # JSON/CSV export tests\n│   └── Integration/\n│       └── TaskWorkflowTest.php  # End-to-end workflow tests\n└── .github/\n    └── workflows/\n        └── ci.yml           # CI: tests, PHPStan, code style\n```\n\n## Design Patterns\n\n| Pattern | Class | Purpose |\n|---------|-------|---------|\n| **Singleton** | `Database` | Single PDO connection instance |\n| **Repository** | `TaskRepository` | Encapsulated data access with user-scoped queries |\n| **Strategy** | `ExporterInterface` / `JsonExporter` / `CsvExporter` | Pluggable export formats (file + streaming) |\n| **Dependency Injection** | `TaskService`, `ApiController`, `AuthService` | Constructor-injected dependencies |\n\n## Requirements\n\n- PHP 8.1+\n- `pdo_sqlite` extension\n- Composer (for dependency management)\n- Docker (optional, for containerized deployment)\n\n## Roadmap\n\n- [ ] Task categories/tags\n- [ ] Recurring tasks\n- [ ] Team collaboration (shared task lists)\n- [ ] WebSocket notifications for real-time updates\n- [ ] Rate limiting on API endpoints\n- [ ] OpenAPI schema validation middleware\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frricajos%2Fphp-task-manager","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frricajos%2Fphp-task-manager","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frricajos%2Fphp-task-manager/lists"}