Skip to content

Commit 11c3d06

Browse files
committed
feat: add Phoenix LiveView demo application
Add a sample Phoenix LiveView application demonstrating Durable's workflow capabilities with real-world features: - Document upload and processing workflow - Real file analysis (size, lines, words for text files) - Conditional approval: PDFs require manual approval, other files auto-approved - Human-in-the-loop approval UI with approve/reject actions - Real-time dashboard with workflow status updates via PubSub - Workflow detail view showing step execution history The demo includes: - DocumentWorkflow: multi-step workflow with validation, analysis, approval - WorkflowLive: dashboard showing all workflow executions - DocumentLive: file upload UI with drag-and-drop support - ApprovalLive: queue for pending human approvals - WorkflowDetailLive: detailed view of workflow execution Includes docker-compose.yml for PostgreSQL setup on port 53412.
1 parent 1495200 commit 11c3d06

52 files changed

Lines changed: 5364 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[
2+
import_deps: [:ecto, :ecto_sql, :phoenix],
3+
subdirectories: ["priv/*/migrations"],
4+
plugins: [Phoenix.LiveView.HTMLFormatter],
5+
inputs: ["*.{heex,ex,exs}", "{config,lib,test}/**/*.{heex,ex,exs}", "priv/*/seeds.exs"]
6+
]

examples/phoenix_demo/.gitignore

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# The directory Mix will write compiled artifacts to.
2+
/_build/
3+
4+
# If you run "mix test --cover", coverage assets end up here.
5+
/cover/
6+
7+
# The directory Mix downloads your dependencies sources to.
8+
/deps/
9+
10+
# Where 3rd-party dependencies like ExDoc output generated docs.
11+
/doc/
12+
13+
# Ignore .fetch files in case you like to edit your project deps locally.
14+
/.fetch
15+
16+
# If the VM crashes, it generates a dump, let's ignore it too.
17+
erl_crash.dump
18+
19+
# Also ignore archive artifacts (built via "mix archive.build").
20+
*.ez
21+
22+
# Temporary files, for example, from tests.
23+
/tmp/
24+
25+
# Ignore package tarball (built via "mix hex.build").
26+
phoenix_demo-*.tar
27+
28+
# Ignore assets that are produced by build tools.
29+
/priv/static/assets/
30+
31+
# Ignore digested assets cache.
32+
/priv/static/cache_manifest.json
33+
34+
# In case you use Node.js/npm, you want to ignore these.
35+
npm-debug.log
36+
/assets/node_modules/
37+

examples/phoenix_demo/AGENTS.md

Lines changed: 449 additions & 0 deletions
Large diffs are not rendered by default.

examples/phoenix_demo/README.md

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
# Durable Phoenix Demo
2+
3+
A sample Phoenix LiveView application demonstrating the [Durable](https://github.com/wavezync/durable) workflow engine with human-in-the-loop approval capabilities.
4+
5+
## Features
6+
7+
- **Document Processing Workflow**: A multi-step workflow that validates, parses, and transforms documents
8+
- **Human-in-the-Loop**: Workflow pauses and waits for manager approval before proceeding
9+
- **Real-time Updates**: LiveView pages update in real-time as workflows progress
10+
- **Dashboard**: Monitor all workflow executions with status tracking
11+
- **Approval Queue**: Review and approve/reject pending workflow approvals
12+
13+
## Getting Started
14+
15+
### Prerequisites
16+
17+
- Elixir 1.15+
18+
- PostgreSQL 13+
19+
20+
### Setup
21+
22+
1. **Start the database** (using Docker):
23+
```bash
24+
cd examples/phoenix_demo
25+
docker-compose up -d
26+
```
27+
28+
This starts PostgreSQL on port 53412.
29+
30+
2. **Install dependencies**:
31+
```bash
32+
mix deps.get
33+
```
34+
35+
3. **Create and migrate the database**:
36+
```bash
37+
mix ecto.create
38+
mix ecto.migrate
39+
```
40+
41+
4. **Start the server**:
42+
```bash
43+
mix phx.server
44+
```
45+
46+
5. **Open in browser**:
47+
48+
Navigate to [http://localhost:4000](http://localhost:4000)
49+
50+
### Stopping the Database
51+
52+
```bash
53+
docker-compose down
54+
```
55+
56+
To also remove the data volume:
57+
```bash
58+
docker-compose down -v
59+
```
60+
61+
## Usage
62+
63+
### Creating a Workflow
64+
65+
1. Click **"New Workflow"** in the navigation
66+
2. Enter a filename (e.g., `report.pdf`, `data.csv`)
67+
3. Click **"Start Workflow"**
68+
69+
### Workflow Steps
70+
71+
The document processing workflow goes through these steps:
72+
73+
1. **Validate Document** - Checks the file extension is valid
74+
2. **Parse Content** - Extracts simulated content from the document
75+
3. **Request Approval** - **Pauses** and waits for human approval
76+
4. **Transform Data** - Processes the approved data
77+
5. **Generate Report** - Creates the final report
78+
79+
### Approving Workflows
80+
81+
1. Navigate to **"Approvals"** in the navigation
82+
2. You'll see pending approval requests
83+
3. Click **"Review"** to see document details
84+
4. Click **"Approve"** or **"Reject"**
85+
86+
When approved, the workflow resumes and completes. When rejected, it handles the rejection gracefully.
87+
88+
## Architecture
89+
90+
### Workflow Definition
91+
92+
```elixir
93+
defmodule PhoenixDemo.Workflows.DocumentWorkflow do
94+
use Durable
95+
use Durable.Helpers
96+
use Durable.Context
97+
use Durable.Wait
98+
99+
workflow "process_document", timeout: hours(24) do
100+
step :validate_document do
101+
# Validate document format
102+
end
103+
104+
step :parse_content do
105+
# Extract content from document
106+
end
107+
108+
step :request_approval do
109+
# Wait for human approval
110+
wait_for_approval("document_approval",
111+
prompt: "Please review the extracted document data"
112+
)
113+
end
114+
115+
decision :check_approval do
116+
# Route based on approval response
117+
end
118+
119+
step :transform_data do
120+
# Transform approved data
121+
end
122+
123+
step :generate_report do
124+
# Generate final report
125+
end
126+
127+
step :handle_rejection do
128+
# Handle rejection case
129+
end
130+
end
131+
end
132+
```
133+
134+
### Key Components
135+
136+
- **WorkflowLive**: Dashboard showing all workflow executions
137+
- **DocumentLive**: Form to create new document workflows
138+
- **ApprovalLive**: Queue for pending human approvals
139+
- **WorkflowDetailLive**: Detailed view of a single workflow
140+
141+
### Database Tables
142+
143+
Durable creates these tables in the `durable` schema:
144+
145+
- `durable.workflow_executions` - Workflow instances
146+
- `durable.step_executions` - Step execution history
147+
- `durable.pending_inputs` - Human input requests
148+
149+
## Development
150+
151+
### Compiling
152+
153+
```bash
154+
mix compile
155+
```
156+
157+
### Running Tests
158+
159+
```bash
160+
mix test
161+
```
162+
163+
### Code Style
164+
165+
```bash
166+
mix format
167+
```
168+
169+
## Learn More
170+
171+
- [Durable Documentation](https://hexdocs.pm/durable)
172+
- [Phoenix LiveView](https://hexdocs.pm/phoenix_live_view)
173+
- [Ecto](https://hexdocs.pm/ecto)
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/* See the Tailwind configuration guide for advanced usage
2+
https://tailwindcss.com/docs/configuration */
3+
4+
@import "tailwindcss" source(none);
5+
@source "../css";
6+
@source "../js";
7+
@source "../../lib/phoenix_demo_web";
8+
9+
/* A Tailwind plugin that makes "hero-#{ICON}" classes available.
10+
The heroicons installation itself is managed by your mix.exs */
11+
@plugin "../vendor/heroicons";
12+
13+
/* daisyUI Tailwind Plugin. You can update this file by fetching the latest version with:
14+
curl -sLO https://github.com/saadeghi/daisyui/releases/latest/download/daisyui.js
15+
Make sure to look at the daisyUI changelog: https://daisyui.com/docs/changelog/ */
16+
@plugin "../vendor/daisyui" {
17+
themes: false;
18+
}
19+
20+
/* daisyUI theme plugin. You can update this file by fetching the latest version with:
21+
curl -sLO https://github.com/saadeghi/daisyui/releases/latest/download/daisyui-theme.js
22+
We ship with two themes, a light one inspired on Phoenix colors and a dark one inspired
23+
on Elixir colors. Build your own at: https://daisyui.com/theme-generator/ */
24+
@plugin "../vendor/daisyui-theme" {
25+
name: "dark";
26+
default: false;
27+
prefersdark: true;
28+
color-scheme: "dark";
29+
--color-base-100: oklch(30.33% 0.016 252.42);
30+
--color-base-200: oklch(25.26% 0.014 253.1);
31+
--color-base-300: oklch(20.15% 0.012 254.09);
32+
--color-base-content: oklch(97.807% 0.029 256.847);
33+
--color-primary: oklch(58% 0.233 277.117);
34+
--color-primary-content: oklch(96% 0.018 272.314);
35+
--color-secondary: oklch(58% 0.233 277.117);
36+
--color-secondary-content: oklch(96% 0.018 272.314);
37+
--color-accent: oklch(60% 0.25 292.717);
38+
--color-accent-content: oklch(96% 0.016 293.756);
39+
--color-neutral: oklch(37% 0.044 257.287);
40+
--color-neutral-content: oklch(98% 0.003 247.858);
41+
--color-info: oklch(58% 0.158 241.966);
42+
--color-info-content: oklch(97% 0.013 236.62);
43+
--color-success: oklch(60% 0.118 184.704);
44+
--color-success-content: oklch(98% 0.014 180.72);
45+
--color-warning: oklch(66% 0.179 58.318);
46+
--color-warning-content: oklch(98% 0.022 95.277);
47+
--color-error: oklch(58% 0.253 17.585);
48+
--color-error-content: oklch(96% 0.015 12.422);
49+
--radius-selector: 0.25rem;
50+
--radius-field: 0.25rem;
51+
--radius-box: 0.5rem;
52+
--size-selector: 0.21875rem;
53+
--size-field: 0.21875rem;
54+
--border: 1.5px;
55+
--depth: 1;
56+
--noise: 0;
57+
}
58+
59+
@plugin "../vendor/daisyui-theme" {
60+
name: "light";
61+
default: true;
62+
prefersdark: false;
63+
color-scheme: "light";
64+
--color-base-100: oklch(98% 0 0);
65+
--color-base-200: oklch(96% 0.001 286.375);
66+
--color-base-300: oklch(92% 0.004 286.32);
67+
--color-base-content: oklch(21% 0.006 285.885);
68+
--color-primary: oklch(70% 0.213 47.604);
69+
--color-primary-content: oklch(98% 0.016 73.684);
70+
--color-secondary: oklch(55% 0.027 264.364);
71+
--color-secondary-content: oklch(98% 0.002 247.839);
72+
--color-accent: oklch(0% 0 0);
73+
--color-accent-content: oklch(100% 0 0);
74+
--color-neutral: oklch(44% 0.017 285.786);
75+
--color-neutral-content: oklch(98% 0 0);
76+
--color-info: oklch(62% 0.214 259.815);
77+
--color-info-content: oklch(97% 0.014 254.604);
78+
--color-success: oklch(70% 0.14 182.503);
79+
--color-success-content: oklch(98% 0.014 180.72);
80+
--color-warning: oklch(66% 0.179 58.318);
81+
--color-warning-content: oklch(98% 0.022 95.277);
82+
--color-error: oklch(58% 0.253 17.585);
83+
--color-error-content: oklch(96% 0.015 12.422);
84+
--radius-selector: 0.25rem;
85+
--radius-field: 0.25rem;
86+
--radius-box: 0.5rem;
87+
--size-selector: 0.21875rem;
88+
--size-field: 0.21875rem;
89+
--border: 1.5px;
90+
--depth: 1;
91+
--noise: 0;
92+
}
93+
94+
/* Add variants based on LiveView classes */
95+
@custom-variant phx-click-loading (.phx-click-loading&, .phx-click-loading &);
96+
@custom-variant phx-submit-loading (.phx-submit-loading&, .phx-submit-loading &);
97+
@custom-variant phx-change-loading (.phx-change-loading&, .phx-change-loading &);
98+
99+
/* Use the data attribute for dark mode */
100+
@custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *));
101+
102+
/* Make LiveView wrapper divs transparent for layout */
103+
[data-phx-session], [data-phx-teleported-src] { display: contents }
104+
105+
/* This file is for your main application CSS */

0 commit comments

Comments
 (0)