audio streaming app
plyr.fm
1---
2title: "local development setup"
3---
4
5## prerequisites
6
7- **python**: 3.11+ (managed via `uv`)
8- **node/bun**: for frontend development
9- **postgres**: local database (optional - can use neon dev instance)
10- **ffmpeg**: for transcoder development (optional)
11
12## quick start
13
14```bash
15# clone repository
16gh repo clone zzstoatzz/plyr.fm
17cd plyr.fm
18
19# install python dependencies
20uv sync
21
22# install frontend dependencies
23cd frontend && bun install && cd ..
24
25# copy environment template
26cp .env.example .env
27# edit .env with your credentials
28
29# run backend
30uv run uvicorn backend.main:app --reload --host 0.0.0.0 --port 8001
31
32# run frontend (separate terminal)
33cd frontend && bun run dev
34```
35
36visit http://localhost:5173 to see the app.
37
38## environment configuration
39
40### required environment variables
41
42create a `.env` file in the project root:
43
44```bash
45# database (use neon dev instance or local postgres)
46DATABASE_URL=postgresql+asyncpg://localhost/plyr # local
47# DATABASE_URL=<neon-dev-connection-string> # neon dev
48
49# oauth (uses client metadata discovery - no registration required)
50ATPROTO_CLIENT_ID=http://localhost:8001/oauth-client-metadata.json
51ATPROTO_CLIENT_SECRET=<your-client-secret>
52ATPROTO_REDIRECT_URI=http://localhost:5173/auth/callback
53OAUTH_ENCRYPTION_KEY=<base64-encoded-32-byte-key>
54
55# storage (r2 or filesystem)
56STORAGE_BACKEND=filesystem # or "r2" for cloudflare r2
57R2_BUCKET=audio-dev
58R2_PRIVATE_BUCKET=audio-private-dev # for supporter-gated content
59R2_IMAGE_BUCKET=images-dev
60R2_ENDPOINT_URL=<your-r2-endpoint>
61R2_PUBLIC_BUCKET_URL=<your-r2-public-url>
62R2_PUBLIC_IMAGE_BUCKET_URL=<your-r2-image-public-url>
63AWS_ACCESS_KEY_ID=<your-r2-access-key>
64AWS_SECRET_ACCESS_KEY=<your-r2-secret>
65
66# optional: observability
67LOGFIRE_ENABLED=false # set to true to enable
68LOGFIRE_WRITE_TOKEN=<your-token>
69LOGFIRE_ENVIRONMENT=development
70
71# optional: notifications
72NOTIFY_ENABLED=false
73```
74
75### generating oauth encryption key
76
77```bash
78python -c "import base64, os; print(base64.b64encode(os.urandom(32)).decode())"
79```
80
81## database setup
82
83### option 1: use neon dev instance (recommended)
84
851. get dev database URL from neon console or `.env.example`
862. set `DATABASE_URL` in `.env`
873. run migrations: `uv run alembic upgrade head`
88
89### option 2: local postgres
90
91```bash
92# install postgres
93brew install postgresql@15 # macos
94# or use docker
95
96# create database
97createdb plyr
98
99# run migrations
100DATABASE_URL=postgresql+asyncpg://localhost/plyr uv run alembic upgrade head
101```
102
103## running services
104
105### backend
106
107```bash
108# standard run
109uv run uvicorn backend.main:app --reload
110
111# with custom port
112uv run uvicorn backend.main:app --reload --port 8001
113
114# with host binding (for mobile testing)
115uv run uvicorn backend.main:app --reload --host 0.0.0.0 --port 8001
116```
117
118backend api docs: http://localhost:8001/docs
119
120### frontend
121
122```bash
123cd frontend
124
125# development server
126bun run dev
127
128# custom port
129PORT=5174 bun run dev
130
131# expose to network (for mobile testing)
132bun run dev -- --host
133```
134
135frontend: http://localhost:5173
136
137### transcoder (optional)
138
139```bash
140cd transcoder
141
142# install rust toolchain if needed
143rustup update
144
145# install ffmpeg
146brew install ffmpeg # macos
147
148# run transcoder
149cargo run
150
151# with custom port
152TRANSCODER_PORT=9000 cargo run
153
154# with debug logging
155RUST_LOG=debug cargo run
156```
157
158transcoder: http://localhost:8080
159
160## development workflow
161
162### making backend changes
163
1641. edit code in `src/backend/`
1652. uvicorn auto-reloads on file changes
1663. test endpoints at http://localhost:8001/docs
1674. check logs in terminal
168
169### making frontend changes
170
1711. edit code in `frontend/src/`
1722. vite auto-reloads on file changes
1733. view changes at http://localhost:5173
1744. check console for errors
175
176### creating database migrations
177
178```bash
179# make model changes in src/backend/models/
180
181# generate migration
182uv run alembic revision --autogenerate -m "description"
183
184# review generated migration in alembic/versions/
185
186# apply migration
187uv run alembic upgrade head
188
189# test downgrade
190uv run alembic downgrade -1
191uv run alembic upgrade head
192```
193
194migrations are managed with alembic — see `alembic/versions/` for existing migrations.
195
196### running tests
197
198```bash
199# all tests
200uv run pytest
201
202# specific test file
203uv run pytest tests/api/test_tracks.py
204
205# with verbose output
206uv run pytest -v
207
208# with coverage
209uv run pytest --cov=backend
210
211# watch mode (re-run on changes)
212uv run pytest-watch
213```
214
215## mobile testing
216
217to test on mobile devices on your local network:
218
219### 1. find your local ip
220
221```bash
222# macos/linux
223ifconfig | grep "inet " | grep -v 127.0.0.1
224
225# windows
226ipconfig
227```
228
229### 2. run backend with host binding
230
231```bash
232uv run uvicorn backend.main:app --reload --host 0.0.0.0 --port 8001
233```
234
235### 3. run frontend with network exposure
236
237```bash
238cd frontend && bun run dev -- --host
239```
240
241### 4. access from mobile
242
243- backend: http://<your-ip>:8001
244- frontend: http://<your-ip>:5173
245
246## troubleshooting
247
248### backend won't start
249
250**symptoms**: `ModuleNotFoundError` or import errors
251
252**solutions**:
253```bash
254# reinstall dependencies
255uv sync
256
257# check python version
258uv run python --version # should be 3.11+
259
260# verify environment
261uv run python -c "from backend.main import app; print('ok')"
262```
263
264### database connection errors
265
266**symptoms**: `could not connect to server` or SSL errors
267
268**solutions**:
269```bash
270# verify DATABASE_URL is set
271echo $DATABASE_URL
272
273# test connection
274uv run python -c "from backend.config import settings; print(settings.database.url)"
275
276# check postgres is running (if local)
277pg_isready
278
279# verify neon credentials (if remote)
280# check neon console for connection string
281```
282
283### frontend build errors
284
285**symptoms**: `module not found` or dependency errors
286
287**solutions**:
288```bash
289# reinstall dependencies
290cd frontend && rm -rf node_modules && bun install
291
292# clear cache
293rm -rf frontend/.svelte-kit
294
295# check node version
296node --version # should be 18+
297bun --version
298```
299
300### oauth redirect errors
301
302**symptoms**: `invalid redirect_uri` or callback errors
303
304**solutions**:
305```bash
306# verify ATPROTO_REDIRECT_URI matches frontend URL
307# should be: http://localhost:5173/auth/callback
308
309# check ATPROTO_CLIENT_ID is accessible (should return client metadata JSON)
310curl http://localhost:8001/oauth-client-metadata.json
311```
312
313### r2 upload failures
314
315**symptoms**: `failed to upload to R2` or storage errors
316
317**solutions**:
318```bash
319# verify credentials
320echo $AWS_ACCESS_KEY_ID
321echo $AWS_SECRET_ACCESS_KEY
322echo $R2_BUCKET
323
324# test r2 connectivity
325uv run python -c "
326from backend.storage import get_storage_backend
327storage = get_storage_backend()
328print(storage.bucket_name)
329"
330
331# or use filesystem backend for local development
332STORAGE_BACKEND=filesystem uv run uvicorn backend.main:app --reload
333```
334
335## useful commands
336
337```bash
338# backend
339uv run uvicorn backend.main:app --reload # start backend
340uv run pytest # run tests
341uv run alembic upgrade head # run migrations
342uv run python -m backend.utilities.cli # admin cli
343
344# frontend
345cd frontend && bun run dev # start frontend
346cd frontend && bun run build # build for production
347cd frontend && bun run preview # preview production build
348cd frontend && bun run check # type check
349
350# transcoder
351cd services/transcoder && cargo run # start transcoder
352cd services/transcoder && cargo test # run tests
353cd services/transcoder && cargo build --release # build for production
354```
355
356## next steps
357
358- read [contributing](/contributing/) for code style and workflow conventions
359- check [deployment environments](/deployment/environments/) when ready to deploy