practical capstone projects

Capstone: Maintainable PHP App

The capstone turns the catalog increments into one portfolio application another developer can run, review, test, and deploy. Do not restart from a blank directory. Consolidate the product manager, login, templates, CLI command, and JSON API into one maintained repository.

Keep The Scope Finishable

The required application is deliberately small:

public product list and detail pages
admin login and logout
protected create, edit, and delete actions
PDO migration and product repository
escaped templates and server-side validation
CSRF protection for browser state changes
CLI product report
read-only JSON product endpoints
automated checks and deployment notes

Add a feature only when the required application is complete. A finished understandable app is stronger portfolio evidence than an unfinished list of technologies.

Use A Reviewable Repository Shape

bin/products-report.php
migrations/
public/index.php
src/Controller/
src/Repository/
src/Service/
templates/
tests/
.env.example
README.md

Keep secrets out of Git. Explain required environment variables in .env.example and the README.

Add Verification At Several Boundaries

Use the cheapest useful check for each risk:

RiskMinimum evidence
Product validationfocused unit test
PDO statements and mappingrepository integration test
Anonymous admin editHTTP-level rejected request
CSRF failureHTTP-level rejected request
Escapingproduct name containing HTML characters
JSON missing productcurl request returning stable 404 JSON
CLI reportnormal and invalid command exits
Deploymentdocumented build, migration, health, and rollback steps

Write The README For A New Developer

Start from a clean checkout and follow only the README. It should explain runtime requirements, environment setup, dependency installation, migration, local server command, test commands, CLI report usage, and deployment outline.

Record one short architecture note: where requests enter, where SQL lives, where authorization runs, and where templates escape output.

Final Review

Before calling the app portfolio-ready:

  1. Run from a clean checkout.
  2. Exercise normal and rejected browser journeys.
  3. Run automated checks.
  4. Review tracked files for secrets and runtime output.
  5. Explain one tradeoff you intentionally made.

Practice

Practice: Finish The Capstone App

Consolidate the guided catalog increments into one repository and prove the application from a clean checkout.

Requirements

  • Implement product browsing and an authenticated admin edit flow.
  • Use PDO migrations and prepared statements.
  • Add escaped templates, validation, CSRF protection, and sessions.
  • Provide CLI maintenance and a small JSON endpoint.
  • Keep the project small enough to finish.
  • Do not hide errors or commit secrets.
  • Include README setup and verification steps.

Produce:

  • the working repository shape from the lesson;
  • a README another developer can follow without hidden setup;
  • the verification evidence table completed with commands or test names;
  • one short architecture note;
  • one deliberate tradeoff you can explain in an interview.
Show solution
clean checkout installs dependencies and applies migrations
local server command opens the product list
anonymous admin edit is rejected
valid admin login regenerates the session ID
create, edit, and delete use validation, authorization, CSRF, and prepared statements
HTML-looking product names render as text
JSON list, found, and missing responses keep stable shapes
CLI report documents successful and failed exits
automated checks pass
deployment notes include migration, health check, and rollback

The architecture note should be brief and concrete:

Requests enter through public/index.php and the router.
Controllers translate HTTP input and call application code.
ProductRepository owns SQL.
Authorization runs before admin changes.
Templates escape untrusted values when rendering HTML.

The app is ready to discuss in an interview when another developer can reproduce those checks from the README and you can explain why each boundary exists.