diff --git a/specs/009-inactive-sessions-purging/checklists/requirements.md b/specs/009-inactive-sessions-purging/checklists/requirements.md new file mode 100644 index 0000000..bd5a8d8 --- /dev/null +++ b/specs/009-inactive-sessions-purging/checklists/requirements.md @@ -0,0 +1,34 @@ +# Specification Quality Checklist: Inactive Sessions Purging, Form Data Persistence, and Centralized Snackbars + +**Purpose**: Validate specification completeness and quality before proceeding to planning +**Created**: четверг, 16 октября 2025 г. +**Feature**: [Link to spec.md](D:\Coding\unisono\specs\009-inactive-sessions-purging\spec.md) + +## Content Quality + +- [x] No implementation details (languages, frameworks, APIs) +- [x] Focused on user value and business needs +- [x] Written for non-technical stakeholders +- [x] All mandatory sections completed + +## Requirement Completeness + +- [x] No [NEEDS CLARIFICATION] markers remain +- [x] Requirements are testable and unambiguous +- [x] Success criteria are measurable +- [x] Success criteria are technology-agnostic (no implementation details) +- [x] All acceptance scenarios are defined +- [x] Edge cases are identified +- [x] Scope is clearly bounded +- [x] Dependencies and assumptions identified + +## Feature Readiness + +- [x] All functional requirements have clear acceptance criteria +- [x] User scenarios cover primary flows +- [x] Feature meets measurable outcomes defined in Success Criteria +- [x] No implementation details leak into specification + +## Notes + +- Items marked incomplete require spec updates before `/speckit.clarify` or `/speckit.plan` \ No newline at end of file diff --git a/specs/009-inactive-sessions-purging/contracts/openapi.yaml b/specs/009-inactive-sessions-purging/contracts/openapi.yaml new file mode 100644 index 0000000..96d938b --- /dev/null +++ b/specs/009-inactive-sessions-purging/contracts/openapi.yaml @@ -0,0 +1,67 @@ +openapi: 3.0.0 +info: + title: Session and Form Persistence API + version: 1.0.0 + +paths: + /api/session/form-data/{formId}: + get: + summary: Retrieve persisted form data for a specific form + parameters: + - in: path + name: formId + schema: + type: string + required: true + description: Identifier of the form + responses: + '200': + description: Successfully retrieved form data + content: + application/json: + schema: + type: object + additionalProperties: + type: string + '404': + description: Form data not found + delete: + summary: Clear persisted form data for a specific form + parameters: + - in: path + name: formId + schema: + type: string + required: true + description: Identifier of the form + responses: + '204': + description: Form data successfully cleared + '404': + description: Form data not found + +components: + schemas: + FormInput: + type: object + properties: + fieldId: + type: string + description: Identifier for the input field + value: + type: string + description: The current value of the input field + +# WebSocket API (conceptual, not directly in OpenAPI) +# The WebSocket API will handle real-time updates for form persistence. +# Messages from client to server: +# - type: "FORM_UPDATE" +# payload: +# formId: string +# fieldId: string +# value: string +# Messages from server to client: +# - type: "FORM_STATE_SYNC" +# payload: +# formId: string +# formState: object (map of fieldId to value) diff --git a/specs/009-inactive-sessions-purging/data-model.md b/specs/009-inactive-sessions-purging/data-model.md new file mode 100644 index 0000000..05e3218 --- /dev/null +++ b/specs/009-inactive-sessions-purging/data-model.md @@ -0,0 +1,23 @@ +# Data Model for Inactive Sessions Purging, Form Data Persistence, and Centralized Snackbars + +## Entities + +### Session +Represents a user's active interaction with the application. +- `sessionId`: Unique identifier (string) +- `userId`: Identifier of the associated user (string) +- `lastActivityTime`: Timestamp of the last user activity (Date/number) +- `persistedFormInputs`: A map or object storing form data (object, e.g., `{ formId: { fieldId: value, ... }, ... }`) + +### Form Input +Represents an individual input field within an unsubmitted form. +- `formId`: Identifier for the form (string) +- `fieldId`: Identifier for the input field (string) +- `value`: The current value of the input field (string or appropriate type) + +### Snackbar Notification +A transient, non-intrusive message displayed to the user. +- `message`: The text content of the notification (string) +- `type`: The type of notification (e.g., 'success', 'error', 'info') (string) +- `duration`: How long the notification should be displayed (number, milliseconds) +- `position`: Fixed to 'top-right' (string) diff --git a/specs/009-inactive-sessions-purging/plan.md b/specs/009-inactive-sessions-purging/plan.md new file mode 100644 index 0000000..2690330 --- /dev/null +++ b/specs/009-inactive-sessions-purging/plan.md @@ -0,0 +1,115 @@ +# Implementation Plan: Inactive Sessions Purging, Form Data Persistence, and Centralized Snackbars + +**Branch**: `009-inactive-sessions-purging` | **Date**: четверг, 16 октября 2025 г. | **Spec**: D:\\Coding\\unisono\\specs\\009-inactive-sessions-purging\\spec.md +**Input**: Feature specification from `/specs/009-inactive-sessions-purging/spec.md` + +**Note**: This template is filled in by the `/speckit.plan` command. See `.specify/templates/commands/plan.md` for the execution workflow. + +## Summary + +This feature implements automatic purging of inactive user sessions, real-time persistence of unsubmitted form input values using WebSockets, and consistent display of snackbar notifications in the top right corner of the UI. + +## Technical Context + +**Language/Version**: TypeScript 5.x, Node.js (LTS) +**Primary Dependencies**: React, Material-UI / MUI, WebSocket library +**Storage**: Ephemeral server-side session storage (in-memory/session store) +**Testing**: Jest, React Testing Library +**Target Platform**: Web (browser for frontend, Node.js server for backend) +**Project Type**: Web application (frontend + backend) +**Performance Goals**: Maintain performance and stability for up to 100 concurrent active user sessions +**Constraints**: Session inactivity timeout configurable via environment variable +**Scale/Scope**: Up to 100 concurrent active user sessions + +## Constitution Check + +*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.* + +### I. Defined Technology Stack: PASS +- Backend: Node.js - PASS +- Frontend: React - PASS +- UI Framework: Material Design 3 (Material-UI / MUI) - PASS +- Containerization: Docker - PASS + +### II. UI/UX Consistency: PASS +- All user interfaces MUST adhere to Material Design 3 principles and components. - PASS + +### III. Container-First Development: PASS +- All application services and development environments MUST run within Docker containers. - PASS + +### IV. Test-Driven Development (TDD): PASS +- New features and bug fixes MUST follow a Test-Driven Development approach. - PASS + +### V. API-First Design: PASS +- The backend and frontend are decoupled and communicate via a well-defined API contract. - PASS + + +## Project Structure + +### Documentation (this feature) + +``` +specs/[###-feature]/ +├── plan.md # This file (/speckit.plan command output) +├── research.md # Phase 0 output (/speckit.plan command) +├── data-model.md # Phase 1 output (/speckit.plan command) +├── quickstart.md # Phase 1 output (/speckit.plan command) +├── contracts/ # Phase 1 output (/speckit.plan command) +└── tasks.md # Phase 2 output (/speckit.tasks command - NOT created by /speckit.plan) +``` + +### Source Code (repository root) + + +``` +# [REMOVE IF UNUSED] Option 1: Single project (DEFAULT) +src/ +├── models/ +├── services/ +├── cli/ +└── lib/ + +tests/ +├── contract/ +├── integration/ +├── unit/ + +# [REMOVE IF UNUSED] Option 2: Web application (when "frontend" + "backend" detected) +backend/ +├── src/ +│ ├── models/ +│ ├── services/ +│ └── api/ +└── tests/ + +frontend/ +├── src/ +│ ├── components/ +│ ├── pages/ +│ └── services/ +└── tests/ + +# [REMOVE IF UNUSED] Option 3: Mobile + API (when "iOS/Android" detected) +api/ +└── [same as backend above] + +ios/ or android/ +└── [platform-specific structure: feature modules, UI flows, platform tests] +``` + +**Structure Decision**: [Document the selected structure and reference the real +directories captured above] + +## Complexity Tracking + +*Fill ONLY if Constitution Check has violations that must be justified* + +| Violation | Why Needed | Simpler Alternative Rejected Because | +|-----------|------------|-------------------------------------| +| [e.g., 4th project] | [current need] | [why 3 projects insufficient] | +| [e.g., Repository pattern] | [specific problem] | [why direct DB access insufficient] | diff --git a/specs/009-inactive-sessions-purging/quickstart.md b/specs/009-inactive-sessions-purging/quickstart.md new file mode 100644 index 0000000..95690d1 --- /dev/null +++ b/specs/009-inactive-sessions-purging/quickstart.md @@ -0,0 +1,42 @@ +# Quickstart Guide for Inactive Sessions Purging, Form Data Persistence, and Centralized Snackbars + +This guide provides instructions to quickly set up, configure, and verify the new features. + +## 1. Configure Session Inactivity Timeout + +The session inactivity timeout is controlled by an environment variable. To configure it: + +1. Locate your backend service's environment configuration (e.g., `.env` file, Docker Compose environment variables). +2. Add or modify the `SESSION_TIMEOUT_MINUTES` variable with your desired timeout in minutes. For example: + ``` + SESSION_TIMEOUT_MINUTES=5 + ``` + (This will set the timeout to 5 minutes.) +3. Restart your backend service for the changes to take effect. + +## 2. Verify Form Data Persistence + +To test the real-time form data persistence: + +1. Navigate to a page containing a form (e.g., a user profile edit page, a new entry form). +2. Start typing values into the form fields but DO NOT submit the form. +3. Open a new browser tab or window and navigate to a different page within the application, or simply close the current tab without submitting. +4. Return to the original form page (or reopen the tab). +5. **Expected Result**: The values you typed previously should be pre-filled in the form fields. +6. To verify clearing on submission: Fill out a form and submit it successfully. Then, try to return to that form page. The fields should now be empty. + +## 3. Observe Snackbar Display + +To verify the consistent display of snackbar notifications: + +1. Perform various actions within the application that trigger snackbar notifications (e.g., successful form submission, an error message, a confirmation). +2. **Expected Result**: All snackbar notifications should consistently appear in the top right corner of the screen, aligned with the page heading. +3. Trigger multiple snackbars in quick succession to observe their stacking/queueing behavior. + +## 4. Test WebSocket Failure Indication + +To test the visual indication for WebSocket communication failure: + +1. Navigate to a page with a form that uses real-time persistence. +2. While typing in the form, intentionally disconnect the WebSocket connection (e.g., by stopping the backend service or using browser developer tools to block WebSocket traffic). +3. **Expected Result**: A subtle, non-intrusive visual indicator should appear near the form, informing the user that real-time persistence is not active. diff --git a/specs/009-inactive-sessions-purging/research.md b/specs/009-inactive-sessions-purging/research.md new file mode 100644 index 0000000..9fc240b --- /dev/null +++ b/specs/009-inactive-sessions-purging/research.md @@ -0,0 +1,3 @@ +# Research for Inactive Sessions Purging, Form Data Persistence, and Centralized Snackbars + +No specific research tasks were identified for this feature during the planning phase, as all technical context was sufficiently clear or clarified during the specification phase. \ No newline at end of file diff --git a/specs/009-inactive-sessions-purging/spec.md b/specs/009-inactive-sessions-purging/spec.md new file mode 100644 index 0000000..a339bd6 --- /dev/null +++ b/specs/009-inactive-sessions-purging/spec.md @@ -0,0 +1,104 @@ +# Feature Specification: Inactive Sessions Purging, Form Data Persistence, and Centralized Snackbars + +**Feature Branch**: `009-inactive-sessions-purging` +**Created**: четверг, 16 октября 2025 г. +**Status**: Draft +**Input**: User description: "Inactive sessions purging. 1. The inactive session must be purged on timeout that I state as ENV variable in minutes. 2. Prevent user from losing input values when leaving a page with filled unsumbitted form: save them to session via websockets immidiately on change. 3. All the snackbars must be displayed in one place - top right corner, aligned with the page heading." + +## User Scenarios & Testing *(mandatory)* + +### User Story 1 - System purges inactive sessions (Priority: P1) + +As a system administrator, I want inactive user sessions to be automatically purged after a configurable timeout, so that system resources are optimized and security risks from stale sessions are minimized. + +**Why this priority**: This directly addresses system resource management and security, which are critical for application stability and integrity. + +**Independent Test**: The system can be tested by setting a short timeout, initiating a session, letting it become inactive, and verifying that the session is terminated and resources are freed. + +**Acceptance Scenarios**: + +1. **Given** a session timeout is configured via an environment variable (e.g., `SESSION_TIMEOUT_MINUTES=5`), **When** a user session remains inactive for longer than the configured timeout, **Then** the system automatically purges the inactive session. +2. **Given** an active user session, **When** the user performs an action within the configured timeout, **Then** the session remains active and is not purged. + +--- + +### User Story 2 - User input values are persisted across navigation (Priority: P1) + +As a user, I want my unsubmitted form input values to be automatically saved to my session as I type, so that I don't lose my work if I accidentally navigate away from a page or my browser crashes. + +**Why this priority**: This significantly improves user experience by preventing data loss, which is a common frustration point. + +**Independent Test**: A user can fill out a form, navigate away, and then return to the form to verify that the input values are still present. + +**Acceptance Scenarios**: + +1. **Given** a user is filling out a form with input fields, **When** the user types into an input field, **Then** the value of that input field is immediately saved to the user's session via WebSocket. +2. **Given** a user has entered values into an unsubmitted form and then navigates to another page, **When** the user returns to the original form page, **Then** the previously entered values are pre-filled in the form fields. +3. **Given** a user has entered values into an unsubmitted form, **When** the user explicitly submits the form, **Then** the saved session data for that form is cleared. + +--- + +### User Story 3 - Snackbars are consistently displayed (Priority: P2) + +As a user, I want all system notifications (snackbars) to appear in a consistent location (top right corner, aligned with page heading), so that I can easily locate and dismiss them without disrupting my workflow. + +**Why this priority**: This enhances user experience by providing a predictable and non-intrusive notification system. + +**Independent Test**: Various system actions that trigger snackbars can be performed, and the display location and alignment of each snackbar can be visually verified. + +**Acceptance Scenarios**: + +1. **Given** any system action triggers a snackbar notification, **When** the snackbar is displayed, **Then** it appears in the top right corner of the screen. +2. **Given** a snackbar is displayed in the top right corner, **When** the page heading is present, **Then** the snackbar is visually aligned with the page heading. +3. **Given** multiple snackbars are triggered in quick succession, **When** they are displayed, **Then** they stack or queue in the top right corner without overlapping other critical UI elements. + +--- + +### Edge Cases + +- What happens if the WebSocket connection is interrupted while a user is typing in a form? (Data loss for unsaved changes) +- How does the system handle a very short session timeout, potentially purging active users? (Should be prevented by activity checks) +- What if a user has multiple forms open simultaneously? (Each form's data should be saved independently) +- What if a snackbar message is very long? (Should wrap or truncate gracefully) + +## Requirements *(mandatory)* + +### Functional Requirements + +- **FR-001**: The system MUST automatically purge user sessions that have been inactive for a configurable duration. +- **FR-002**: The session inactivity timeout MUST be configurable via an environment variable, specified in minutes. +- **FR-003**: The system MUST save unsubmitted form input values to the user's session immediately upon change. +- **FR-004**: Form input value persistence MUST utilize WebSocket communication for real-time updates. +- **FR-005**: The system MUST clear persisted form input values from the session upon successful form submission. +- **FR-006**: All system-generated snackbar notifications MUST be displayed in the top right corner of the user interface. +- **FR-007**: Snackbar notifications MUST be visually aligned with the main page heading when present. +- **FR-008**: Persisted form input values MUST be automatically cleared from the session when the user's session ends. +- **FR-009**: Persisted form input values MUST rely on existing session security for protection, without additional encryption or masking. +- **FR-010**: The system MUST provide a subtle, non-intrusive visual indicator near the form if WebSocket communication for form data persistence fails. +- **FR-011**: Concurrent modifications to the same form field from different browser tabs/windows by the same user MUST be resolved using a "last write wins" strategy. + +### Key Entities + +- **Session**: Represents a user's active interaction with the application, containing user-specific data including persisted form inputs. +- **Form Input**: Individual data fields within an unsubmitted form that require persistence. +- **Snackbar Notification**: A transient, non-intrusive message displayed to the user. + +## Clarifications + +### Session 2025-10-16 + +- Q: When should persisted form input data be automatically cleared from the session if the form is never submitted? → A: When the user's session ends +- Q: What level of data protection (e.g., encryption) is required for the persisted form input values stored in the session? → A: No specific protection beyond session security +- Q: What is the expected maximum number of concurrent active user sessions? → A: 100 +- Q: How should the system visually indicate to the user if WebSocket communication for form data persistence fails? → A: A subtle, non-intrusive indicator near the form +- Q: How should concurrent modifications to the same form field from different browser tabs/windows by the same user be handled? → A: Last write wins + +## Success Criteria *(mandatory)* + +### Measurable Outcomes + +- **SC-001**: System resource utilization (CPU, memory) for inactive sessions is reduced by at least 20% within 24 hours of deploying the session purging feature. +- **SC-002**: The rate of user-reported data loss due to accidental navigation or browser crashes on unsubmitted forms decreases by 90% within one month of deployment. +- **SC-003**: 100% of snackbar notifications appear in the top right corner of the UI, aligned with the page heading, across all supported browsers and devices. +- **SC-004**: The average time a user spends re-entering lost form data is reduced to effectively zero. +- **SC-005**: The system MUST maintain performance and stability for up to 100 concurrent active user sessions. diff --git a/specs/009-inactive-sessions-purging/tasks.md b/specs/009-inactive-sessions-purging/tasks.md new file mode 100644 index 0000000..8444810 --- /dev/null +++ b/specs/009-inactive-sessions-purging/tasks.md @@ -0,0 +1,66 @@ +# Tasks for Inactive Sessions Purging, Form Data Persistence, and Centralized Snackbars + +**Branch**: `009-inactive-sessions-purging` | **Date**: четверг, 16 октября 2025 г. + +## Phase 1: Setup + +- [ ] T001 Ensure `SESSION_TIMEOUT_MINUTES` environment variable is configurable in backend/Dockerfile and backend/.env + +## Phase 2: Foundational + +- [ ] T002 Implement core session management logic for tracking `lastActivityTime` in backend/src/services/SessionService.ts +- [ ] T003 Implement ephemeral server-side session storage in backend/src/services/SessionService.ts +- [ ] T004 Set up WebSocket server in backend/src/ws/index.ts +- [ ] T005 Set up WebSocket client in frontend/src/services/websocket.ts + +## Phase 3: User Story 1 - System purges inactive sessions (Priority: P1) + +- [ ] T006 [US1] Implement session inactivity check based on `lastActivityTime` and `SESSION_TIMEOUT_MINUTES` in backend/src/services/SessionService.ts +- [ ] T007 [US1] Implement session purging mechanism in backend/src/services/SessionService.ts +- [ ] T008 [US1] Add unit/integration tests for session purging in backend/tests/sessions.test.ts + +## Phase 4: User Story 2 - User input values are persisted across navigation (Priority: P1) + +- [ ] T009 [P] [US2] Implement WebSocket handler for `FORM_UPDATE` to save form data to session in backend/src/ws/index.ts +- [ ] T010 [P] [US2] Implement WebSocket handler for `FORM_STATE_SYNC` to send form data to client in backend/src/ws/index.ts +- [ ] T011 [P] [US2] Implement HTTP GET endpoint for `/api/session/form-data/{formId}` in backend/src/api/sessions.ts +- [ ] T012 [P] [US2] Implement HTTP DELETE endpoint for `/api/session/form-data/{formId}` in backend/src/api/sessions.ts +- [ ] T013 [P] [US2] Implement form component to send `FORM_UPDATE` via WebSocket on input change in frontend/src/components/DesireForm.tsx +- [ ] T014 [P] [US2] Implement form component to receive `FORM_STATE_SYNC` and pre-fill form fields in frontend/src/components/DesireForm.tsx +- [ ] T015 [P] [US2] Implement logic to clear persisted form data on successful form submission in frontend/src/components/DesireForm.tsx +- [ ] T016 [P] [US2] Implement subtle, non-intrusive visual indicator for WebSocket failure in frontend/src/components/ErrorState.tsx or similar +- [ ] T017 [US2] Add unit/integration tests for form data persistence in frontend/tests/DesireForm.test.tsx and backend/tests/sessions.test.ts + +## Phase 5: User Story 3 - Snackbars are consistently displayed (Priority: P2) + +- [ ] T018 [P] [US3] Implement a centralized snackbar component in frontend/src/components/SnackbarDisplay.tsx (new file) +- [ ] T019 [P] [US3] Ensure snackbars appear in the top right corner, aligned with page heading in frontend/src/components/SnackbarDisplay.tsx +- [ ] T020 [P] [US3] Implement stacking/queueing behavior for multiple snackbars in frontend/src/components/SnackbarDisplay.tsx +- [ ] T021 [US3] Add unit/integration tests for snackbar display in frontend/tests/SnackbarDisplay.test.tsx (new file) + +## Phase 6: Polish & Cross-Cutting Concerns + +- [ ] T022 Review and refine error handling for all features across backend and frontend +- [ ] T023 Update documentation (e.g., README, API docs) in README.md and specs/009-inactive-sessions-purging/plan.md +- [ ] T024 Performance testing and optimization for session purging and form persistence + +## Dependencies + +- Phase 1 (Setup) -> Phase 2 (Foundational) +- Phase 2 (Foundational) -> Phase 3 (US1) +- Phase 2 (Foundational) -> Phase 4 (US2) +- Phase 2 (Foundational) -> Phase 5 (US3) +- Phase 3, 4, 5 -> Phase 6 (Polish) + +## Parallel Execution Examples + +- **User Story 2 (Form Persistence)**: Tasks T009-T016 can be worked on in parallel by different developers, as they cover distinct backend and frontend components. For example, one developer can work on backend WebSocket handlers (T009, T010) while another works on frontend form components (T013, T014). +- **User Story 3 (Snackbars)**: Tasks T018-T020 can be developed independently of other features once the foundational setup is complete. + +## Implementation Strategy + +This feature will be implemented using an MVP-first approach, delivering value incrementally: + +1. **MVP**: Focus on User Story 1 (System purges inactive sessions) and User Story 3 (Snackbars are consistently displayed). This provides core system maintenance and a better user notification experience. +2. **Next Increment**: Implement User Story 2 (User input values are persisted across navigation), which significantly enhances user experience. +3. **Final Phase**: Address polish and cross-cutting concerns, including comprehensive error handling, documentation, and performance optimization.