#!/bin/sh
# Read-only filesystem architecture validator for websites/apps/<appname>.
set -eu
APPS_ROOT=${APPS_ROOT:-/home/intel145/websites/apps}
APP=${1:-}
DETAILS=0
usage(){ cat <<'EOF'
Usage: system.architecture.audit.sh APP_NAME [--details]

Validates the Websites System Architecture Standard.
Read-only; does not modify files or configuration.
EOF
}
[ -n "$APP" ] || { usage; exit 2; }; shift || true
while [ "$#" -gt 0 ]; do case "$1" in --details) DETAILS=1;; -h|--help) usage; exit 0;; *) echo "ERROR: unknown option: $1" >&2; exit 2;; esac; shift; done
case "$APP" in *[!a-z0-9_]*|'') echo 'ERROR: app name must use lowercase letters, digits, and underscore only.' >&2; exit 2;; esac
[ -d "$APPS_ROOT" ] || { echo "ERROR: APPS_ROOT not found: $APPS_ROOT" >&2; exit 2; }
ROOT=$(cd "$APPS_ROOT" && pwd -P); APPDIR=$APPS_ROOT/$APP; [ -d "$APPDIR" ] || { echo "ERROR: app not found: $APPDIR" >&2; exit 2; }; REAL=$(cd "$APPDIR" && pwd -P)
case "$REAL/" in "$ROOT/"*) ;; *) echo 'ERROR: app path escapes apps root.' >&2; exit 2;; esac
TMP=${TMPDIR:-/tmp}/system_architecture_audit_$$; trap 'rm -f "$TMP".*' EXIT HUP INT TERM
pass=0; warn=0; fail=0; : > "$TMP.details"
emit(){ s=$1; id=$2; msg=$3; detail=${4:-}; printf '%-7s %-12s %s\n' "$s" "$id" "$msg"; case "$s" in PASS) pass=$((pass+1));; WARN) warn=$((warn+1));; FAIL) fail=$((fail+1));; esac; [ -n "$detail" ] && printf '[%s] %s\n%s\n' "$id" "$msg" "$detail" >> "$TMP.details"; }
printf 'System architecture audit\nApp: %s\nRoot: %s\n\n' "$APP" "$REAL"
if [ -f "$REAL/index.php" ] || [ -f "$REAL/$APP.index.php" ]; then emit PASS ARCH-001 'Registered or conventional public entry file exists.'; else emit WARN ARCH-001 'No index.php or appname.index.php found; register explicit entry policy.'; fi
for req in admin config css docs includes js pages public src storage tests vendor; do [ -d "$REAL/$req" ] && :; done
# Directory naming violations.
find "$REAL" -type d -print | while IFS= read -r p; do [ "$p" = "$REAL" ] && continue; n=${p##*/}; case "$n" in *[!a-z0-9_]*) printf '%s\n' "${p#"$REAL"/}" >> "$TMP.bad_dirs";; esac; done
if [ -s "$TMP.bad_dirs" ]; then emit WARN ARCH-002 'Directory naming policy violations found.' "Rule: directories use lowercase letters, digits, underscore only.\nMatches:\n$(cat "$TMP.bad_dirs")"; else emit PASS ARCH-002 'Directory names comply with lowercase/underscore policy.'; fi
# File naming violations.
find "$REAL" -type f -print | while IFS= read -r p; do n=${p##*/}; case "$n" in *.*) b=${n%.*};; *) b=$n;; esac; case "$b" in *[!a-z0-9]*) printf '%s\n' "${p#"$REAL"/}" >> "$TMP.bad_files";; esac; done
if [ -s "$TMP.bad_files" ]; then emit WARN ARCH-003 'File naming policy violations found.' "Rule: file base names use lowercase letters and digits only; no hyphen or underscore.\nMatches:\n$(cat "$TMP.bad_files")"; else emit PASS ARCH-003 'File base names comply with lowercase/no-separator policy.'; fi
# Global root ownership.
grep -RIn --include='*.php' -E 'class="[^"]*app-wrapper' "$REAL" 2>/dev/null > "$TMP.wrappers" || true
wc=$(wc -l < "$TMP.wrappers" | tr -d ' ')
if [ "$wc" -le 1 ]; then emit PASS ARCH-004 'At most one app-wrapper declaration found.'; else emit FAIL ARCH-004 "$wc app-wrapper declarations found; only primary template may own the global layout root." "Rule: one global layout root.\nMatches:\n$(cat "$TMP.wrappers")"; fi
if [ -d "$REAL/pages" ]; then grep -RIn --include='*.php' -E 'class="[^"]*(app-wrapper|app-main)' "$REAL/pages" 2>/dev/null > "$TMP.pages" || true; if [ -s "$TMP.pages" ]; then emit FAIL ARCH-005 'pages/ contains global layout markup.' "Rule: pages/ may contain local fragments only.\nMatches:\n$(cat "$TMP.pages")"; else emit PASS ARCH-005 'pages/ contains no app-wrapper or app-main markup.'; fi; fi
if [ -d "$REAL/includes" ]; then grep -RIn --include='*.php' -E 'class="[^"]*(app-wrapper|app-main)' "$REAL/includes" 2>/dev/null > "$TMP.includes" || true; if [ -s "$TMP.includes" ]; then emit FAIL ARCH-006 'includes/ contains global layout markup.' "Rule: includes/ may contain helpers/fragments only.\nMatches:\n$(cat "$TMP.includes")"; else emit PASS ARCH-006 'includes/ contains no app-wrapper or app-main markup.'; fi; fi
# Public/private-risk inventory.
for private in config includes pages src storage tests vendor old docs; do if [ -d "$REAL/$private" ]; then emit WARN "ARCH-$private" "$private/ exists and must be denied by Nginx/hosting policy unless explicitly public."; fi; done
if [ "$DETAILS" -eq 1 ] && [ -s "$TMP.details" ]; then printf '\nDetails\n-------\n'; cat "$TMP.details"; fi
printf '\nSummary: PASS=%s WARN=%s FAIL=%s\n' "$pass" "$warn" "$fail"
[ "$fail" -eq 0 ] || exit 1
