5.1 KiB
Homarr Workshop
Workshop is a small PocketBase service that serves the public documentation site and stores one Custom JSX v2 widget per submission.
The runtime image extends ghcr.io/muchobien/pocketbase:0.39; Homarr adds only the built documentation, PocketBase
collections, API rules, and its explicit serve arguments.
It intentionally has no approval queue, user bans, moderator roles, reusable widget connections, or remote control over
installed widgets. Submissions publish immediately. Authenticated users can vote, comment, and report; users with
isAdmin enabled can dismiss reports or delete any submission or comment.
Local development
pnpm docker:workshop
Use docker compose -f apps/workshop/docker-compose.yml logs -f workshop for logs and
docker compose -f apps/workshop/docker-compose.yml stop workshop to stop it without deleting data.
Compose passes the selected port to PocketBase as PORT, so it listens on the same port inside and outside the
container. With the image directly, set both values: docker run -e PORT=3003 -p 3003:3003 <workshop-image>.
Open http://127.0.0.1:18090/_/, create the first PocketBase superuser, and configure GitHub OAuth on the users collection.
The users.isAdmin field defaults to false. Collection rules allow account creation only through OAuth without that
field and reject all regular-user attempts to change it. Appoint administrators out of band with a PocketBase
superuser or a deliberate SQLite update; there is no public role-management endpoint or hook.
Users must sign in again after the role changes. Setting the value back to false removes Workshop administrator access.
The GitHub OAuth application needs one callback for the Workshop host:
https://<workshop-host>/api/oauth2-redirect
Self-hosted Homarr origins do not need to be registered with GitHub. Keep PB_ALLOWED_ORIGINS=* (the default) so localhost and arbitrary self-hosted domains can open the central PocketBase OAuth popup. Set a restricted origin list only if it includes every Homarr origin that should use Workshop sign-in.
Set GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET in the repository-root .env. Set
WORKSHOP_PUBLIC_ORIGIN=https://<workshop-host> so notification emails link to the public Workshop. Configure the sender
and SMTP transport in PocketBase. PocketBase emails the submission author about new comments, emails every current
Workshop administrator about a new report, and emails the author after an administrator deletes their submission. Mail
failures are logged and never reject a comment, report, or deletion.
Run the disposable service integration test from the repository root:
pnpm test:workshop
The test uses a separate Compose project and deletes its named volume on exit. It never writes fixture users or admin
roles into the normal homarr-workshop_pb_data volume.
The Workshop does not maintain a second Custom Widget schema. Its frontend validates submissions with
customWidgetImportSchema from @homarr/custom-widgets, and Homarr validates canonical content again before installation.
The validated $schema is also stored as widgetSchema for listing compatibility badges; it must match the downloaded
manifest before Homarr enables installation.
PocketBase API rules enforce submission and comment ownership, one vote/report per user and submission, and
administrator-only moderation. Each new submission receives one real author-owned upvote. Reports are private to
administrators and are dismissed by changing their status. PocketBase cascade deletion removes related votes, comments,
and reports when a submission is deleted. Authors and administrators can mark a submission outdated without making it
un-installable.
Production docs preview
Build the documentation and serve it from PocketBase using the same production image layout as the hosted Workshop:
pnpm docker:docs
Open http://127.0.0.1:3003. Set DOCS_EXPOSE_PORT to use another host port. PocketBase data persists in the
homarr-workshop_pb_data named volume.
Point a local Homarr checkout at it with:
WORKSHOP_API_URL=http://127.0.0.1:3003 pnpm dev
The production Homarr image reads the same variable when the container starts:
docker run -p 7575:7575 -e WORKSHOP_API_URL=http://127.0.0.1:3003 <homarr-image>
This command starts the profiled docs service from apps/workshop/docker-compose.yml. It does not start the development workshop service. Stop and remove the preview with:
docker compose -f apps/workshop/docker-compose.yml --profile docs rm --stop --force docs
Normal startup never deletes data. To intentionally recreate the local database, stop the stack first and then run:
docker compose -f apps/workshop/docker-compose.yml down --volumes
PocketBase data lives in /pb_data. Docker Compose persists it in the pb_data named volume for both the development Workshop service and the production documentation/Workshop service. The image serves the built Homarr documentation and Workshop UI from /pb_public.
At startup the container repairs ownership of existing data volumes, then runs PocketBase as its non-root user.