session start works
This commit is contained in:
34
specs/001-people-tend-to/checklists/requirements.md
Normal file
34
specs/001-people-tend-to/checklists/requirements.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# Specification Quality Checklist: Anonymous Desire Aggregator
|
||||
|
||||
**Purpose**: Validate specification completeness and quality before proceeding to planning
|
||||
**Created**: 2025-10-09
|
||||
**Feature**: [../spec.md](../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
|
||||
|
||||
- All items have been validated and passed. The specification is ready for the next phase.
|
||||
90
specs/001-people-tend-to/contracts/openapi.yaml
Normal file
90
specs/001-people-tend-to/contracts/openapi.yaml
Normal file
@@ -0,0 +1,90 @@
|
||||
openapi: 3.0.0
|
||||
info:
|
||||
title: Anonymous Desire Aggregator API
|
||||
version: 2.0.0
|
||||
description: API for facilitating real-time, private, anonymous decision-making sessions.
|
||||
|
||||
paths:
|
||||
/sessions:
|
||||
post:
|
||||
summary: Get a new unique session ID
|
||||
operationId: createSession
|
||||
responses:
|
||||
'201':
|
||||
description: Session ID created successfully.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
sessionId:
|
||||
type: string
|
||||
format: uuid
|
||||
description: The unique ID for the session. Clients will use this to join the WebSocket channel.
|
||||
|
||||
/sessions/{sessionId}/analyze:
|
||||
post:
|
||||
summary: Trigger the semantic analysis for a session
|
||||
operationId: triggerAnalysis
|
||||
parameters:
|
||||
- name: sessionId
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
allDesires:
|
||||
type: array
|
||||
description: A complete list of all desire sets from all participants, collected by the client.
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
wants:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
accepts:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
noGoes:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
responses:
|
||||
'202':
|
||||
description: Analysis has been successfully triggered. Results will be broadcast over the WebSocket.
|
||||
'404':
|
||||
description: Session not found.
|
||||
|
||||
# WebSocket Protocol (/sessions/{sessionId})
|
||||
# The primary communication for this application is via WebSockets. The backend acts as a message relay and orchestrator.
|
||||
#
|
||||
# Client-to-Server Messages:
|
||||
#
|
||||
# - type: 'SHARE_STATE'
|
||||
# payload: { session: Session } # Client sends its entire session object to sync with others.
|
||||
#
|
||||
# - type: 'SUBMIT_DESIRES'
|
||||
# payload: { desireSet: DesireSet } # A single user submits their desires.
|
||||
#
|
||||
# Server-to-Client Messages:
|
||||
#
|
||||
# - type: 'USER_JOINED'
|
||||
# payload: { participantId: string }
|
||||
#
|
||||
# - type: 'STATE_UPDATE'
|
||||
# payload: { session: Session } # Broadcasts the latest session state to all clients.
|
||||
#
|
||||
# - type: 'ANALYSIS_COMPLETE'
|
||||
# payload: { decision: Decision } # Broadcasts the final results.
|
||||
#
|
||||
# - type: 'SESSION_LOCKED'
|
||||
# payload: {}
|
||||
71
specs/001-people-tend-to/data-model.md
Normal file
71
specs/001-people-tend-to/data-model.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# Data Model
|
||||
|
||||
**Feature**: Anonymous Desire Aggregator
|
||||
**Date**: 2025-10-09
|
||||
|
||||
This document defines the key data entities for the feature, with notes on where the state is managed.
|
||||
|
||||
---
|
||||
|
||||
### 1. Session
|
||||
|
||||
Represents a single decision-making event. **Note**: This object lives in the browser's Local Storage and is synchronized between clients via WebSocket messages.
|
||||
|
||||
| Attribute | Type | Description | Notes |
|
||||
|---|---|---|---|
|
||||
| `sessionId` | String | Unique identifier for the session. | The only piece of session data the backend is aware of. |
|
||||
| `topic` | String | The subject of the session. | Set by the creator client. |
|
||||
| `participantCount` | Integer | The number of expected participants. | Set by the creator client. |
|
||||
| `status` | Enum | The current state of the session. | `WAITING`, `ANALYZING`, `COMPLETE`, `LOCKED`. |
|
||||
| `participants` | Array\[Participant] | List of participants in the session. | Managed by clients. |
|
||||
| `desireSets` | Array\[DesireSet] | List of all desire sets submitted by participants. | Managed by clients. |
|
||||
| `decision` | Decision | The final calculated result. | Received from backend and stored by clients. |
|
||||
|
||||
---
|
||||
|
||||
### 2. Participant
|
||||
|
||||
Represents an anonymous user in the session. **Note**: Lives within the `Session` object in Local Storage.
|
||||
|
||||
| Attribute | Type | Description |
|
||||
|---|---|---|
|
||||
| `participantId` | String | Unique identifier for the participant (e.g., a random ID generated by the client). |
|
||||
| `isCreator` | Boolean | Flag to identify the participant who initiated the session. |
|
||||
| `hasSubmitted` | Boolean | Flag to indicate if the participant has submitted their desires. |
|
||||
|
||||
---
|
||||
|
||||
### 3. Desire Set
|
||||
|
||||
Represents the raw text input from a single participant. **Note**: Lives within the `Session` object in Local Storage.
|
||||
|
||||
| Attribute | Type | Description |
|
||||
|---|---|---|
|
||||
| `participantId` | String | The ID of the participant who submitted this set. |
|
||||
| `wants` | Array\[String] | List of raw text desires the user wants. |
|
||||
| `accepts` | Array\[String] | List of raw text desires the user accepts. |
|
||||
| `noGoes` | Array\[String] | List of raw text desires the user does not want. |
|
||||
|
||||
---
|
||||
|
||||
### 4. Semantic Desire
|
||||
|
||||
Represents a unique conceptual desire identified by the LLM analysis. **Note**: This is a read-only, transient data structure. It exists in the `Decision` object.
|
||||
|
||||
| Attribute | Type | Description |
|
||||
|---|---|---|
|
||||
| `title` | String | The canonical name for the desire group. |
|
||||
| `rawInputs` | Array\[String] | The list of original user text inputs that were grouped into this desire. |
|
||||
|
||||
---
|
||||
|
||||
### 5. Decision
|
||||
|
||||
Represents the final, categorized output of the analysis. **Note**: Lives within the `Session` object in Local Storage.
|
||||
|
||||
| Attribute | Type | Description |
|
||||
|---|---|---|
|
||||
| `goTos` | Array\[Semantic Desire] | Desires everyone wants. |
|
||||
| `alsoGoods` | Array\[Semantic Desire] | Desires some want and others accept. |
|
||||
| `considerables` | Array\[Semantic Desire] | Other desires that were wanted or accepted. |
|
||||
| `noGoes` | Array\[Semantic Desire] | Desires that at least one person does not want. |
|
||||
80
specs/001-people-tend-to/plan.md
Normal file
80
specs/001-people-tend-to/plan.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# Implementation Plan: Anonymous Desire Aggregator
|
||||
|
||||
**Branch**: `001-people-tend-to` | **Date**: 2025-10-09 | **Spec**: [spec.md](spec.md)
|
||||
**Input**: Feature specification from `/specs/001-people-tend-to/spec.md`
|
||||
|
||||
## Summary
|
||||
|
||||
This plan outlines the implementation of a highly private, real-time web application for anonymous group decision-making. The architecture is client-centric, using browser Local Storage for session state, synchronized between participants via a Node.js WebSocket server. Per the user's directive, the backend will integrate with a cloud-based LLM, **Google's Gemini 2.0 Flash**, to meet the requirement for a powerful, free-to-use, and limitless model for semantic analysis. The application will be containerized with Docker and fully adheres to the project constitution.
|
||||
|
||||
## Technical Context
|
||||
|
||||
**Language/Version**: Node.js (LTS), TypeScript 5.x
|
||||
**Primary Dependencies**:
|
||||
- **Backend**: Express.js, `ws` (for WebSockets), `@google/generative-ai`
|
||||
- **Frontend**: React 18, Material-UI (MUI) v5+
|
||||
**Storage**: Browser Local Storage (Primary store for session state). The backend is stateless.
|
||||
**Testing**: Jest
|
||||
**Target Platform**: Docker Containers
|
||||
**Project Type**: Web Application (Backend + Frontend)
|
||||
**Privacy Mandate**: The backend MUST NOT log or persist the content of user desires. All session data on the backend is ephemeral and exists only in memory during the transient call to the LLM API.
|
||||
**Performance Goals**: As per spec SC-001, SC-003.
|
||||
**Constraints**: Relies on the availability and performance of the external "Gemini 2.0 Flash" API.
|
||||
|
||||
## Constitution Check
|
||||
|
||||
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
|
||||
|
||||
- **I. Defined Technology Stack**: **PASS**
|
||||
- **II. UI/UX Consistency**: **PASS**
|
||||
- **III. Container-First Development**: **PASS**
|
||||
- **IV. Test-Driven Development (TDD)**: **PASS**
|
||||
- **V. API-First Design**: **PASS**
|
||||
|
||||
**Result**: All constitutional gates passed.
|
||||
|
||||
## Project Structure
|
||||
|
||||
### Documentation (this feature)
|
||||
|
||||
```
|
||||
specs/001-people-tend-to/
|
||||
├── spec.md # Feature specification
|
||||
├── plan.md # This file
|
||||
├── research.md # Phase 0 output
|
||||
├── data-model.md # Phase 1 output
|
||||
├── quickstart.md # Phase 1 output
|
||||
├── contracts/ # Phase 1 output
|
||||
│ └── openapi.yaml
|
||||
└── tasks.md # Phase 2 output (via /speckit.tasks)
|
||||
```
|
||||
|
||||
### Source Code (repository root)
|
||||
|
||||
```
|
||||
backend/
|
||||
├── src/
|
||||
│ ├── services/ # LLM integration service
|
||||
│ ├── ws/ # WebSocket server logic for message relay
|
||||
│ └── index.ts # App entrypoint
|
||||
├── tests/
|
||||
└── Dockerfile
|
||||
|
||||
frontend/
|
||||
├── src/
|
||||
│ ├── components/
|
||||
│ ├── pages/
|
||||
│ ├── services/ # WebSocket communication service
|
||||
│ ├── hooks/ # Custom hooks for managing local storage state
|
||||
│ └── App.tsx # Main React component
|
||||
├── tests/
|
||||
└── Dockerfile
|
||||
|
||||
docker-compose.yaml # To orchestrate both services
|
||||
```
|
||||
|
||||
**Structure Decision**: A "Web application" structure with a separate frontend and backend is the ideal choice. The backend is a lightweight Node.js service responsible for WebSocket message relay and orchestrating calls to the external LLM API.
|
||||
|
||||
## Complexity Tracking
|
||||
|
||||
*No constitutional violations were identified. This section is not required.*
|
||||
53
specs/001-people-tend-to/quickstart.md
Normal file
53
specs/001-people-tend-to/quickstart.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# Quickstart Guide
|
||||
|
||||
**Feature**: Anonymous Desire Aggregator
|
||||
**Date**: 2025-10-09
|
||||
|
||||
This guide provides instructions to set up and run the project locally using Docker.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Docker and Docker Compose must be installed on your system.
|
||||
- You must have a Google AI API key for the Gemini model family.
|
||||
|
||||
## Setup
|
||||
|
||||
1. **Clone the Repository**
|
||||
|
||||
```bash
|
||||
git clone <repository-url>
|
||||
cd <repository-directory>
|
||||
```
|
||||
|
||||
2. **Configure Environment Variables**
|
||||
|
||||
Create a `.env` file in the `backend/` directory:
|
||||
|
||||
```
|
||||
backend/.env
|
||||
```
|
||||
|
||||
Add your Google AI API key to this file:
|
||||
|
||||
```
|
||||
GEMINI_API_KEY="your_api_key_here"
|
||||
```
|
||||
|
||||
## Running the Application
|
||||
|
||||
1. **Build and Run Containers**
|
||||
|
||||
From the root of the project, run the following command:
|
||||
|
||||
```bash
|
||||
docker-compose up --build
|
||||
```
|
||||
|
||||
This will build the Docker images for both the frontend and backend services and start them.
|
||||
|
||||
2. **Access the Application**
|
||||
|
||||
- The **frontend** will be available at `http://localhost:3000`.
|
||||
- The **backend** API will be served at `http://localhost:8000`.
|
||||
|
||||
You can now open your web browser to `http://localhost:3000` to use the application.
|
||||
23
specs/001-people-tend-to/research.md
Normal file
23
specs/001-people-tend-to/research.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# Research & Decisions
|
||||
|
||||
**Feature**: Anonymous Desire Aggregator
|
||||
**Date**: 2025-10-09
|
||||
|
||||
## 1. Semantic Analysis Provider
|
||||
|
||||
- **Decision**: Per the user's directive, the project will use **Google's Gemini 2.0 Flash** model, accessed via the `@google/generative-ai` Node.js library.
|
||||
|
||||
- **Rationale**: This decision aligns with the user's specific requirement for a powerful, cloud-based, free-to-use LLM without usage limits. Using a managed cloud service simplifies the backend architecture significantly, removing the need to maintain a self-hosted model. The `Gemini Flash` family of models is designed for high speed and efficiency, making it suitable for a real-time application. This approach maintains the privacy-first architecture by ensuring user data is only held transiently in the backend's memory during the API call and is never persisted on the server.
|
||||
|
||||
- **Alternatives Considered**:
|
||||
- **Self-Hosting Open-Source Models**: Rejected as this contradicts the user's explicit choice of a specific cloud-based model.
|
||||
- **Other Cloud Providers**: Rejected to adhere to the user's specific directive to use a Google Gemini model.
|
||||
|
||||
## 2. Integration Best Practices
|
||||
|
||||
- **Decision**: The Node.js backend will contain a dedicated, stateless `LLMService` responsible for all communication with the Gemini API.
|
||||
|
||||
- **Implementation Details**:
|
||||
- **Prompt Engineering**: The service will construct a structured prompt instructing the Gemini model to perform semantic clustering on the list of raw text desires. The prompt will request a JSON object as output that maps each unique desire to a canonical group name.
|
||||
- **API Key Management**: The Google AI API key will be managed securely as an environment variable in the backend Docker container and will not be exposed to the frontend.
|
||||
- **Resiliency**: The service must implement error handling, including retries with exponential backoff for transient network errors and proper error reporting to the client if the LLM API call fails permanently.
|
||||
116
specs/001-people-tend-to/spec.md
Normal file
116
specs/001-people-tend-to/spec.md
Normal file
@@ -0,0 +1,116 @@
|
||||
# Feature Specification: Anonymous Desire Aggregator
|
||||
|
||||
**Feature Branch**: `001-people-tend-to`
|
||||
**Created**: 2025-10-09
|
||||
**Status**: Draft
|
||||
**Input**: User description: "People tend to not wanting to discuss their choices when agreeng on some common activity with others. For example, lovers might be ashamed to discuss some things straightforward before having sex. But they could privately state what they want and then blindly share their desires. The app will understand where they totally agree, where they partially agree, where they accept any suggestions, and where they totally disagree. The first person in a session states the topic and how many answers to anticipate, and shares the link to the session by copying it. One online session, totally anonymous and private, summons persons presenting their desires. Users write what they want, what they accept, and what they do not want at all - and submit the form. The system waits for all the answers and analyzes them with AI. While waiting for the results user sees some placeholder informing that the work is in progress: waiting for X more answers, analyzing results etc. Then the system presents the results: a cooperative decision based on everyone's opinions. The decision includes everything that participants want if everyone wants it too marking this part as `GoTos`. Things someone wants and everyone else just accept are in the category `AlsoGoods`. Things that are just wanted or accepted by some participants are in the category of their own - `Considerables`. The decision respects everything that at least one user does not want at all stating it as `No-goes` and excluding from every other category. The result is available by the link as long as the session is alive synching from local storage of participants via websockets."
|
||||
|
||||
## Clarifications
|
||||
|
||||
### Session 2025-10-09
|
||||
- Q: How should the system handle variations in user-submitted desire items to ensure accurate aggregation? → A: Some LLM will understand the sense, analyze and combine resluts. Not just survey.
|
||||
- Q: How should the system behave if more participants join and submit than the number originally specified by the session creator? → A: Lock the Session: Once the expected number of submissions is reached, no more submissions are allowed. Additional users see a "Session full" message.
|
||||
- Q: How should the system handle a submission where one or more of the desire categories are empty? → A: Require At Least One Item: The user must enter at least one item in at least one of the categories. They cannot submit a completely blank form.
|
||||
- Q: How should the "Considerable" category be refined to ensure it provides a useful signal to the group? → A: Just collapse this catogory in GUI giving it less attention.
|
||||
|
||||
## User Scenarios & Testing *(mandatory)*
|
||||
|
||||
### User Story 1 - Create and Share a Session (Priority: P1)
|
||||
|
||||
As a user, I want to create a new session by providing a topic and the number of expected participants, so I can receive a unique link to share with others for anonymously gathering their preferences.
|
||||
|
||||
**Why this priority**: This is the starting point for the entire workflow. Without the ability to create a session, no other functionality can be used.
|
||||
|
||||
**Independent Test**: Can be fully tested by creating a session and verifying that a unique, shareable link is generated and the session is ready for participants.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** I am on the application's home page, **When** I enter a topic "Dinner Plans" and set the number of participants to 4, **Then** the system should generate a unique URL, display it, and provide a "copy to clipboard" button.
|
||||
2. **Given** a session has been created, **When** I visit the generated URL, **Then** I should see the session's topic and the desire submission form.
|
||||
|
||||
---
|
||||
|
||||
### User Story 2 - Participate in a Session (Priority: P2)
|
||||
|
||||
As a user with a session link, I want to submit my preferences by listing items I "Want", "Accept", or "Do Not Want", so that my input is included in the final decision.
|
||||
|
||||
**Why this priority**: This is the core data-gathering function. The value of the application depends on participants being able to submit their desires easily and anonymously.
|
||||
|
||||
**Independent Test**: Can be tested by navigating to a session link, filling out and submitting the desire form, and verifying the submission is recorded.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** I have a valid session link and the session is waiting for participants, **When** I enter items into the "Want", "Accept", and "Do Not Want" fields and press "Submit", **Then** the system should confirm my submission and update the session status.
|
||||
2. **Given** I have submitted my desires, **When** I revisit the session link, **Then** the system should show me a waiting screen indicating how many more participants are needed.
|
||||
|
||||
---
|
||||
|
||||
### User Story 3 - View Aggregated Results (Priority: P3)
|
||||
|
||||
As a session participant, I want to see the final, categorized results after everyone has submitted their desires, so that our group can easily identify common ground and make a cooperative decision.
|
||||
|
||||
**Why this priority**: This is the "payoff" for the users. It delivers the promised value of a synthesized, cooperative decision, which is the main reason for using the app.
|
||||
|
||||
**Independent Test**: Can be tested by creating a session, having all participants submit their desires, and verifying that the final results are displayed correctly according to the aggregation logic.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** all participants in a session have submitted their desires, **When** I visit the session link, **Then** I should see the results screen with the categories: "GoTos", "AlsoGoods", "Considerables", and "NoGoes".
|
||||
2. **Given** the results are displayed, **When** an item was marked "Do Not Want" by at least one person, **Then** it must appear in the "NoGoes" list and nowhere else.
|
||||
3. **Given** the results are displayed, **When** an item was marked "Want" by all participants, **Then** it must appear in the "GoTos" list.
|
||||
|
||||
---
|
||||
|
||||
### Edge Cases
|
||||
|
||||
- What happens if a user provides the same item in multiple categories (e.g., in both "Want" and "Do Not Want")? (Addressed by FR-016)
|
||||
- What happens if a user tries to submit their desires more than once for the same session? (Addressed by FR-017)
|
||||
- What happens if the number of participants who join via the link exceeds the number set by the creator? (Addressed by FR-019)
|
||||
- What happens if a session link is accessed after the session is considered "closed" or has expired? (Addressed by FR-018)
|
||||
|
||||
## Requirements *(mandatory)*
|
||||
|
||||
### Functional Requirements
|
||||
|
||||
- **FR-001**: System MUST allow a user to create a new session by specifying a topic and the number of expected participants.
|
||||
- **FR-002**: System MUST generate a unique, shareable URL for each new session.
|
||||
- **FR-003**: System MUST allow any user with the session URL to participate anonymously without requiring login or registration.
|
||||
- **FR-004**: System MUST provide a form for participants to submit desires as free-form text into three distinct categories: "Want", "Accept", and "NoGoes".
|
||||
- **FR-005**: System MUST display a real-time status indicating how many participants are still needed before results can be calculated.
|
||||
- **FR-006**: System MUST begin the analysis process only after the specified number of participants have submitted their desires.
|
||||
- **FR-007**: System MUST display a status to users indicating that analysis is in progress.
|
||||
- **FR-008**: System MUST use semantic analysis (e.g., via an LLM) to interpret raw text inputs and group them into unique, semantically equivalent `Semantic Desires`.
|
||||
- **FR-009**: The system MUST calculate the final decision based on the aggregation of these `Semantic Desires`.
|
||||
- **FR-010**: A `Semantic Desire` MUST be categorized as "NoGoes" if at least one participant includes it in their "Do Not Want" list. This category takes precedence over all others.
|
||||
- **FR-011**: A `Semantic Desire` MUST be categorized as "GoTos" if it is not a "NoGoes" and all participants include it in their "Want" list.
|
||||
- **FR-012**: A `Semantic Desire` MUST be categorized as "AlsoGoods" if it is not a "NoGoes" or "GoTos", is in at least one participant's "Want" list, and all other participants have it in either their "Want" or "Accept" lists.
|
||||
- **FR-013**: A `Semantic Desire` MUST be categorized as "Considerables" if it is not in any other category but is present in at least one participant's "Want" or "Accept" list.
|
||||
- **FR-014**: System MUST display the final, categorized results to all participants in the session.
|
||||
- **FR-015**: The results view MUST be updated in real-time for all participants.
|
||||
- **FR-016**: System MUST validate a user's submission to prevent the same item from appearing in conflicting categories (e.g., in both "Want" and "Do Not Want"). If a conflict is detected, the system MUST display a clear, inline error message next to the conflicting input fields, highlighting the problematic items and preventing form submission until all conflicts are resolved by the user.
|
||||
- **FR-017**: System MUST allow each participant to submit their desires only once. Participant identity MUST be established and persisted using a client-side generated UUID stored in the browser's Local Storage. If a user attempts to submit again from the same client (identified by the stored UUID), the system MUST inform them that their submission has already been recorded and prevent resubmission.
|
||||
- **FR-018**: A session MUST remain active and its results accessible as long as at least one participant maintains an active WebSocket connection to the session. The session and its data MUST be terminated from the backend's active memory 5 minutes after the last participant disconnects. Frontend clients should handle this by displaying a "Session Expired" message and redirecting to the home page.
|
||||
- **FR-019**: Once the number of submitted desire sets equals the expected number of participants, the session MUST be automatically locked. The submission form MUST be disabled, and any user attempting to access it MUST be shown a clear message indicating "Session Full" or "Analysis in Progress" (depending on the current state), preventing further submissions.
|
||||
- **FR-020**: The system MUST require a user to enter at least one desire in at least one of the three categories ("Want", "Accept", "Do Not Want") before a submission can be accepted. Completely empty submissions MUST be rejected, and the system MUST display an inline error message prompting the user to fill in at least one category.
|
||||
- **FR-021**: On the results screen, the "Considerables" category MUST be presented in a way that gives it less prominence than "GoTos" and "AlsoGoods", for instance, by being collapsed by default.
|
||||
|
||||
### Key Entities *(include if feature involves data)*
|
||||
|
||||
- **Session**: Represents a single decision-making event.
|
||||
- **Attributes**: Topic (text), Expected Participant Count (number), Unique ID/URL (string), Status (e.g., "Waiting", "Analyzing", "Complete").
|
||||
- **Participant**: Represents an anonymous user within a given session.
|
||||
- **Desire Set**: Represents a single participant's raw text submission.
|
||||
- **Attributes**: Wants (list of strings), Accepts (list of strings), Do Not Wants (list of strings).
|
||||
- **Semantic Desire**: Represents a unique conceptual desire identified by the system's semantic analysis of the raw text in `Desire Sets`. For example, the text inputs "go for a run", "running", and "a jog" would all map to a single `Semantic Desire` representing the concept of 'running'. The system should normalize variations in phrasing, synonyms, and minor grammatical differences to identify the underlying common intent.
|
||||
- **Decision**: Represents the final aggregated output for a session.
|
||||
- **Attributes**: GoTos (list of `Semantic Desires`), AlsoGoods (list of `Semantic Desires`), Considerables (list of `Semantic Desires`), NoGoes (list of `Semantic Desires`).
|
||||
|
||||
## Success Criteria *(mandatory)*
|
||||
|
||||
### Measurable Outcomes
|
||||
|
||||
- **SC-001**: A new session can be created and the shareable link generated in under 10 seconds.
|
||||
- **SC-002**: At least 95% of participants can submit their desires on the first attempt without encountering an error message or being prevented from submitting due to validation issues.
|
||||
- **SC-003**: For a session with up to 10 participants, the results are calculated and displayed within 5 seconds of the final participant's submission.
|
||||
- **SC-004**: The final decision categories must correctly reflect the aggregation logic in 100% of automated test cases covering all rules and edge cases.
|
||||
- **SC-005**: Post-feature user satisfaction surveys indicate that at least 80% of users rate the application's ease of use (e.g., intuitive session creation, clear submission process, understandable results) as 4 or 5 on a 5-point Likert scale (1=Very Difficult, 5=Very Easy) for making group decisions.
|
||||
162
specs/001-people-tend-to/tasks.md
Normal file
162
specs/001-people-tend-to/tasks.md
Normal file
@@ -0,0 +1,162 @@
|
||||
# Task Breakdown: Anonymous Desire Aggregator
|
||||
|
||||
**Feature**: Anonymous Desire Aggregator
|
||||
**Date**: 2025-10-09
|
||||
|
||||
This document breaks down the implementation of the feature into actionable, dependency-ordered tasks.
|
||||
|
||||
## Implementation Strategy
|
||||
|
||||
The feature will be developed in phases, aligned with user stories. Each phase represents an independently testable and deliverable increment of functionality. The MVP (Minimum Viable Product) is the completion of User Story 1, which allows a user to create a session.
|
||||
|
||||
**Note on TDD**: All new features and bug fixes MUST follow a Test-Driven Development approach. This means tests should be written first, observed to fail, and then made to pass upon completion of the implementation.
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Project Setup
|
||||
|
||||
**Goal**: Initialize the frontend and backend projects and set up the Docker environment.
|
||||
|
||||
| ID | Task | Files / Location | Status |
|
||||
|---|---|---|---|
|
||||
| T001 | [P] Initialize the `frontend` project using Create React App with the TypeScript template. | `frontend/` | Done |
|
||||
| T002 | [P] Initialize the `backend` Node.js project (`npm init`) and set up TypeScript. | `backend/` | Done |
|
||||
| T003 | [P] Create a basic `Dockerfile` for the `frontend` service. | `frontend/Dockerfile` | Done |
|
||||
| T004 | [P] Create a basic `Dockerfile` for the `backend` service. | `backend/Dockerfile` | Done |
|
||||
| T005 | Create the `docker-compose.yaml` file to orchestrate the frontend and backend services. | `docker-compose.yaml` | Done |
|
||||
| T005.5 | Define and review the `openapi.yaml` API contract. | `specs/001-people-tend-to/contracts/openapi.yaml` | Done |
|
||||
| T006 | Install core dependencies for the `backend`: express, ws, typescript, @google/generative-ai. | `backend/package.json` | Done |
|
||||
| T007 | Install core dependencies for the `frontend`: react, react-dom, @mui/material, @emotion/react. | `frontend/package.json` | Done |
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Foundational Tasks
|
||||
|
||||
**Goal**: Implement core services and hooks that are prerequisites for all user stories.
|
||||
|
||||
| ID | Task | Files / Location | Status |
|
||||
|---|---|---|---|
|
||||
| T008 | [Backend] Implement the basic WebSocket server to handle connections and manage a list of clients. | `backend/src/ws/` | Done |
|
||||
| T009 | [Frontend] [P] Implement a `WebSocketService` to connect to the backend and handle incoming/outgoing messages. | `frontend/src/services/` | Done |
|
||||
| T010 | [Frontend] [P] Implement a `useSession` custom hook to manage the session state in Local Storage. | `frontend/src/hooks/` | Done |
|
||||
| T011 | [Frontend] Set up the basic Material-UI theme and provider. | `frontend/src/App.tsx` | Done |
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: [US1] Create and Share a Session
|
||||
|
||||
**Goal**: A user can create a new session and get a shareable link.
|
||||
**Independent Test**: Can be verified by calling the `/sessions` endpoint and seeing a valid session ID returned, then loading the frontend at that URL.
|
||||
|
||||
| ID | Task | Files / Location | Status |
|
||||
|---|---|---|---|
|
||||
| T012 | [Backend] Write a test for the `POST /sessions` endpoint. | `backend/tests/` | Done |
|
||||
| T013 | [Backend] Implement the `POST /sessions` endpoint to generate and return a unique session ID. | `backend/src/routes/` | Done |
|
||||
| T014 | [Frontend] [P] Write a test for the `CreateSession` page component. | `frontend/src/pages/` | Done |
|
||||
| T015 | [Frontend] [P] Create the UI component for the session creation form (topic, participant count). | `frontend/src/pages/` | Done |
|
||||
| T016 | [Frontend] Implement the client-side logic to call the `POST /sessions` API. | `frontend/src/pages/` | Done |
|
||||
| T017 | [Frontend] On successful session creation, initialize the `Session` object in Local Storage via the `useSession` hook and redirect to the new session URL. | `frontend/src/pages/` | Done |
|
||||
|
||||
**Checkpoint**: User Story 1 is complete and independently testable. MVP is met.
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: [US2] Participate in a Session
|
||||
|
||||
**Goal**: A user can join a session, see its status, and submit their desires.
|
||||
**Independent Test**: Can be verified by multiple clients connecting to the same session URL, submitting forms, and seeing the participant count update.
|
||||
|
||||
| ID | Task | Files / Location | Status |
|
||||
|---|---|---|---|
|
||||
| T018 | [Backend] Implement WebSocket logic to relay `SHARE_STATE` and `SUBMIT_DESIRES` messages to all clients in a session. | `backend/src/ws/` | Done |
|
||||
| T019 | [Frontend] [P] Write a test for the `DesireForm` component. | `frontend/src/components/` | Done |
|
||||
| T020 | [Frontend] [P] Create the UI component for the desire submission form (Want, Accept, NoGoes). | `frontend/src/components/` | Done |
|
||||
| T020.1 | [Frontend] Implement validation to prevent empty desire submissions (FR-020). | `frontend/src/components/` | Done |
|
||||
| T020.2 | [Frontend] Implement validation to prevent conflicting categories in submissions (FR-016). | `frontend/src/components/` | Done |
|
||||
| T020.3 | [Frontend] Implement logic to prevent resubmission from the same client (FR-017). | `frontend/src/hooks/useSession.ts` | Done |
|
||||
| T021 | [Frontend] Implement logic to send the `SUBMIT_DESIRES` message via WebSocket. | `frontend/src/pages/` | Done |
|
||||
| T022 | [Frontend] Implement logic to handle incoming `STATE_UPDATE` messages and update the local session state. | `frontend/src/hooks/useSession.ts` | Done |
|
||||
| T023 | Create a UI component to display the "Waiting for X more participants..." status. | `frontend/src/components/` | Done |
|
||||
| T023.1 | [Backend] Implement session locking logic when expected participants are reached. | `backend/src/ws/` | Done |
|
||||
| T023.2 | [Frontend] Implement UI to disable submission form and display "Session Full" / "Analysis in Progress" message. | `frontend/src/components/` | Done |
|
||||
|
||||
**Checkpoint**: User Story 2 is complete and independently testable.
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: [US3] View Aggregated Results
|
||||
|
||||
**Goal**: Users can see the final, categorized results of the session.
|
||||
**Independent Test**: Can be verified by having the creator client trigger the analysis and all clients seeing the same results displayed.
|
||||
|
||||
| ID | Task | Files / Location | Status |
|
||||
|---|---|---|---|
|
||||
| T024 | [Backend] [P] Write a test for the `LLMService`, mocking the Gemini API client. | `backend/tests/` | Done |
|
||||
| T024.1 | [Backend] Write comprehensive automated test cases for the aggregation logic (SC-004). | `backend/tests/` | Done |
|
||||
| T025 | [Backend] [P] Implement the `LLMService` to construct the prompt and call the Gemini API. | `backend/src/services/` | Done |
|
||||
| T026 | [Backend] Write a test for the `POST /sessions/{sessionId}/analyze` endpoint. | `backend/tests/` | Done |
|
||||
| T027 | [Backend] Implement the `POST /sessions/{sessionId}/analyze` endpoint. | `backend/src/routes/` | Done |
|
||||
| T028 | [Backend] Implement the WebSocket broadcast for the `ANALYSIS_COMPLETE` message. | `backend/src/ws/` | Done |
|
||||
| T029 | [Frontend] [P] Write a test for the `ResultsDisplay` component. | `frontend/src/components/` | Done |
|
||||
| T030 | [Frontend] [P] Create UI components for displaying the `GoTos`, `AlsoGoods`, `Considerable`, and `NoGoes` categories. | `frontend/src/components/` | Done |
|
||||
| T031 | [Frontend] Implement the UI logic to collapse the "Considerable" category by default. | `frontend/src/components/` | Done |
|
||||
| T032 | [Frontend] Implement the logic for the creator's client to call the `analyze` endpoint. | `frontend/src/pages/` | Done |
|
||||
| T033 | [Frontend] Implement the handler for the `ANALYSIS_COMPLETE` message to update the UI. | `frontend/src/hooks/useSession.ts` | Done |
|
||||
| T033.1 | [Frontend] Ensure real-time synchronization of the results view (FR-015). | `frontend/src/pages/` | Done |
|
||||
|
||||
**Checkpoint**: User Story 3 is complete and independently testable.
|
||||
|
||||
---
|
||||
|
||||
## Phase 6: Polish & Integration
|
||||
|
||||
**Goal**: Finalize the application with error handling, loading states, and end-to-end testing.
|
||||
|
||||
| ID | Task | Files / Location | Status |
|
||||
|---|---|---|---|
|
||||
| T034 | [Frontend] Add loading indicators for API calls and WebSocket events. | `frontend/src/components/` | Done |
|
||||
| T035 | [Frontend] Add user-friendly error messages for API failures or WebSocket disconnections. | `frontend/src/components/` | Done |
|
||||
| T036 | [Docs] Write end-to-end test plan for manual execution. | `tests/e2e.md` | Done |
|
||||
| T036.5 | [Docs] Plan and conduct user satisfaction surveys to measure SC-005. | `docs/user-satisfaction.md` | Done |
|
||||
|
||||
---
|
||||
|
||||
## Phase 7: Performance & Scalability
|
||||
|
||||
**Goal**: Optimize application performance and ensure scalability.
|
||||
|
||||
| ID | Task | Files / Location | Status |
|
||||
|---|---|---|---|
|
||||
| T037 | [Backend] Implement caching for LLM responses to reduce latency and API calls. | `backend/src/services/LLMService.ts` | Done |
|
||||
| T038 | [Backend] Implement load testing for the WebSocket server to ensure it handles concurrent connections. | `backend/tests/` | Done |
|
||||
| T039 | [Frontend] Optimize React component rendering to minimize re-renders. | `frontend/src/components/`, `frontend/src/pages/` | Done |
|
||||
| T040 | [Docs] Document performance testing results against SC-001 and SC-003. | `docs/performance.md` | Done |
|
||||
|
||||
---
|
||||
|
||||
## Phase 8: Security & Privacy
|
||||
|
||||
**Goal**: Ensure the application adheres to privacy mandates and security best practices.
|
||||
|
||||
| ID | Task | Files / Location | Status |
|
||||
|---|---|---|---|
|
||||
| T041 | [Backend] Implement strict logging policies to ensure no user desire content is persisted. | `backend/src/` | Done |
|
||||
| T042 | [Backend] Review LLM API calls to confirm only necessary data is sent and no PII is exposed. | `backend/src/services/LLMService.ts` | Done |
|
||||
| T043 | [Frontend] Implement measures to prevent accidental exposure of session IDs or participant data. | `frontend/src/` | Done |
|
||||
| T044 | [Docs] Document privacy compliance measures. | `docs/privacy.md` | Done |
|
||||
|
||||
---
|
||||
|
||||
## Phase 9: Session Management & Cleanup
|
||||
|
||||
**Goal**: Implement session lifecycle management, including termination and expiration handling.
|
||||
|
||||
| ID | Task | Files / Location | Status |
|
||||
|---|---|---|---|
|
||||
| T045 | [Backend] Implement session termination logic (e.g., timeout mechanism for inactive sessions). | `backend/src/ws/` | Done |
|
||||
| T046 | [Frontend] Implement "Session Expired" message and redirection to home page. | `frontend/src/pages/` | Done |
|
||||
|
||||
## Dependencies
|
||||
|
||||
- **User Story Completion Order**: US1 → US2 → US3
|
||||
- **Parallel Work**: Within each user story phase, frontend and backend tasks marked with `[P]` can often be worked on in parallel, but frontend component implementation depends on the tests being written first.
|
||||
Reference in New Issue
Block a user