Project Structure

Keel keeps framework internals separate from app code while keeping views plain PHP.

public_html/
  index.php
  css/keel.css       yours
  js/keel.js         yours
  deck/              Deck's, published by Composer, git-ignored
    deck.css
    deck.min.css
    deck.js
    deck-extras.js
    deck-icons.svg
  uploads/
src/
  Core/
  App/
    Controllers/
    Middleware/
    Models/
    Services/
routes/
  web.php
views/
  partials/
  auth/
  dashboard/
resources/
  images/
database/
  migrations/
  migrate.php
  queue-work.php
tests/
storage/
  logs/
  app/

What belongs where

  • src/Core/: framework internals like Router, Request, Response, Database, View, ErrorHandler.
  • src/App/Controllers/: HTTP endpoints and request orchestration.
  • src/App/Services/: business logic, external APIs, and workflows.
  • src/App/Middleware/: route guards and request checks.
  • routes/web.php: route registration.
  • views/: plain PHP templates (no template engine dependency).
  • public_html/deck/: Deck's published files. Not yours — see below.
  • public_html/css/keel.css and public_html/js/keel.js: Keel's own styles and glue, served exactly as written. There is no build step.
  • resources/images/: brand source images.
  • database/migrations/: SQL migrations applied by php database/migrate.php.
  • database/queue-work.php: queue worker CLI entrypoint.

Deck's files versus yours

Two directories under public_html/ hold CSS. The difference matters, because one of them is overwritten without warning.

  public_html/deck/ public_html/css/keel.css
Whose Deck's Yours
How it gets there composer install You write it
In git No, git-ignored Yes
Safe to edit Never Always

Never edit anything in public_html/deck/. It is build output: Composer republishes the whole directory on every install and update, so an edit there survives until the next install and then vanishes — including on a teammate's machine, and in CI, where it never existed at all. The directory is git-ignored for that reason, and a fresh clone has no public_html/deck/ until Composer runs.

Everything you want to change goes in public_html/css/keel.css instead. Deck reserves four cascade layers for it — app.base, app.components, app.pages and app.overrides — which are declared after all of Deck's, so a rule there beats a Deck rule without !important and without extra specificity. That is the supported way to override Deck, and it survives upgrades. See Building the Interface.