New Web Application

Build a complete task management app from scratch. Every prompt is included - from database design to authentication, CRUD, REST API, and admin panel.

Intermediate 4-6 hours project Lesson 11 of 20

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
Prompt 1 - Project init
> 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

Prompt 2 - Database schema
> 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

Prompt 3 - UserModel
> 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.
Prompt 4 - Auth controller + views
> 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

Prompt 5 - Projects CRUD
> 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
Prompt 6 - Tasks CRUD
> 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

Prompt 7 - 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

Prompt 8 - 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)
Build one phase at a time, test before moving on

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.

Frequently Asked Questions

For learning, pure PHP is better - you see exactly what each part does. For production applications, Laravel is strongly recommended once you understand the basics. AI works equally well with Laravel: "Build a Laravel Eloquent model for products with these relationships..." The prompts are almost identical, just with Laravel conventions.

Yes, and it is one of AI's strongest capabilities. Describe your application in plain English: "I need a task management app where users can create projects, add tasks to projects, assign tasks to team members, and set due dates." The AI will propose tables, columns, foreign keys, and indexes. Review the design before implementing it.

Ask the AI: "Create a configuration system that reads from environment variables on production and from a local config.local.php file on development. Add config.local.php to .gitignore." This is a standard pattern that AI implements correctly every time.