Skip to content

c0dewhacker/Roomer

Repository files navigation

Roomer

Self-hosted workspace booking — desks, assets, and floor plans, fully under your control.

License: ELv2 Docker GitHub Actions Workflow Status


What is Roomer?

Roomer is a self-hosted platform for managing desk and asset reservations across offices, buildings, and floors. Upload floor plans, place bookable assets on a canvas, and let your team book space — without handing your occupancy data to a third-party SaaS.


Features

Floor plan editor Upload image, PDF or DXF floor plans and place assets on an interactive canvas
Desk & asset booking Book by date with live availability (available, booked, assigned, queued, restricted)
Permanent assignments Assign desks to users with primary/secondary ownership; bulk-assign via CSV
Zone management Group assets into colour-coded zones with optional conflict rules
Building & floor management Building admins and floor managers for delegated admin without full super-admin access
Queue & waitlist Users join a waitlist and are automatically promoted when a desk frees up
Bulk CSV import Import buildings, floors, zones, and assets in a single pass
Asset registry Track non-bookable inventory (laptops, monitors, etc.) alongside bookable space
Role-based access Super admin, building admin, floor manager, and user roles
Multi-provider login Local, LDAP, OIDC, and SAML — mix providers with a configurable default and URL overrides
SCIM 2.0 provisioning Automated user and group sync from Okta, Azure AD / Entra ID, OneLogin, etc.
Email notifications Booking confirmations and queue promotions via SMTP

Roomer-demo


Quick Start (Docker)

The fastest way to run Roomer is with the pre-built Docker images.

1. Create a .env file in the project root:

SESSION_SECRET=<run: openssl rand -hex 32>
APP_ORIGIN=http://localhost
COOKIE_SECURE=false
WEB_PORT=80
EMAIL_FROM=noreply@roomer.local

# Admin account credentials (see "Seeding" below)
SEED_ADMIN_EMAIL=admin@roomer.local
SEED_ADMIN_PASSWORD=changeme

2. Start everything:

docker compose up -d

The web app will be at http://localhost (or WEB_PORT if changed). The API container automatically runs prisma migrate deploy on startup, then seeds the admin account on first run.

Find the admin password: the seed step prints it to the API logs:

docker compose logs api | grep "seed"

If SEED_ADMIN_PASSWORD is not set, a random password is generated and logged there. Set it in your .env to use a known password.

3. (Optional) Seed demo buildings and desks:

Add SEED_DEMO_DATA=true to your .env (before first start, or re-run the seed manually):

docker compose exec api npx prisma db seed

This adds a sample building ("Acme HQ") with a floor, two zones, and six desks, plus a regular test user (user@roomer.local). Change all passwords after first login.

Docker Compose environment variables

Variable Default Description
SESSION_SECRET Required. 32+ character random string.
APP_ORIGIN http://localhost Public URL used in CORS and email links.
COOKIE_SECURE false Set to true when serving over HTTPS.
WEB_PORT 80 Host port for the web container.
EMAIL_FROM noreply@roomer.local Sender address for system emails.
SEED_ADMIN_EMAIL admin@roomer.local Email for the super-admin account created on first seed.
SEED_ADMIN_PASSWORD (random) Password for the super-admin account. If unset, a random password is generated and printed to the API container logs.
SEED_DEMO_DATA false Set to true to seed demo buildings, floors, desks and a test user on first start.
SEED_USER_PASSWORD (random) Password for the demo test user (user@roomer.local). Only used when SEED_DEMO_DATA=true.

Build from source

docker compose -f docker-compose.build.yaml up --build

Docker images

Image Description
c0dewhacker/roomer-api Multi-stage Node 24 Alpine. Runs migrations then starts Fastify.
c0dewhacker/roomer-web Multi-stage Vite build served by nginx 1.27. Proxies /api to the API.

Both images are built from the monorepo root so they can access packages/shared.


Stack

Layer Technology
API Fastify + TypeScript
Database PostgreSQL 18 + Prisma ORM
Frontend React 18 + Vite + Tailwind CSS + shadcn/ui
Canvas Konva (react-konva)
Job queue pg-boss (PostgreSQL-backed)
Monorepo pnpm workspaces + Turborepo

Development Setup

Prerequisites

  • Node.js v24+ (required by Prisma 7)
  • pnpm v10+ — npm install -g pnpm@10
  • Docker and Docker Compose

1. Clone and install

git clone https://github.com/c0dewhacker/Roomer.git roomer
cd roomer
pnpm install

2. Start infrastructure

docker compose up -d

This starts PostgreSQL and Mailpit (local SMTP catcher for dev email):

Service URL Notes
PostgreSQL localhost:5435 User/pass/db: roomer
Mailpit SMTP localhost:1025 Dev email relay
Mailpit Web http://localhost:8025 View outbound email

3. Configure the API

Create apps/api/.env:

# Required
DATABASE_URL=postgresql://roomer:roomer@localhost:5435/roomer
SESSION_SECRET=<openssl rand -hex 32>

# Defaults — override as needed
NODE_ENV=development
PORT=3001
CORS_ORIGIN=http://localhost:5173

# Email (matches Mailpit defaults above)
SMTP_HOST=localhost
SMTP_PORT=1025
SMTP_SECURE=false
EMAIL_FROM=noreply@roomer.local
APP_URL=http://localhost:5173

# Seed credentials — set these before running db:seed so you know the password.
# If SEED_ADMIN_PASSWORD is omitted, a random password is generated and printed to stdout.
SEED_ADMIN_EMAIL=admin@roomer.local
SEED_ADMIN_PASSWORD=admin123
SEED_DEMO_DATA=true

4. Migrate and seed

pnpm --filter api db:migrate   # apply migrations
pnpm --filter api db:seed      # seed demo data

With the .env values above, the seed creates:

Resource Value
Admin login admin@roomer.local / admin123 (from your .env)
Organisation Acme Corp (renamed when SEED_DEMO_DATA=true)
Building Acme HQ with Ground Floor — 6 sample desks across two zones
Test user user@roomer.local (password from SEED_USER_PASSWORD, or logged if unset)

Without SEED_DEMO_DATA=true, only the admin account and a blank organisation ("My Organisation") are created.

5. Start dev servers

pnpm dev                      # both apps via Turborepo
# or individually:
pnpm --filter api dev          # API  → http://localhost:3001
pnpm --filter web dev          # Web  → http://localhost:5173

Open http://localhost:5173 and sign in with admin@roomer.local / admin123.


Production Deployment

The Docker images are production-ready as-is. Key checklist:

  • Set COOKIE_SECURE=true and serve over HTTPS
  • Set APP_ORIGIN to your public domain (e.g. https://roomer.example.com)
  • Set API_PUBLIC_URL to your public API URL if different from APP_ORIGIN (used for SCIM endpoint links)
  • Use a managed PostgreSQL instance by overriding DATABASE_URL in the API environment
  • Mount a persistent volume at /app/uploads for floor plan storage (already in docker-compose.yml)
  • For horizontal API scaling, point FILE_STORAGE_PATH at shared network storage rather than a local volume

API Reference

The REST API runs on port 3001 by default.

  • Swagger UI: http://localhost:3001/docs (enabled in development; set SWAGGER_ENABLED=true to enable in production)
  • All routes are prefixed /api/v1
Prefix Description
/api/v1/auth Login, logout, session, enterprise SSO (OIDC/SAML/LDAP)
/api/v1/buildings Buildings CRUD, managers, access groups
/api/v1/floors Floors, zones, floor plan upload, availability
/api/v1/assets Asset registry, bookable desks, user assignments, bulk assignment CSV
/api/v1/bookings Booking lifecycle
/api/v1/queue Waitlist management
/api/v1/import/bulk Global CSV bulk import
/api/v1/users User management
/api/v1/groups Group management
/api/v1/settings Organisation settings, auth provider config, SCIM provisioning
/scim/v2 SCIM 2.0 provisioning (separate prefix, bearer token auth)

Configuration Reference

All API environment variables:

Variable Default Description
DATABASE_URL PostgreSQL connection string (required)
SESSION_SECRET Cookie signing secret, min 32 chars (required)
PORT 3001 API listen port
HOST 0.0.0.0 API bind address
CORS_ORIGIN http://localhost:5173 Allowed frontend origin
COOKIE_SECURE false in dev Require HTTPS for session cookies
TRUST_PROXY false in dev Trust X-Forwarded-For headers
ALLOW_BEARER_AUTH true in dev Accept Authorization: Bearer tokens
SWAGGER_ENABLED true in dev Expose Swagger UI at /docs
FILE_STORAGE_PATH ./uploads Directory for floor plan images
MAX_FILE_SIZE_MB 20 Maximum upload size
API_PUBLIC_URL http://localhost:3001 Public URL of the API — shown in the SCIM settings panel as the endpoint base URL
SMTP_HOST localhost Outbound email relay host
SMTP_PORT 1025 Outbound email relay port
SMTP_SECURE false Use TLS for SMTP
SMTP_USER SMTP username (if required)
SMTP_PASS SMTP password (if required)
EMAIL_FROM noreply@roomer.local Sender address for system emails
APP_URL http://localhost:5173 Public URL used in email links

Roles

Role Scope Permissions
SUPER_ADMIN Global Full access to all resources and settings
BUILDING_ADMIN Per building Superset of floor manager for every floor in the building (full implementation in progress)
FLOOR_MANAGER Per floor Manage zones, assets, and bookings on assigned floors
USER Global Book available assets, manage own bookings

Available Scripts

Run from the monorepo root:

Command Description
pnpm dev Start all apps in development mode
pnpm build Build all apps for production
pnpm lint Lint all packages
pnpm --filter api db:migrate Run pending Prisma migrations
pnpm --filter api db:seed Seed demo data
pnpm --filter api db:studio Open Prisma Studio (database browser)

Project Structure

roomer/
├── apps/
│   ├── api/              # Fastify REST API
│   │   ├── prisma/       # Schema, migrations, seed
│   │   └── src/
│   │       ├── routes/
│   │       ├── middleware/
│   │       └── lib/
│   └── web/              # React SPA
│       └── src/
│           ├── components/
│           ├── pages/
│           ├── hooks/
│           └── stores/
├── packages/
│   └── shared/           # Shared types and Zod schemas
├── docker-compose.yml        # Pull pre-built images
├── docker-compose.build.yaml # Build from source
└── turbo.json

License

Roomer is licensed under the Elastic License 2.0.

In short: you can use, modify, and self-host Roomer freely — including for commercial internal use. You may not provide Roomer as a managed hosted service to third parties (i.e. you cannot run a Roomer-as-a-Service business).

See the LICENSE file for the full terms.

About

Roomer is a self-hosted platform for managing desk and asset reservations across offices, buildings, and floors. Upload floor plans, place bookable assets on a canvas, and let your team book space — without handing your occupancy data to a third-party SaaS.

Topics

Resources

License

Stars

Watchers

Forks

Contributors

Languages