built basic ui structure in /hierarchy
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
---
|
||||
trigger: model_decision
|
||||
description: When working on the voxer-like audio recording, chunking, streaming and playback setup
|
||||
---
|
||||
|
||||
# Audio Recording & Streaming Architecture
|
||||
|
||||
This project implements a "Voxer-like" audio messaging system using Phoenix Channels for binary streaming and Oban for background processing.
|
||||
|
||||
## 1. Components & Data Flow
|
||||
- **Capture**: `AudioRecorder` JS Hook (`assets/js/hooks/audio_recorder.js`) uses `MediaRecorder` with `audio/webm;codecs=opus`.
|
||||
- **Transport**: Raw binary chunks are pushed via Phoenix Channels (`audio:lobby`).
|
||||
- **Persistence**: Server appends chunks to a `.webm` file in `priv/static/uploads/`.
|
||||
- **Processing**: `audio_end` event triggers an **Oban** job (`RiverConnect.Workers.ProcessRecording`) to finalize and update status.
|
||||
- **Serving**: Files are served from `/uploads/` via a dedicated `Plug.Static` entry in `RiverConnectWeb.Endpoint`.
|
||||
|
||||
## 2. Channel Protocol (`AudioChannel`)
|
||||
- **`audio_start`**: `%{"id" => id}`. Initializes the recording session and creates a temp file.
|
||||
- **`audio_chunk`**: `{:binary, payload}`. Appends binary to the file and broadcasts to other listeners for live playback.
|
||||
- **`audio_end`**: `%{"duration_ms" => ms, "id" => id}`. Creates the `AudioMessage` DB record and enqueues the Oban worker.
|
||||
|
||||
## 3. Real-time Playback
|
||||
- While a recording is in progress, the channel broadcasts `audio_chunk` events.
|
||||
- The receiving `AudioRecorder` hook uses `AudioContext.decodeAudioData` to play these chunks immediately, providing a "near-realtime" walkie-talkie experience.
|
||||
|
||||
## 4. Database Schema (`AudioMessage`)
|
||||
- `user_id`: String (Guest ID or User ID).
|
||||
- `file_path`: Relative path (e.g., `/uploads/uuid.webm`).
|
||||
- `duration_ms`: Total recording duration.
|
||||
- `status`: `"processing"` | `"ready"`.
|
||||
- **Note**: The schema must `@derive {Jason.Encoder, ...}` to be sent over Phoenix Channels.
|
||||
|
||||
## 5. Environment Constraints (Windows)
|
||||
- Commands like `mix` may need to be executed via `cmd /c` or with explicit PATH to `erl.exe` and `mix.bat` in backgrounds tasks.
|
||||
- Static files in `priv/static/uploads` must be exposed explicitly in `endpoint.ex` and may require a server restart to be served correctly after initial creation.
|
||||
|
||||
## 6. Development Tips
|
||||
- **Restart Required**: Adding new sockets or `Plug.Static` rules in `endpoint.ex` requires a full `mix phx.server` restart.
|
||||
- **Permissions**: Ensure the browser has microphone permissions for the specific port (default 4000/4005).
|
||||
- **Streaming Jitter**: Basic playback uses `decodeAudioData`. For production-grade streaming without gaps, a jitter buffer/audio scheduler would be required.
|
||||
@@ -0,0 +1,35 @@
|
||||
# Audio Recording & Streaming Architecture
|
||||
|
||||
This project implements an asynchronous and real-time audio messaging system using Phoenix Channels for binary streaming and Oban for background processing.
|
||||
|
||||
## 1. Components & Data Flow
|
||||
- **Capture**: `AudioRecorder` JS Hook (`assets/js/hooks/audio_recorder.js`) utilizes the `MediaRecorder` API with `audio/webm;codecs=opus`.
|
||||
- **Transport**: Binary chunks are transmitted via Phoenix Channels (`audio:lobby`).
|
||||
- **Persistence**: The server appends incoming chunks to a `.webm` file located in `priv/static/uploads/`.
|
||||
- **Finalization**: An `audio_end` event triggers an **Oban** job (`RiverConnect.Workers.ProcessRecording`) to verify the file and update the database status.
|
||||
- **Serving**: Static audio files are exposed via a dedicated `Plug.Static` entry in `RiverConnectWeb.Endpoint`.
|
||||
|
||||
## 2. Channel Protocol (`AudioChannel`)
|
||||
- **`audio_start`**: `%{"id" => id}`. Initializes the server-side recording state and creates the target file.
|
||||
- **`audio_chunk`**: `{:binary, payload}`. Appends binary data to the file and broadcasts the chunk for real-time consumption.
|
||||
- **`audio_end`**: `%{"duration_ms" => ms, "id" => id}`. Persists the `AudioMessage` record and enqueues the processing worker.
|
||||
|
||||
## 3. Real-time Streaming
|
||||
- During an active recording session, the channel broadcasts `audio_chunk` events to all subscribers.
|
||||
- Subscribed clients use `AudioContext.decodeAudioData` to process and play the binary stream with minimal latency.
|
||||
|
||||
## 4. Database Schema (`AudioMessage`)
|
||||
- `user_id`: Identifies the sender (Guest or Authenticated).
|
||||
- `file_path`: Relative URL to the static resource.
|
||||
- `duration_ms`: Integer representing the length of the audio.
|
||||
- `status`: State machine values (`"processing"`, `"ready"`).
|
||||
- **Note**: The schema must `@derive {Jason.Encoder, ...}` for binary serialization over the socket.
|
||||
|
||||
## 5. Environment & Infrastructure
|
||||
- **Windows Support**: `mix` commands in background processes may require explicit PATH configuration for Erlang/Elixir binaries.
|
||||
- **Static Configuration**: Dynamic directories in `priv/static` require explicit inclusion in the `Endpoint` configuration to be served correctly.
|
||||
|
||||
## 6. Implementation Notes
|
||||
- **Server Restarts**: Modifications to `endpoint.ex` or `UserSocket` require a server restart to take effect.
|
||||
- **Hardware Access**: Web-based recording requires secure context (HTTPS/Localhost) and explicit browser microphone permissions.
|
||||
- **Latency Management**: Real-time playback relies on prompt chunk processing; production environments may require a jitter buffer for consistency.
|
||||
@@ -0,0 +1,41 @@
|
||||
---
|
||||
trigger: model_decision
|
||||
description: When working on UI
|
||||
---
|
||||
|
||||
# Kobalte for Solid.js Coding Rules
|
||||
|
||||
## Core Mandate
|
||||
1. **Always use [Kobalte](https://kobalte.dev/)** for UI components in Solid.js (e.g., Popovers, Dialogs, Selects, Tooltips, etc.).
|
||||
2. **DO NOT** implement custom UI logic or accessibility patterns from scratch unless explicitly requested by the user.
|
||||
3. **DO NOT** use other UI libraries for Solid.js unless explicitly requested.
|
||||
|
||||
## Implementation Guidelines
|
||||
- **Importing**: Always import from `@kobalte/core`.
|
||||
- **Structure**: Follow the standard Kobalte pattern: `Component.Root`, `Component.Trigger`, `Component.Portal`, `Component.Content`, etc.
|
||||
- **Styling**:
|
||||
- Use **Tailwind CSS** for all styling.
|
||||
- Apply styles directly to the Kobalte primitive components using the `class` prop.
|
||||
- Use `data-*` attributes provided by Kobalte (e.g., `data-expanded`, `data-disabled`) for state-based styling in Tailwind.
|
||||
- **Portals**: Use `<Popover.Portal>` or `<Dialog.Portal>` to ensure correct DOM placement and stacking context.
|
||||
- **Animations**: Prefer Tailwind's `animate-in`, `fade-in`, `zoom-in`, etc. (from `tailwindcss-animate` if available, or custom animations) combined with Kobalte's state attributes.
|
||||
|
||||
## Example Pattern (Popover)
|
||||
```jsx
|
||||
import { Popover } from "@kobalte/core";
|
||||
|
||||
<Popover.Root>
|
||||
<Popover.Trigger class="...">...</Popover.Trigger>
|
||||
<Popover.Portal>
|
||||
<Popover.Content class="...">
|
||||
<Popover.Arrow />
|
||||
<Popover.Title class="...">...</Popover.Title>
|
||||
<Popover.Description class="...">...</Popover.Description>
|
||||
</Popover.Content>
|
||||
</Popover.Portal>
|
||||
</Popover.Root>
|
||||
```
|
||||
|
||||
## Exceptions
|
||||
- Only bypass Kobalte if the user explicitly says: "Do not use Kobalte for this" or "Build this from scratch".
|
||||
- If a component is not available in Kobalte, ask for clarification before choosing an alternative.
|
||||
@@ -0,0 +1,58 @@
|
||||
---
|
||||
trigger: always_on
|
||||
---
|
||||
|
||||
# Elixir & Solid.js Bridge Architecture
|
||||
|
||||
This project uses a hybrid architecture where **Phoenix LiveView** manages the server-side state and **Solid.js** handles the reactive client-side UI via a "Bridge Hook".
|
||||
|
||||
## 1. Core Architecture
|
||||
- **State Source of Truth**: `socket.assigns` in Elixir LiveViews.
|
||||
- **Transport**: JSON payloads via `push_event/3` (Server -> Client) and `pushEvent` (Client -> Server).
|
||||
- **Client Container**: A `div` with `phx-update="ignore"`, a unique `id`, and `phx-hook="SolidBridge"`.
|
||||
- **Reactivity**: A Phoenix Hook initializes a **Solid.js Store**. Server events trigger `setState` on the store, which drives Solid's fine-grained reactivity.
|
||||
|
||||
## 2. Frontend Build Pipeline
|
||||
- **Bundler**: Custom `esbuild` script ([build.js](file:///c:/Users/TimothyCardoza/Documents/AI-Apps/RiverConnect/Rivertalk/river_connect/assets/build.js)).
|
||||
- **Runtime**: `bun` is used for dependency management and running the build script.
|
||||
- **JSX Support**: Solid.js JSX is compiled via `esbuild-plugin-solid`.
|
||||
- **Dependency Paths**:
|
||||
- Phoenix dependencies (js) are loaded from `package.json` (npm versions).
|
||||
- Aliases: `phoenix-colocated` is shimmed to `js/phoenix-colocated-shim.js` to prevent dynamic require errors.
|
||||
|
||||
## 3. Directory Structure & Key Files
|
||||
- `lib/river_connect_web/live/`: Elixir LiveView components.
|
||||
- `assets/js/hooks/SolidBridge.jsx`: The Phoenix Hook that spawns Solid.
|
||||
- `assets/js/components/`: Solid.js reactive components (`.jsx`).
|
||||
- `priv/static/assets/js/app.js`: Generated bundle (Target for `esbuild`).
|
||||
|
||||
## 4. State Syncing Patterns
|
||||
### Server to Client (Push)
|
||||
```elixir
|
||||
# lib/app_live.ex
|
||||
def handle_event("update", _params, socket) do
|
||||
new_state = %{count: 1}
|
||||
{:noreply, push_event(socket, "sync_state", new_state)}
|
||||
end
|
||||
```
|
||||
|
||||
### Client to Server (Push)
|
||||
```javascript
|
||||
// assets/js/components/MyComponent.jsx
|
||||
const update = () => props.push("client_event", { data: "payload" });
|
||||
```
|
||||
|
||||
## 5. UI Components & Styling
|
||||
- **Styling**: Tailwind CSS + DaisyUI.
|
||||
- **Headless UI**: [Kobalte](https://kobalte.dev/) is used for complex UI logic (Popovers, Tooltips, Tabs) while maintaining total style control.
|
||||
- **Glassmorphism**: Use `.glass` helper in CSS for translucent, blurred backgrounds.
|
||||
|
||||
## 6. Development Workflow
|
||||
- **Watchers**: Run automatically via `mix phx.server` (Configured in `config/dev.exs` using `bun`).
|
||||
- **Manual Build**: `bun run --prefix assets build`.
|
||||
- **Adding Dependencies**: Use `bun add` in the `assets/` directory.
|
||||
|
||||
## 7. Important Constraints
|
||||
- **NEVER** use `phx-update="replace"` on Solid.js root containers; it will destroy the Solid DOM tree.
|
||||
- **ALWAYS** use `phx-update="ignore"` for Solid mounts.
|
||||
- **JSX in JS**: The build script is configured to treat `.js` files as JSX, but preferred extension for Solid components is `.jsx`.
|
||||
Reference in New Issue
Block a user