Open source pet hotel management system. Clone it, run it, own your data.
No cloud subscriptions. No external APIs. All data stays on your machine.
- Reservations — multi-step booking flow with check-in/check-out management
- Tutors & Animals — full registration with vaccination file uploads
- Digital Contracts — auto-generated PDF with unique token per booking
- Digital Signatures — mobile-first canvas (touch + mouse + retina support)
- Authenticity Verification — SHA-256 hash + QR Code on every signed contract
- Dashboard — KPIs and occupancy overview
- Calendar — visual availability and blocked dates
- Services — configurable services and pricing
- Settings & Onboarding — hotel branding, name, logo
- Bilingual — Portuguese and English interface
- Dark / Light mode
- Versioned migrations — schema updates never corrupt existing data
- Automatic daily backup —
db.jsonbacked up automatically
| Layer | Technology |
|---|---|
| Backend | Node.js 18+ · Express · PDFKit · QRCode |
| Frontend | React 18 · Vite · TypeScript · Tailwind CSS v3 |
| Storage | Local db.json (no database required) |
| Auth | None (single-tenant, local network) |
- Node.js 18 or higher
- npm 9 or higher
- Git
# Clone the repository
git clone https://github.com/Viniciusap/petstay-manager.git
cd petstay-manager
# Install all dependencies (root + backend + frontend)
npm run install:all
# Copy environment file and adjust if needed
cp .env.example .env
# Start both servers
npm run dev- Backend: http://localhost:3001
- Frontend: http://localhost:5173
On first run, migrations execute automatically and create /backend/data/db.json.
Copy .env.example to .env and adjust as needed:
cp .env.example .env| Variable | Default | Description |
|---|---|---|
PORT |
3001 |
Backend port |
FRONTEND_URL |
http://localhost:5173 |
CORS allowed origin — set to your frontend URL |
NODE_ENV |
development |
Environment |
| Variable | Default | Description |
|---|---|---|
BACKEND_URL |
http://localhost:3001 |
Where Vite proxies API calls — set to your backend URL |
PORT |
5173 |
Frontend dev server port |
Running on a local network or custom host? Set both variables so each side knows where the other is:
# .env
PORT=3001
FRONTEND_URL=http://192.168.1.10:5173
NODE_ENV=development
BACKEND_URL=http://192.168.1.10:3001Then access the app from any device on the network at http://192.168.1.10:5173.
petstay-manager/
├── backend/
│ └── src/
│ ├── routes/ # REST API endpoints
│ ├── middleware/ # Validation, error handling, CORS
│ ├── migrations/ # Versioned schema migrations
│ └── utils/ # PDF, backup, hash, db helpers
├── frontend/
│ └── src/
│ ├── components/ # UI design system + signing canvas
│ ├── pages/ # All app pages
│ ├── contexts/ # Theme, Toast, Translation
│ └── i18n/ # PT and EN translation files
├── docs/ # Extra documentation
├── .env.example
├── CHANGELOG.md
└── CONTRIBUTING.md
backend/data/is listed in.gitignoreand never committed — your data stays local.
# Pull new code (never touches /backend/data)
git pull origin main
# Install any new dependencies
npm run install:all
# Restart — migrations run automatically
npm run devSchema migrations are versioned and incremental. Existing data is always preserved.
- Booking created → contract token generated
- Admin shares signing link with tutor (e.g. via WhatsApp)
- Tutor opens link on mobile → reads contract → signs on canvas
- Signature saved as PNG → final PDF generated with signature + QR Code
- SHA-256 hash stored for authenticity verification
- Anyone can verify a contract at
/verify/:token
Two supported deployment options. Choose based on your needs:
| Option A — Railway | Option B — Vercel full-stack | |
|---|---|---|
| Storage | Local db.json + disk |
Vercel Postgres + Vercel Blob |
| Complexity | Low | Medium |
| Free tier | Railway Hobby plan | Vercel + Postgres + Blob free tiers |
| Data location | Your server volume | Vercel infrastructure |
No database setup required. Data stays in a file on your server.
1. Deploy the backend on Railway
- Connect your repo, set root directory to
backend - Start command:
node src/index.js - Add a persistent volume mounted at
/app/data - Set environment variables:
PORT=3001 FRONTEND_URL=https://your-app.vercel.app NODE_ENV=production STORAGE_ADAPTER=local
2. Deploy the frontend on Vercel
- Connect your repo, set root directory to
frontend - Build command:
npm run build· Output:dist - Add environment variable:
VITE_API_URL=https://petstay-backend.railway.app
3. Set the signing link base URL
In the app settings page, set Base URL to your Vercel frontend URL. This is embedded in QR Codes on signed contracts.
Runs entirely on Vercel. No external servers needed.
- A Vercel account (free tier works)
- This repo pushed to GitHub
- Go to vercel.com/new
- Click Add New Project → Import Git Repository
- Select your fork/copy of this repo
- Important: leave the root directory as
/(do not change tofrontendorbackend) — thevercel.jsonat the root handles everything - Click Deploy (it will fail the first time — that's expected, storage isn't configured yet)
- In your Vercel project → Storage tab → Create Database
- Select Postgres → give it a name (e.g.
petstay-db) → Create - Click Connect to Project — Vercel automatically adds
POSTGRES_URLand related variables to your environment
- In Storage tab → Create Database again
- Select Blob → give it a name (e.g.
petstay-files) → Create - Click Connect to Project — Vercel automatically adds
BLOB_READ_WRITE_TOKEN
In your project → Settings → Environment Variables, add:
| Variable | Value |
|---|---|
STORAGE_ADAPTER |
vercel |
NODE_ENV |
production |
FRONTEND_URL |
https://your-app.vercel.app (your actual Vercel URL) |
TRUST_PROXY |
1 |
POSTGRES_URLandBLOB_READ_WRITE_TOKENare already set automatically by Vercel in Steps 2–3.
- Go to the Deployments tab
- Click the three-dot menu on the latest deployment → Redeploy
- Wait for the build to finish — the app will be live at your Vercel URL
Open the app. On first load, the backend creates all database tables automatically. Go through the onboarding wizard to configure your hotel name, logo, and settings.
In Settings → Base URL, enter your Vercel URL (e.g. https://your-app.vercel.app). This is embedded in QR Codes on every signed contract so clients can verify authenticity.
Note: the Vercel free tier has limits — 100GB Blob storage, 256MB Postgres, 100GB-hours of serverless compute per month. For a single pet hotel, this is more than enough.
| Variable | Default | Where | Purpose |
|---|---|---|---|
STORAGE_ADAPTER |
local |
backend | local or vercel |
PORT |
3001 |
backend | Backend port |
FRONTEND_URL |
http://localhost:5173 |
backend | CORS allowed origin |
NODE_ENV |
development |
backend | Environment |
TRUST_PROXY |
(unset) | backend | Set to 1 behind a reverse proxy (Vercel, Railway) |
POSTGRES_URL |
(unset) | backend | Required when STORAGE_ADAPTER=vercel |
BLOB_READ_WRITE_TOKEN |
(unset) | backend | Required when STORAGE_ADAPTER=vercel |
BACKEND_URL |
http://localhost:3001 |
root .env |
Vite dev proxy target (dev only) |
VITE_API_URL |
(unset) | frontend build | Absolute backend URL for production builds |
See CONTRIBUTING.md for full guidelines.
Quick rules:
- Any
db.jsonschema change requires a migration in/backend/src/migrations/ - All UI strings must use
t('key')— no hardcoded text in components - Follow Conventional Commits
- Branch from
main, open a PR with description of what changed and why
Local adapter (default): all data stays in /backend/data/db.json on your own machine or server. Nothing is sent to external services. Each hotel instance is fully independent.
Vercel adapter: data is stored in your own Vercel Postgres database and Vercel Blob store, linked to your Vercel account. No third-party services outside of Vercel are involved.
Uploaded files (vaccination proofs, signatures, PDFs) go to /backend/data/ locally or to your Vercel Blob store when using the Vercel adapter.
MIT — free to use, modify, and distribute.