# wms-app — web server rules for the repository root.
#
# The whole repository sits under the web root (/wms-app/), so everything that is
# not part of the running app must be refused here: git history, .env files,
# deployment and build folders, SDLC documents, the Node server source, CLI-only
# PHP scripts and library internals. Needs AllowOverride All (docker/php/apache-wms.conf
# enables it for the container) plus mod_rewrite and mod_headers.
Options -Indexes
RewriteEngine On
# HTTP → HTTPS when the deployment says TLS is available (FORCE_HTTPS=true in the
# environment). Honours X-Forwarded-Proto so it also works behind a TLS proxy.
RewriteCond %{ENV:FORCE_HTTPS} ^true$
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP:X-Forwarded-Proto} !=https
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# Dotfiles and dot-folders anywhere: .git, .env, .claude, .htaccess, .mcp.json …
RewriteRule (^|/)\. - [R=404,L]
# Folders that are never served.
RewriteRule ^(nodejs|docker|sdlc|sdlc-delivery|scripts|lib|notes|docs|vendor|node_modules)(/|$) - [R=404,L]
# Repository files at the root: build/deploy config, CLI scripts, archives, docs.
RewriteRule ^(composer\.(json|lock)|docker-compose\.ya?ml|setup\.php|demo_seed[^/]*\.php)$ - [R=404,L]
RewriteRule \.(zip|tar|gz|tgz|sql|sh|md|log|bak|old|orig|swp|dist|example|ini|yml|yaml|lock|env|pem|key|crt|map)$ - [R=404,L]
# App internals included by the entry points, never requested directly: config,
# DB connection, shared utilities, manager classes, bundled libraries (PHPMailer
# ships get_oauth_token.php), and the page fragments.
RewriteRule ^app/(config[^/]*\.php|dbconn\.php|preset\.php)$ - [R=404,L]
RewriteRule ^app/assets/utils/ - [R=404,L]
RewriteRule ^app/include_[^/]+\.php$ - [R=404,L]
# Uploaded files are served through a PHP gate that requires a signed-in session.
RewriteRule ^app/uploads/(.+)$ app/file.php?path=$1 [L,QSA,B]
# Sent on every response (pages, API JSON, static files). Pages add a
# Content-Security-Policy of their own from include_header.php.
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "geolocation=(), microphone=(), payment=(), usb=()"
Header always unset X-Powered-By
Header unset X-Powered-By
# HSTS only means anything over HTTPS; browsers ignore it on plain HTTP.
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" "expr=%{HTTPS} == 'on' || %{HTTP:X-Forwarded-Proto} == 'https'"