Skip to content

Sessions survive deploys, 12-hour idle timeout (#194) - #222

Merged
aleksejs1 merged 2 commits into
mainfrom
feat/session-idle-timeout-194
Oct 3, 2026
Merged

aleksejs1 merged 2 commits into
mainfrom
feat/session-idle-timeout-194

Conversation

@aleksejs1

Copy link
Copy Markdown
Owner

Closes #194, part of #213.

What changes

  • Sessions survive a redeploy. Session files move from PHP's default (the container's own tmp, lost on every recreate) to var/sessions, inside the /app/var volume every topology mounts. Not var/cache, which the deploy step deletes.
  • 12-hour idle timeout. AuthSession stamps last_active_at on login and on every authenticated request, and ends a login idle for more than IDLE_TIMEOUT_SECONDS. A logged-in session with no stamp counts as idle.
  • An idle logout drops the login, not the session. The check runs in CompanyFilterListener, before the CSRF listener; invalidating the session there made an idle tab's first write fail with 403 "invalid CSRF token", which the client doesn't treat as a logout. Found in review round 1.
  • gc_maxlifetime is 48 hours, disk cleanup only. cookie_lifetime stays 0.

No migration, no frontend change.

Verification

  • make verify-pr-ready passes (808 backend tests, lint, mutation).
  • New tests with a mocked clock: rejected past the timeout and stays rejected, exactly 12h still valid, each request restarts the window, the live-state poll alone keeps a session alive, re-login after an idle logout, and 401 (not 403) for a write sent with the CSRF token an idle tab still holds.
  • Dev stack: a real session returned 200 from /api/me before and after docker compose up -d --force-recreate; with last_active_at set 12h 5s back it returned 401.
  • Two code-review rounds; the second came back with nothing that held up.

Not done

  • Production check from the issue's first acceptance criterion: only possible after the deploy.
  • The deploy that first ships this signs everyone out one more time (old sessions are in the old container's tmp).
  • The live-update poll pauses in a hidden tab, so a background tab idle for 12 hours is logged out. Not changed here.

See docs/decisions/2026-10-03-sessions-survive-deploys-idle-timeout.md.

🤖 Generated with Claude Code

aleksejs1 and others added 2 commits October 3, 2026 19:38
Session files move from PHP's default (the container's tmp, lost on every
recreate) to var/sessions, inside the volume every topology mounts.

AuthSession stamps last_active_at on login and on every authenticated
request, and ends a login idle for more than 12 hours. Only the login is
dropped, not the session: the check runs before the CSRF listener, and
invalidating there would turn an idle tab's first write into a 403 the
client doesn't treat as a logout.

gc_maxlifetime is 48 hours, for disk cleanup only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CI's mutation job flagged two escaped mutants in the idle branch. The
filter-disable call there had no reachable effect (CompanyFilterListener
resets the filter per request) and is dropped; the timestamp removal now
has a unit test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@aleksejs1
aleksejs1 merged commit e77f8b6 into main Oct 3, 2026
6 checks passed
@aleksejs1
aleksejs1 deleted the feat/session-idle-timeout-194 branch October 3, 2026 16:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Sessions: survive deploys and enforce a 12-hour idle timeout

1 participant