diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..e1cb160 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,12 @@ +.git +.gitignore +graphify-out/ +.claude/ +public/cache/* +!public/cache/.gitkeep +data/*.sqlite* +images/* +!images/.gitkeep +docker-compose.yml +Dockerfile +Dockerfile.sass diff --git a/.gitignore b/.gitignore index 20e923f..397ada8 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ /data/*.sqlite-shm .claude/ /graphify-out/ +/images/* +!/images/.gitkeep diff --git a/AGENTS.md b/AGENTS.md index 03b3f09..e7faa99 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -246,6 +246,19 @@ index below) before `App/migrations/` (project schema) — see the project adds still defaults to no `migrations_dir` at all unless it sets one; the two-root default is specific to `default`. +A sibling top-level `images/` directory (same gitignore-wholesale-with- +`.gitkeep` treatment as `public/cache/`) exists as **reserved scaffolding +for a future image-upload feature — no config key, no upload code, nothing +reads or writes it yet.** It's deliberately a separate directory from +`data/`, not nested under it, even though both are "project data that +survives a framework update": a project may run MySQL, or no database at +all, so coupling image storage to the SQLite volume would be wrong. See +`novaconium/pages/admin/docs/docker/index.twig` for how the Docker Compose +setup gives it its own volume. Don't add an `images_dir` config key until +an actual feature reads it — an unused key would misrepresent the +framework's state, the same reasoning that keeps every other config key +tied to real consuming code. + `Lib\Session` (`novaconium/lib/Session.php`) is a thin wrapper around native PHP sessions (`session_start()`/`$_SESSION`, not a custom store), all-static and lazy-start like `Lib\Csrf` — nothing calls `session_start()` diff --git a/CLAUDE.md b/CLAUDE.md index 43c994c..a75ef03 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1 +1,6 @@ +# Agent permissions + +- Only run `git` commands with the user's explicit permission for that specific command/action. +- Never run `docker` commands (build, compose up, run, etc.) — leave all Docker execution to the user. + @AGENTS.md diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..56eeaf9 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,40 @@ +# Arch Linux + Apache + PHP image for running novaconium in production. +# See /admin/docs/docker for volumes, overriding App/ without a rebuild, +# and optional MySQL wiring. +FROM archlinux:base + +RUN pacman -Syu --noconfirm --needed apache php php-apache sqlite \ + && pacman -Scc --noconfirm + +# php-apache on Arch is built against mpm_prefork, not httpd's default +# mpm_event — swap MPMs, enable mod_rewrite, point DocumentRoot at +# public/, and wire in mod_php. +RUN sed -i \ + -e 's/^LoadModule mpm_event_module/#LoadModule mpm_event_module/' \ + -e 's/^#LoadModule mpm_prefork_module/LoadModule mpm_prefork_module/' \ + -e '/^#LoadModule rewrite_module/s/^#//' \ + -e 's#DocumentRoot "/srv/http"#DocumentRoot "/var/www/html/public"#' \ + -e 's###' \ + -e 's/^AllowOverride None/AllowOverride All/' \ + /etc/httpd/conf/httpd.conf \ + && printf '\nLoadModule php_module modules/libphp.so\nAddHandler php-script .php\nDirectoryIndex index.php index.html\nServerName localhost\n' \ + >> /etc/httpd/conf/httpd.conf \ + && sed -i \ + -e 's/^;extension=pdo_sqlite/extension=pdo_sqlite/' \ + -e 's/^;extension=pdo_mysql/extension=pdo_mysql/' \ + /etc/php/php.ini + +WORKDIR /var/www/html + +COPY novaconium/ ./novaconium/ +COPY public/ ./public/ +COPY App/ ./App/ + +# Runtime-writable paths not covered by named volumes in docker-compose.yml. +RUN mkdir -p public/cache data images \ + && touch novaconium/contact-log.txt \ + && chown -R http:http public/cache data images App novaconium/contact-log.txt + +EXPOSE 80 + +CMD ["httpd", "-D", "FOREGROUND"] diff --git a/README.md b/README.md index c23d614..b4f3b81 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,14 @@ Visit `http://127.0.0.1:8000/` for the static home page, then click around — ` Point the vhost's document root at `public/`, make sure `mod_rewrite` is enabled and `AllowOverride All` is set for that directory so `public/.htaccess` takes effect, and it just works — no build step required. +### Run it in Docker + +``` +docker compose up --build +``` + +Builds an Arch Linux-based Apache/PHP image and serves the site at `http://localhost:8080/`. Three named volumes (`cache`, `data`, `images`) keep the page cache, SQLite database, and a reserved-for-later images directory out of paths the "Updating the framework" workflow below would wipe; `App/` is baked into the image but can be bind-mounted for edits without a rebuild. See [Docker](http://127.0.0.1:8000/admin/docs/docker) for details. + ### Starting a new project Clone this repo and drop its Git history — no Composer scaffold or installer: @@ -86,6 +94,7 @@ php novaconium/bin/create-static-page.php blog/my-new-post The full framework documentation — routing, sidecars, libraries, database, session, content index, XML sitemap, RSS feeds, layouts, static caching, SEO, Matomo analytics, admin authentication, draft pages, styling, project layout, and third-party notices — lives at `/admin/docs` on any running instance (so it travels with the code, no internet connection needed). Highlights: - [Getting started](http://127.0.0.1:8000/admin/docs/getting-started) +- [Docker](http://127.0.0.1:8000/admin/docs/docker) - [Routing](http://127.0.0.1:8000/admin/docs/routing) - [Sidecars](http://127.0.0.1:8000/admin/docs/sidecars) - [Libraries](http://127.0.0.1:8000/admin/docs/libraries) diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..489d351 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,29 @@ +services: + web: + build: . + ports: + - "8080:80" + volumes: + - cache:/var/www/html/public/cache + - data:/var/www/html/data + - images:/var/www/html/images + # Uncomment to override the baked-in App/ with a host copy, no rebuild: + # - ./App:/var/www/html/App + + # Optional — only needed if App/config.php adds a db_connections entry + # with driver: mysql. See /admin/docs/database. + # db: + # image: mysql:8 + # environment: + # MYSQL_DATABASE: novaconium + # MYSQL_USER: novaconium + # MYSQL_PASSWORD: change-me + # MYSQL_ROOT_PASSWORD: change-me + # volumes: + # - mysql-data:/var/lib/mysql + +volumes: + cache: + data: + images: + # mysql-data: diff --git a/images/.gitkeep b/images/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/novaconium/pages/admin/docs/_layout/layout.twig b/novaconium/pages/admin/docs/_layout/layout.twig index 4834f91..a67cfc7 100644 --- a/novaconium/pages/admin/docs/_layout/layout.twig +++ b/novaconium/pages/admin/docs/_layout/layout.twig @@ -8,6 +8,7 @@