What We Build
A TaskFlow task management application with:
- User registration and login (sessions + remember me)
- Projects that users can create and share
- Tasks within projects (title, description, priority, due date, status)
- REST API for all CRUD operations
- Admin panel for user and content management
> Initialize a PHP task management app called "TaskFlow":
Directory structure:
/app/
controllers/AuthController.php, ProjectController.php, TaskController.php
models/UserModel.php, ProjectModel.php, TaskModel.php
middleware/AuthMiddleware.php
/api/
auth.php, projects.php, tasks.php
/config/
db.php, app.php
/public/
index.php (entry point)
/views/
auth/login.php, auth/register.php
projects/index.php, projects/show.php, projects/form.php
tasks/form.php
admin/index.php, admin/users.php
shared/header.php, footer.php
/assets/
css/app.css, js/app.js
Create CLAUDE.md describing this architecture.
Create all files with appropriate empty class/function stubs.
Phase 1: Database Design
> Design and create the complete database schema for TaskFlow.
Create /database/schema.sql with these tables:
users: id, name, email, password_hash, role(user/admin), avatar,
email_verified, remember_token, last_login, created_at
projects: id, name, description, owner_id(FK users), color, status,
created_at, archived_at
project_members: id, project_id, user_id, role(owner/member/viewer), joined_at
tasks: id, project_id, title, description, assigned_to(FK users),
priority(low/medium/high/urgent), status(todo/in_progress/done/cancelled),
due_date, completed_at, sort_order, created_by, created_at, updated_at
comments: id, task_id, user_id, content, created_at
Add appropriate indexes for foreign keys and commonly filtered columns.
Add ON DELETE CASCADE where appropriate.
Phase 2: Authentication
> Build app/models/UserModel.php with these methods:
- create(array $data): int (hash password, return new user ID)
- findByEmail(string $email): ?array
- findById(int $id): ?array
- update(int $id, array $data): bool
- updatePassword(int $id, string $newPassword): bool
- setRememberToken(int $id, string $token): bool
- findByRememberToken(string $token): ?array
- all(int $limit = 50, int $offset = 0): array
Use PDO prepared statements. Password: password_hash/verify.
> Build the complete authentication system:
app/controllers/AuthController.php:
- showLogin(), processLogin(), showRegister(), processRegister(), logout()
- processLogin: validate, check credentials, start session, handle remember_me cookie (30 days)
- processRegister: validate, check email uniqueness, create user, auto-login
- CSRF token verification on all POST handlers
views/auth/login.php:
- Email + password fields, remember me checkbox
- Bootstrap card layout, validation error display, register link
views/auth/register.php:
- Name, email, password, confirm password
- Client-side password strength indicator (JS)
app/middleware/AuthMiddleware.php:
- check(): redirects to login if not authenticated (session or remember_me cookie)
- admin(): additionally checks role === 'admin'
Phase 3: CRUD Features
> Build the complete Projects feature:
app/models/ProjectModel.php:
- getUserProjects(int $userId): array (owned + member of)
- create(array $data, int $ownerId): int
- update(int $id, array $data): bool
- delete(int $id): bool (archive it, not hard delete)
- addMember(int $projectId, int $userId, string $role): bool
- getMembers(int $projectId): array
views/projects/index.php:
- Grid of project cards with color accent, task count, member avatars
- "New Project" button opens a modal form
- Filter by: My Projects, Shared With Me, Archived
views/projects/show.php:
- Project header with name, description, member list, settings button
- Task board view: 3 columns (Todo, In Progress, Done)
- Each task is a draggable card showing: title, priority badge, due date, assignee avatar
- "Add Task" button at bottom of each column
> Build the complete Tasks feature:
app/models/TaskModel.php:
- getByProject(int $projectId): array (grouped by status)
- create(array $data): int
- update(int $id, array $data): bool
- updateStatus(int $id, string $status): bool
- delete(int $id): bool
- getComments(int $taskId): array
- addComment(int $taskId, int $userId, string $content): int
views/tasks/form.php (used as a modal or page):
- Title, description (textarea), priority select, status select,
assigned_to select (project members), due_date picker
- Comment thread at bottom of edit form
Add drag-and-drop in assets/js/app.js:
- Drag tasks between status columns
- Call updateStatus API on drop
Phase 4: REST API
> Build JSON REST API endpoints:
api/projects.php:
GET /api/projects List user's projects
POST /api/projects Create project
GET /api/projects/{id} Get single project with tasks
PUT /api/projects/{id} Update project
DELETE /api/projects/{id} Archive project
api/tasks.php:
GET /api/tasks?project_id=X List tasks for a project
POST /api/tasks Create task
PUT /api/tasks/{id} Update task (including status change)
DELETE /api/tasks/{id} Delete task
All endpoints:
- Auth via session (same as web) or Bearer token in Authorization header
- Return JSON with Content-Type: application/json
- Return {"error": "message"} with correct HTTP status on failure
- Route parsing: use $_SERVER['REQUEST_URI'] and $_SERVER['REQUEST_METHOD']
Phase 5: Admin Panel
> Build the admin panel at /admin/:
views/admin/index.php (dashboard):
- Stats cards: total users, total projects, total tasks, tasks completed today
- Recent registrations table (last 10 users)
- Recent activity feed
views/admin/users.php:
- Full user list table: avatar, name, email, role, last_login, created_at
- Actions: Edit role (user/admin), Suspend/Unsuspend, Delete
- Search by name/email
- Pagination (20 per page)
All admin routes protected by AuthMiddleware::admin()
Use a separate Bootstrap sidebar layout for admin (not the public layout)
Resist the temptation to run all 8 prompts at once. After each phase: open the browser, test the feature manually, fix any issues with follow-up prompts. Building on a broken foundation multiplies the problems. Each phase should be working before starting the next.