init
This commit is contained in:
335
instructions.md
Normal file
335
instructions.md
Normal file
@@ -0,0 +1,335 @@
|
||||
# User Stories for P2P Chat Application
|
||||
|
||||
> **Reference:** [webrtc.org](https://webrtc.org)
|
||||
|
||||
The following user stories describe a peer-to-peer chat and voice application (Discord-like) built with **Electron** and **Angular** (using RxJS and NgRx) with a local SQLite store (via SQL.js). A central server only provides a directory of active rooms and users; all message and audio/video data is exchanged directly between peers (no port forwarding needed). Stories are grouped by role and include acceptance criteria and technical notes.
|
||||
|
||||
---
|
||||
|
||||
## Regular User
|
||||
|
||||
### Search and Join Chat Server
|
||||
|
||||
**User Story:** As a Regular User, I want to search for available chat servers (rooms) by name or topic so that I can find and join active communities.
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- A search input allows queries against the central directory of servers.
|
||||
- Matching servers are returned and listed with details (name, current user count, etc.).
|
||||
- I can select a server from the list and send a join request.
|
||||
- If the server exists and is active, I am connected to that server's peer network.
|
||||
- Error is shown if the server is not found or unavailable.
|
||||
|
||||
**Technical Notes:**
|
||||
- Use Angular's `HttpClient` to call the central REST API (e.g. `GET /servers?search={query}`), which returns an Observable.
|
||||
- Use RxJS operators (e.g. `debounceTime`) to handle user input.
|
||||
- Use Angular components/forms for the search UI and display results. Use `async` pipe in templates for Observables.
|
||||
- Store search results and selected server info in an NgRx store or Angular Signals to manage state and reactively update UI.
|
||||
|
||||
---
|
||||
|
||||
### Create Chatroom (Become Host)
|
||||
|
||||
**User Story:** As a Regular User, I want to create a new chatroom so that I can start my own voice/text server; I should automatically become the room's host.
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- I can create a named room; the central server registers the new room.
|
||||
- I join the newly created room and see myself listed as the host/owner.
|
||||
- The host can set an optional password or topic for the room.
|
||||
- Other users searching for rooms see this new room available.
|
||||
- If I disconnect without others online, the room is removed from the server directory.
|
||||
|
||||
**Technical Notes:**
|
||||
- Use Angular forms to input room details and NgRx actions to handle creation. Dispatch an action that posts to the central server API (e.g. `POST /servers`) and upon success updates the local store.
|
||||
- In the NgRx state, mark the creator as `host: true`. Follow NgRx best practices (immutable state, action-driven updates).
|
||||
- No code style notes here beyond following lint rules (e.g. `prefer const`, `no var`, 2-space indent).
|
||||
- After creation, initiate the P2P mesh: the host opens listening sockets (WebRTC or TCP sockets) and waits for peers (see "P2P Connectivity" story).
|
||||
|
||||
---
|
||||
|
||||
### Join Existing Chatroom
|
||||
|
||||
**User Story:** As a Regular User, I want to join an existing chatroom so that I can participate in it.
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- I can select an available room and request to join.
|
||||
- The host is notified of my request and (if approved) I connect to the room.
|
||||
- If no approval step, I immediately join and synchronize chat history and participants.
|
||||
- Upon joining, I receive the current chat history (text and possibly voice stream) from one or more peers.
|
||||
|
||||
**Technical Notes:**
|
||||
- Use Angular Router or services to handle navigation/joining logic.
|
||||
- When joining, use a WebRTC signaling channel (via the central server or direct peer signaling) to exchange ICE candidates (STUN/TURN).
|
||||
- Once connected, use WebRTC DataChannels for chat data and Streams for audio/video.
|
||||
- On the host side, use NgRx Effects to handle incoming join events and broadcast initial state (messages and user list) to new peer.
|
||||
|
||||
---
|
||||
|
||||
### Send, Edit, Delete, and React to Messages
|
||||
|
||||
**User Story:** As a Regular User, I want to send text messages, and edit or delete my own messages (and react to any message), so that I can communicate effectively and correct mistakes.
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- I can type and send a chat message, which is immediately delivered to all peers.
|
||||
- I can edit or delete any of my own previously sent messages; these edits/deletions update on all peers in real time.
|
||||
- I can react (e.g. add emoji) to any message; reactions are displayed next to the message for all users.
|
||||
- All message operations (send/edit/delete/react) are performed instantly (optimistic UI) and confirmed or synchronized with peers.
|
||||
- Deleted messages are removed from the UI for all users.
|
||||
|
||||
**Technical Notes:**
|
||||
- Use WebRTC `RTCDataChannel` (via a library like `simple-peer` or native API) for sending JSON-encoded message events between peers. Data channels provide reliable, ordered delivery for text.
|
||||
- Maintain a local message store (NgRx store or Signals) that holds all chat messages and reactions. Update the store immutably and broadcast updates to other peers.
|
||||
- Persist messages locally using SQL.js: run SQLite in-memory and after significant changes call `db.export()` to save state (or write to a file via Electron). On join, import/export to synchronize history (SQL.js can load an existing `Uint8Array` DB).
|
||||
- Implement send/edit/delete/react actions and reducers/effects in NgRx. Ensure all reducers treat state immutably and use NgRx Effects for any asynchronous broadcasts.
|
||||
- Follow lint rules for event handlers and functions (`no-unused-vars`, consistent naming).
|
||||
|
||||
---
|
||||
|
||||
### Voice Chat (Push-to-Talk)
|
||||
|
||||
**User Story:** As a Regular User, I want to join a voice channel within the chatroom so that I can talk to other participants (e.g. using push-to-talk or a switch).
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- I can enable my microphone and connect to the voice channel.
|
||||
- Other users hear my voice with low latency, and I hear theirs.
|
||||
- Only one person needs to be host; no central server relaying audio.
|
||||
- If I mute or leave, others no longer hear me.
|
||||
- Voice quality adapts to network (e.g. uses Opus codec).
|
||||
|
||||
**Technical Notes:**
|
||||
- Use WebRTC MediaStreams for audio: call `navigator.mediaDevices.getUserMedia({ audio: true })` to capture microphone audio. Add this audio track to the peer connection.
|
||||
- On receiving side, use a `<audio>` element or Web Audio API to play incoming audio streams.
|
||||
- Use an ICE/STUN configuration to establish P2P UDP voice channels. This avoids needing port forwarding.
|
||||
- Manage audio tracks in NgRx or a service for mute/unmute state. No messages need SQLite storage.
|
||||
- Consider using Electron's `contextIsolation` and secure context for permissions.
|
||||
|
||||
---
|
||||
|
||||
### Screen Sharing (with Game Capture)
|
||||
|
||||
**User Story:** As a Regular User, I want to share my screen or a game window with others so that I can show my gameplay or desktop.
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- I can start screen sharing (full screen, a window, or browser tab).
|
||||
- Other users see a video stream of my screen.
|
||||
- Shared video uses hardware-accelerated decoding (GPU) for performance.
|
||||
- Sharing a game window is possible (capturing fullscreen games).
|
||||
- I can stop sharing and return to voice-only.
|
||||
|
||||
**Technical Notes:**
|
||||
- Use `navigator.mediaDevices.getDisplayMedia()` to capture the screen or window as a MediaStream. For game capture, Electron's `desktopCapturer` or `getDisplayMedia()` with a game window source can be used.
|
||||
- Combine the screen stream with WebRTC peer connections so that peers receive video as part of the call.
|
||||
- Configure the WebRTC codec to a hardware-accelerated codec (e.g. VP8/VP9 with GPU decoding) if supported. Electron/Chromium typically handles GPU decode automatically for WebRTC.
|
||||
- Ensure to handle multiple video tracks (microphone and screen) in the peer connection.
|
||||
- Follow ESLint rules for function naming and spacing in all new components.
|
||||
|
||||
---
|
||||
|
||||
### Local Chat History (Offline Access)
|
||||
|
||||
**User Story:** As a Regular User, I want the chat history to be saved locally in the app's database so that I can scroll through recent messages even after restarting the app or going offline.
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- All sent/received messages in each room are saved in a local SQLite (via SQL.js) database.
|
||||
- When I reopen the app or reconnect to a room, previous messages are loaded from the local DB.
|
||||
- The database updates dynamically as new messages arrive or are edited/deleted.
|
||||
- The DB file (or exported data) persists between app restarts (using Electron's filesystem).
|
||||
|
||||
**Technical Notes:**
|
||||
- Initialize sql.js on app startup: load the WASM file (e.g. `sql-wasm.wasm`) by configuring `locateFile` in `initSqlJs`.
|
||||
- Create a database (`new SQL.Database()`) to hold tables like `messages` and `users`. Use SQL for durable local storage.
|
||||
- On each chat event, insert or update records (`INSERT`/`UPDATE`/`DELETE`). Query the DB to load history.
|
||||
- After updates, call `db.export()` and save the byte array to a file in Electron's app data directory. On restart, load that file into SQL.js to restore state.
|
||||
- Keep SQL code tidy and run queries through a service or NgRx effect, in line with TypeScript ESLint rules (`no unused vars`, `semicolons`, etc.).
|
||||
|
||||
---
|
||||
|
||||
## Admin
|
||||
|
||||
### Moderate Users
|
||||
|
||||
**User Story:** As an Admin (room moderator), I want to remove or ban disruptive users so that I can keep the chatroom safe.
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- I see a list of all users in the room and can select a user to kick or ban.
|
||||
- If I kick a user, that user is immediately disconnected from the room and cannot rejoin unless invited.
|
||||
- If I ban a user, their address/user ID is added to a room-specific ban list; they cannot rejoin even if they try.
|
||||
- Kicked or banned users cannot send any messages or voice.
|
||||
- A record of the action (who was kicked/banned) is logged in the chat (for transparency).
|
||||
|
||||
**Technical Notes:**
|
||||
- On the Angular UI, display user list in an admin dashboard component. Use NgRx store for active users.
|
||||
- When "kick/ban" is invoked, dispatch an NgRx action. An NgRx Effect can broadcast a "force-disconnect" signal to that peer's client.
|
||||
- The target client, upon receiving this signal, shows a message and disconnects. The room's peers update their state to remove that user.
|
||||
- Maintain a ban list (in local state/SQL.js); on new join attempts check this list to reject banned users.
|
||||
- Implementation parallels Discord's model: admins can ban/remove members. Follow lint rules and ensure any admin actions update state immutably.
|
||||
|
||||
---
|
||||
|
||||
### Moderate Chat Content
|
||||
|
||||
**User Story:** As an Admin, I want to delete inappropriate messages (even if sent by others) so that harmful content is removed immediately.
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- I see a delete option on any message in the chat history.
|
||||
- Deleting a message removes it from the view for all participants in real time.
|
||||
- Deleted message history is purged from local DB for all users.
|
||||
- A placeholder (e.g. "Message deleted") is shown so others know a message was removed (optional).
|
||||
|
||||
**Technical Notes:**
|
||||
- In the message list component, show a delete button for admins on every message.
|
||||
- On deletion, dispatch an action; use an NgRx Effect to broadcast a "delete-message" event on the data channel to all peers.
|
||||
- Each peer then removes that message from its NgRx store and local SQL DB.
|
||||
- Ensure the deletion logic updates the state immutably and follows ESLint rules (e.g. no empty interfaces, one statement per line).
|
||||
|
||||
---
|
||||
|
||||
### Manage Chatroom / Server Info
|
||||
|
||||
**User Story:** As an Admin, I want to update room settings (name, description, rules) so that I can keep the room information current.
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- I can change the room's display name, topic, or description.
|
||||
- Changes propagate to all users immediately (they see the new name/topic).
|
||||
- If the room is private, I can update the password or invite list.
|
||||
- All users see an "updated by admin" notification.
|
||||
|
||||
**Technical Notes:**
|
||||
- Use an Angular form or settings dialog for editing room info. Update NgRx store and broadcast changes to peers.
|
||||
- Store room metadata in NgRx; use a dedicated slice for "room settings."
|
||||
- On update, send a "update-room-info" message over the data channel. Peers update their local UI accordingly.
|
||||
- Persist settings in SQL.js so that if the host restarts, the settings remain.
|
||||
|
||||
---
|
||||
|
||||
### Assign / Revoke Moderator Role (Optional)
|
||||
|
||||
**User Story:** As an Admin, I want to designate other users as moderators or revoke their privileges so that management can be delegated.
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- I can promote a user to moderator (grant them admin rights) and demote them.
|
||||
- Moderators get the same capabilities as Admin for moderation tasks.
|
||||
- The UI reflects their moderator status (e.g., a badge).
|
||||
- Role changes are synced to all clients.
|
||||
|
||||
**Technical Notes:**
|
||||
- Add a "roles" field in user state (e.g. `user = { id, name, role }`).
|
||||
- Implement an Admin action to change a user's role; broadcast this over the P2P channel.
|
||||
- All clients update their NgRx state so that role-based UI (e.g. delete buttons) appear accordingly.
|
||||
- Use NgRx to enforce role logic in reducers, following immutability rules.
|
||||
|
||||
---
|
||||
|
||||
## System
|
||||
|
||||
### Automatic Host Reassignment
|
||||
|
||||
**User Story:** As a System, I need to automatically elect a new host if the current host leaves so that the room continues operating smoothly.
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- If the host disconnects unexpectedly, the system selects another participant as the new host.
|
||||
- Selection criteria might be: longest connected, lowest ping, or first joined. (Define one policy.)
|
||||
- All clients update to mark the new host (e.g. show a host badge).
|
||||
- The new host gains any host privileges (can kick/ban, etc.).
|
||||
- The central directory is updated if needed (new host can keep room alive).
|
||||
|
||||
**Technical Notes:**
|
||||
- Implement a leader-election algorithm in the P2P mesh: e.g., use Lamport timestamps or simply choose the next-in-list user.
|
||||
- On host disconnect event (detected via data channel/peerconnection `onclose`), dispatch a "host-left" action. An NgRx Effect can determine new host ID and broadcast a "new-host" event.
|
||||
- Update NgRx state `hostId` and any UI accordingly. This follows NgRx unidirectional flow and immutability.
|
||||
- Ensure any pending room changes (like last chat state) transfer seamlessly. The local SQLite DB is already consistent across peers, so no data is lost.
|
||||
|
||||
---
|
||||
|
||||
### Peer-to-Peer Connectivity & NAT Traversal
|
||||
|
||||
**User Story:** As a System, I want all peers to connect directly (audio/data) without requiring users to configure port forwarding.
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- Peers automatically discover routes to each other (using STUN/TURN) and establish direct connections.
|
||||
- No manual network configuration is needed by users.
|
||||
- Voice and data streams work across typical home/office NATs.
|
||||
- If a direct path fails, relay via TURN.
|
||||
|
||||
**Technical Notes:**
|
||||
- Use WebRTC's ICE framework: supply STUN (and optionally TURN) servers in the `RTCPeerConnection` configuration.
|
||||
- Exchange ICE candidates via the central server signaling (or existing peer connections).
|
||||
- The WebRTC API inherently avoids port forwarding by NAT traversal.
|
||||
- If TURN is needed, use a public TURN (or self-hosted) relay. This ensures compliance with "no port forwarding" requirement.
|
||||
- Manage connections in NgRx/Services; create Effects to handle ICE candidate events and re-dispatch as needed.
|
||||
|
||||
---
|
||||
|
||||
### Central Server Directory Endpoints
|
||||
|
||||
**User Story:** As a System, I will provide REST endpoints so that clients can search for servers and get lists of active users.
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- A `GET /servers` endpoint returns current active rooms with metadata (name, user count, host).
|
||||
- A `GET /users` endpoint returns currently online users for a room.
|
||||
- Clients can `POST /join-request` to signal intent to join (if such a flow is needed).
|
||||
- Data is updated in real time as rooms/users come and go (clients may poll or use WebSocket if implemented).
|
||||
|
||||
**Technical Notes:**
|
||||
- Implement server APIs (e.g., with Node.js/Express) that track room and user registrations in memory or a lightweight DB.
|
||||
- The Angular app uses `HttpClient` to call these endpoints.
|
||||
- Use RxJS on the frontend to poll or listen (via WebSocket or Server-Sent Events) for updates, updating the NgRx store on arrival.
|
||||
- Adhere to API error handling best practices in Angular (interceptors, error messages).
|
||||
|
||||
---
|
||||
|
||||
### Initiate P2P Signaling
|
||||
|
||||
**User Story:** As a System, I need to facilitate the initial WebRTC handshake between peers so that they can establish direct connections.
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- The host and new peers exchange session descriptions (SDP) and ICE candidates via a signaling channel.
|
||||
- Signaling can be done over the existing P2P network or via the central server (just for metadata exchange, not media).
|
||||
- Once ICE handshake is complete, direct peer connections are established for chat.
|
||||
|
||||
**Technical Notes:**
|
||||
- Use the central server or a temporary WebSocket channel for exchanging SDP offers/answers (as per WebRTC spec).
|
||||
- Implement an NgRx Effect that listens for signaling messages (e.g. via a WebSocket service) and creates/sets local/remote descriptions on `RTCPeerConnection`.
|
||||
- All signaling messages (offer, answer, ICE candidates) should be sent as JSON over a lightweight channel.
|
||||
- Once WebRTC `onicecandidate` fires, send each candidate to the peer.
|
||||
|
||||
---
|
||||
|
||||
### Data Synchronization
|
||||
|
||||
**User Story:** As a System, I need to keep each peer's local database in sync so that all users see the same chat history and user list.
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- When a new user joins, they receive the full current chat history and user list from an existing peer.
|
||||
- All peers agree on the same final state for edits/deletions; conflicts (rare) are resolved consistently (e.g. last-write-wins).
|
||||
- The local SQL databases converge to the same data for the same room.
|
||||
- After reconnections or partitioning, peers resynchronize missing events.
|
||||
|
||||
**Technical Notes:**
|
||||
- On join, the host (or longest-staying peer) can send a "state dump" (all messages and user list) to the newcomer via the data channel, then replay new events.
|
||||
- Use timestamps or message IDs to order events. Ensure RxJS streams or NgRx Effects handle out-of-order gracefully.
|
||||
- Persist full chat log and user list in SQLite; on conflict (e.g., duplicate message IDs) merge by timestamp.
|
||||
- Leverage NgRx selectors to produce sorted message lists, ensuring UI consistency across clients.
|
||||
|
||||
---
|
||||
|
||||
## Code Quality Guidelines
|
||||
|
||||
> **Note:** All code should follow the project's TypeScript and Angular style guidelines.
|
||||
|
||||
The ESLint flat config enforces rules like:
|
||||
- `no-var`
|
||||
- `prefer-const`
|
||||
- 2-space indentation
|
||||
- Angular ESLint for templates
|
||||
|
||||
Use these lint rules and Prettier formatting (as noted in config) to maintain code quality. Each component, service, and NgRx element should comply with the attached ESLint configuration.
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- **WebRTC:** [webrtc.org](https://webrtc.org) - ICE/STUN/TURN, P2P connectivity
|
||||
- **Angular:** [angular.dev](https://angular.dev) - HttpClient, Observables, async pipe
|
||||
- **NgRx:** Immutable state management, action-driven updates, Effects
|
||||
- **SQL.js:** [github.com/sql-js/sql.js](https://github.com/sql-js/sql.js) - SQLite in browser/Electron
|
||||
- **Discord Moderation:** [discord.com](https://discord.com) - Moderation model reference
|
||||
Reference in New Issue
Block a user