فهرست منبع

Build: make published host port configurable via HTTP_PORT (default 8080)

docker-compose.yml's host port was hard-coded to 8088, forcing operators
to edit the file (and remember to keep it out of merges) to publish on a
different port. Replaced with `${HTTP_PORT:-8080}:80` so the host port
is set in .env alongside APP_BASE_URL. Default moves from 8088 → 8080
so the compose default and APP_BASE_URL default finally agree.

Docs: SPEC §8 env block, README quick-setup, admin-manual §3.2 (no more
mismatch caveat) + new §3.3 "Host port" + §4.1 / §4.4 / §4.5 updates;
old §3.3-§3.7 renumbered to §3.4-§3.8 with two cross-refs fixed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ClaudePriv@chiappa.zhdk.ch 4 ساعت پیش
والد
کامیت
4354266825
5فایلهای تغییر یافته به همراه46 افزوده شده و 24 حذف شده
  1. 5 0
      .env.example
  2. 3 2
      README.md
  3. 2 1
      SPEC.md
  4. 32 20
      doc/admin-manual.md
  5. 4 1
      docker-compose.yml

+ 5 - 0
.env.example

@@ -17,6 +17,11 @@ OIDC_ENABLED=true
 # Used to build the OIDC redirect URI {APP_BASE_URL}/auth/callback
 APP_BASE_URL=http://localhost:8080
 
+# Host port the docker-compose stack publishes (container side is fixed at
+# Apache:80). Pick any free port on the host. Keep APP_BASE_URL in sync —
+# the OIDC redirect URI registered in Entra must match exactly.
+HTTP_PORT=8080
+
 # Path to the SQLite database file inside the container. Leave as-is unless
 # you have a specific reason to change it. The parent dir is the mounted
 # volume (/var/www/data).

+ 3 - 2
README.md

@@ -51,12 +51,13 @@ cp .env.example .env
 #    ENTRA_CLIENT_SECRET instead (or in addition).
 chmod 600 .env
 
-# 4. Build and start the container (compose maps host port 8088 → container 80)
+# 4. Build and start the container (compose maps host port HTTP_PORT
+#    from .env → container 80; default 8080, change in .env to taste)
 docker compose up -d --build
 #    Equivalent shortcut once `make` is installed: `make prod`
 
 # 5. Open the app
-xdg-open http://localhost:8088   # or just visit it in a browser
+xdg-open http://localhost:8080   # substitute your HTTP_PORT if changed
 ```
 
 If you signed in via the local-admin fallback you are immediately the

+ 2 - 1
SPEC.md

@@ -326,6 +326,7 @@ ENTRA_TENANT_ID=
 ENTRA_CLIENT_ID=
 ENTRA_CLIENT_SECRET=
 APP_BASE_URL=http://localhost:8080
+HTTP_PORT=8080              # host port docker-compose publishes (→ container :80)
 DB_PATH=/var/www/data/app.sqlite
 SESSION_PATH=/var/www/data/sessions
 APP_ENV=production
@@ -1710,7 +1711,7 @@ cp .env.example .env
 # Fill Entra vars, OR set LOCAL_ADMIN_EMAIL + LOCAL_ADMIN_PASSWORD_HASH
 # (see README's Quick setup for the password_hash() one-liner)
 make prod   # or `docker compose up --build`
-# open http://localhost:8088
+# open http://localhost:8080
 ```
 
 The SQLite file lives at `./data/app.sqlite` on the host; nuking it resets

+ 32 - 20
doc/admin-manual.md

@@ -83,11 +83,22 @@ APP_BASE_URL=https://sprint.example.com
 The base URL the application is reachable at, **without** trailing slash.
 This is used to construct the OIDC redirect URI and must match exactly
 what is registered in Entra. For local testing the default
-`http://localhost:8080` is fine — but the compose file ships the app on
-port `8088`, so use `http://localhost:8088` if you have not edited
-`docker-compose.yml`.
+`http://localhost:8080` matches the default `HTTP_PORT` (see §3.3), so
+no edits are needed unless you have changed one or the other.
 
-### 3.3 Database and session storage paths
+### 3.3 Host port
+
+```
+HTTP_PORT=8080
+```
+
+The host port `docker-compose.yml` publishes for the app (container side
+is fixed at Apache port 80). Default `8080`. Pick any free host port; you
+do not need to edit `docker-compose.yml`. Whatever you set here must
+match the port in `APP_BASE_URL` and the redirect URI registered in
+Entra.
+
+### 3.4 Database and session storage paths
 
 ```
 DB_PATH=/var/www/data/app.sqlite
@@ -98,7 +109,7 @@ Leave the defaults unless you are also remapping the volume. The parent
 directory `/var/www/data` is the volume mount point inside the container
 and corresponds to `./data/` on the host.
 
-### 3.4 Environment mode
+### 3.5 Environment mode
 
 ```
 APP_ENV=production
@@ -107,7 +118,7 @@ APP_ENV=production
 `production` silences verbose PHP errors. Any other value (e.g. `dev`)
 turns them on — useful when troubleshooting in a non-public install.
 
-### 3.5 Reverse proxy and HTTPS
+### 3.6 Reverse proxy and HTTPS
 
 ```
 TRUSTED_PROXIES=10.0.0.0/8,192.168.0.0/16
@@ -164,7 +175,7 @@ location / {
 }
 ```
 
-### 3.6 Nominating the first administrator (OIDC)
+### 3.7 Nominating the first administrator (OIDC)
 
 Historically the first user to complete sign-in via *any* path was promoted
 to administrator. On a public-facing first deploy that is a land-grab risk
@@ -190,7 +201,7 @@ Either / both / neither may be set:
 - **Both set**: the signing user is promoted on a match against either field.
 - **One set**: only that channel matters.
 - **Neither set**: the OIDC path will *never* auto-promote. In that case
-  bootstrap the first administrator via the local-admin fallback (§3.7) or
+  bootstrap the first administrator via the local-admin fallback (§3.8) or
   by setting `users.is_admin = 1` directly in `app.sqlite`.
 
 Auto-promotion additionally requires that no administrator already exists
@@ -198,11 +209,11 @@ Auto-promotion additionally requires that no administrator already exists
 promotions go through the **Users** page (§5.1). The promotion is recorded
 in the audit log as `BOOTSTRAP_ADMIN` with `via=oidc`.
 
-The local-admin fallback (§3.7) is itself an explicit env-bootstrap and
+The local-admin fallback (§3.8) is itself an explicit env-bootstrap and
 does not require the variables above — its `BOOTSTRAP_ADMIN` audit row is
 tagged `via=local`.
 
-### 3.7 Local admin fallback (optional)
+### 3.8 Local admin fallback (optional)
 
 ```
 LOCAL_ADMIN_EMAIL=admin@example.com
@@ -293,8 +304,8 @@ What happens:
    apply every file in `migrations/` BEFORE Apache binds the port. If
    a migration fails, the container exits non-zero and Apache never
    starts — check `docker compose logs` for the migration's stderr.
-3. Apache then starts on port 80, exposed on the host as port
-   **8088** (see `docker-compose.yml`).
+3. Apache then starts on port 80, exposed on the host as the port set
+   by `HTTP_PORT` in `.env` (default **8080** — see §3.3 / §4.5).
 
 The web request path itself never applies SQL — it only checks that
 `schema_version` matches the on-disk migration set and refuses to serve
@@ -302,7 +313,7 @@ The web request path itself never applies SQL — it only checks that
 A forgotten deploy step therefore produces a loud, fast-failing 503
 instead of silent stale-schema serving (R01-N22).
 
-Open `http://<host>:8088`. If you used the local-admin fallback, sign
+Open `http://<host>:8080`. If you used the local-admin fallback, sign
 in at `/auth/local`. Otherwise click the Entra sign-in CTA on `/`.
 
 ### 4.2 Running detached (recommended for production)
@@ -353,20 +364,21 @@ returns `200 OK` with a small JSON body. Use it from a load balancer or
 uptime monitor:
 
 ```bash
-curl -fsS http://<host>:8088/healthz
+curl -fsS http://<host>:8080/healthz
 ```
 
 ### 4.5 Changing the host port
 
-Edit the `ports` line in `docker-compose.yml`:
+Set `HTTP_PORT` in `.env` to any free port on the host:
 
-```yaml
-ports:
-  - "8088:80"
+```
+HTTP_PORT=9090
 ```
 
-Change `8088` to any free port on the host. After editing, `docker
-compose up -d` is enough — no rebuild required. Update `APP_BASE_URL`
+`docker-compose.yml` substitutes the variable into the `ports` mapping
+(`"${HTTP_PORT:-8080}:80"`); the default `8080` applies when the
+variable is unset. After editing, `docker compose up -d` re-creates the
+container with the new port — no rebuild required. Update `APP_BASE_URL`
 in `.env` and the redirect URI in Entra to match.
 
 ---

+ 4 - 1
docker-compose.yml

@@ -4,7 +4,10 @@ services:
       context: .
       target: runtime
     ports:
-      - "8088:80"
+      # Host port comes from .env (HTTP_PORT). Default 8080 matches the
+      # APP_BASE_URL default in .env.example. Container side is fixed at
+      # 80 (Apache). Keep APP_BASE_URL in sync if you change it.
+      - "${HTTP_PORT:-8080}:80"
     env_file: .env
     volumes:
       - ./data:/var/www/data