# =====================================================================
#  Nexa Admin — public/ (DocumentRoot)
#  TDD §3.1 steps 2-3, §13.1, §15.6
# =====================================================================

# ---------------------------------------------------------------------
# Directory listing
# ---------------------------------------------------------------------
# Without this, a directory with no index file lists its contents,
# exposing the full asset tree and plugin versions to an attacker.
Options -Indexes

# Do not follow symlinks whose owner differs from the link's.
Options +FollowSymLinks

# ---------------------------------------------------------------------
# Front controller
# ---------------------------------------------------------------------
<IfModule mod_rewrite.c>
    RewriteEngine On

    # Honour the DocumentRoot when the app is reached through an alias.
    RewriteBase /

    # Redirect trailing slashes to the canonical form, so /users/ and
    # /users are not two distinct URLs.
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} (.+)/$
    RewriteRule ^ %1 [L,R=301]

    # An existing file or directory is served directly by Apache and PHP is
    # never invoked. This is why public/assets costs nothing at runtime.
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d

    # Everything else goes to the front controller. REQUEST_URI is preserved,
    # so the router sees the original path.
    RewriteRule ^ index.php [L]
</IfModule>

<IfModule !mod_rewrite.c>
    # Fail loudly rather than serving a directory listing or a blank page.
    <IfModule mod_headers.c>
        Header set X-Rewrite-Missing "true"
    </IfModule>
    ErrorDocument 500 "mod_rewrite is not enabled. The application cannot route requests."
</IfModule>

# ---------------------------------------------------------------------
# Deny access to sensitive files
# ---------------------------------------------------------------------
# Redundant with these files living above the DocumentRoot. Redundant
# deliberately: it is what keeps one misconfiguration from becoming a breach.
<FilesMatch "^\.(env|git|htaccess|htpasswd|DS_Store)|\.(ini|log|sh|sql|bak|swp|dist|json|lock|md)$">
    Require all denied
</FilesMatch>

# ---------------------------------------------------------------------
# Security headers
# ---------------------------------------------------------------------
# Also set in PHP (Response::applySecurityHeaders) so they apply to static
# assets served directly by Apache, which never reach PHP.
<IfModule mod_headers.c>
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Frame-Options "DENY"
    Header always set Referrer-Policy "strict-origin-when-cross-origin"

    # Strip the PHP version fingerprint if expose_php is on.
    Header always unset X-Powered-By
    Header always unset Server
</IfModule>

# ---------------------------------------------------------------------
# Static asset caching
# ---------------------------------------------------------------------
# Safe because asset URLs carry a version query string (TDD §17.6); a
# changed file gets a new URL, so a long max-age never serves stale content.
<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType text/css                 "access plus 1 year"
    ExpiresByType application/javascript   "access plus 1 year"
    ExpiresByType text/javascript          "access plus 1 year"
    ExpiresByType image/png                "access plus 1 year"
    ExpiresByType image/jpeg               "access plus 1 year"
    ExpiresByType image/gif                "access plus 1 year"
    ExpiresByType image/svg+xml            "access plus 1 year"
    ExpiresByType image/webp               "access plus 1 year"
    ExpiresByType font/woff                "access plus 1 year"
    ExpiresByType font/woff2               "access plus 1 year"
    ExpiresByType application/font-woff    "access plus 1 year"
    ExpiresByType application/vnd.ms-fontobject "access plus 1 year"
    ExpiresDefault                         "access plus 1 day"
</IfModule>

<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/html text/plain text/css text/javascript
    AddOutputFilterByType DEFLATE application/javascript application/json
    AddOutputFilterByType DEFLATE image/svg+xml
</IfModule>

# ---------------------------------------------------------------------
# Upload limits
# ---------------------------------------------------------------------
# The application-level check in UploadService (Phase 7) only runs AFTER PHP
# has accepted the body, so the ceiling is enforced here as well (TDD §16.6).
<IfModule mod_php.c>
    php_value upload_max_filesize 20M
    php_value post_max_size 24M
</IfModule>

# 24 MB, matching post_max_size above.
LimitRequestBody 25165824
