ShelterOS helps shelters manage the complete lifecycle of an animal — from rescue to forever home — in one clean, modern platform.
Rescue → Intake → Medical Care → Foster → Adoption
Animal shelters often run on spreadsheets, chats, and paper notes. Important details get lost, foster matching is manual, and staff spend too much time coordinating instead of caring for animals.
ShelterOS brings everything into one system:
- Staff get a full admin workspace for animals, medical records, fosters, adoptions, and analytics
- The public can browse animals and apply to foster or adopt
- AI helps match foster volunteers to the right animals with clear scores and reasons
Built with a focus on:
- Supporting animal shelters, rescues, and foster programs
- Improving animal adoption and matching
- Improving animal welfare and quality of life
- Create and manage animal records
- Track species, breed, age, gender, weight, personality, and description
- Upload photos and videos
- Assign unique animal IDs (e.g.
DOG-90128) - Manage status across the full pipeline:
rescuedintakemedicalfosteradoption_readyadopted
- Visual journey history for every animal
- Events like rescued, intake, vaccinated, medical checkup, fostered, and adopted
- Metadata support for location, people involved, reference codes, and notes
- Demo-friendly and useful for staff decisions
- Vaccination history
- Medications with dosage and frequency
- Conditions tracking
- Next checkup reminders
- Notes for veterinary observations
- Overdue checkup visibility on the dashboard
- Public foster applications
- Admin review of foster requests
- Status flow:
applied→ approved/active → completed/terminated - Foster profile data:
- experience level
- availability
- preferred species
- housing type
- kids / other pets
- activity preference
- special-needs experience
- AI match score stored with each request
- Public listing of adoption-ready animals
- Animal profile sheets with personality, health summary, and simplified timeline
- Adoption application flow
- Admin-side application tracking
Powered by Google Gemini
When a foster applies, ShelterOS:
- Reads the foster profile
- Reads the animal profile + latest medical conditions
- Generates a compatibility score from 0–100
- Returns:
- match score
- recommendation (
strong/moderate/weak/not_recommended) - summary
- strengths
- concerns
- suggested questions for staff
There is also batch recommendation scoring so logged-in fosters can see personalized “Recommended for You” animals without scoring one-by-one.
Admin dashboard includes:
Metric cards
- Animals in Shelter
- Ready for Adoption
- Pending Foster Requests
- Adoptions This Month
- Overdue Checkups
Charts
- Animals by status
- Activity over time
Operational panels
- Recent activity feed
- Needs attention:
- overdue medical checkups
- stale foster applications
- animals stuck in medical too long
Quick stats
- Active fosters
- Registered adopters
- Average days from intake to adoption
adminshelter_stafffoster_volunteeradopter
Role-based access controls what each user can view and do.
- Add a rescued animal
- Log intake + medical records
- Update timeline events
- Review foster / adoption applications
- Use AI match scores to approve the best foster
- Track shelter health from the dashboard
- Sign up with foster questionnaire
- Browse available animals
- See AI-recommended matches
- Apply to foster
- Wait for shelter review and contact
- Sign up as adopter
- Browse adoption-ready animals
- Open animal profile
- Submit adoption application
- React Router
- TypeScript
- Tailwind CSS
- shadcn/ui
- Recharts (dashboard charts)
- React Hook Form + Zod
- Fastify
- JWT authentication
- Role-based middleware
- Drizzle ORM
- PostgreSQL (Neon)
- Cloudinary (image/video upload + delete by
public_id)
- Google Gemini
- single foster-animal scoring
- batch recommendation scoring
apps/
admin/ # Admin Portal
web/ # Web
backend/ # Fastify backend
packages/
db/ # Drizzle schema + types
auth/ # JWT helpers
Foster experience is stored as a packed profile string, for example:
[experience:previous_foster][duration:1 month][species:both][housing:house_fenced][fencedYard:yes][activityLevel:medium][hasKids:no][hasOtherPets:dogs][specialNeeds:yes][maxAnimals:2]
The AI uses:
- foster experience tags
- availability
- location
- animal species/breed/age/personality
- latest medical conditions
Output example:
{
"matchScore": 87,
"recommendation": "strong",
"summary": "Strong fit based on dog preference and intermediate experience.",
"strengths": ["Has prior foster experience", "Fenced yard available"],
"concerns": ["May need support with high-energy training"],
"suggestedQuestions": ["Can you commit for at least 4 weeks?"]
}- Less operational chaos
- Clear animal status tracking
- Faster foster decisions
- Better visibility into bottlenecks
- Simple application flow
- Personalized recommendations
- Transparent animal profiles and journey history
- Better temporary care matches
- Smoother path to adoption
- Higher chance of the right home, not just any home
Possible next steps:
- Post-adoption follow-up tracking
- Lost-and-found / microchip integration
- SMS/email notification system
- Advanced adoption matching
- Multi-shelter support
- Mobile app for field intake
ShelterOS was built with a product mindset: fewer scattered tools, clearer workflows, and AI that supports human judgment instead of replacing it.
If shelters can move faster and match better, more animals get home.
- Node.js 24
- pnpm
- Docker & Docker Compose
- PostgreSQL (local or Neon)
git clone https://github.com/talha5978/shelter-os.git
cd shelter-os
pnpm installCopy the example env file and fill in your values:
cp .env.example .envTypical variables:
# Environment
NODE_ENV=development
VITE_ENV=development
# Backend Port
BACKEND_PORT=3000
# Apps and Backend URLs
ADMIN_URL=http://localhost:5173
WEB_URL=http://localhost:5174
API_BASE_URL=http://localhost:3000
# Database Connection
PG_CONNECTION_STRING=postgresql://xxxxxxxxxxxxxxxxxx
# JWT
JWT_SECRET=MAfqVePSUzVISF4ugE8BlKB14XXXXXXXXXXXXXX
JWT_EXPIRES_IN=1h
# Cloudinary Config
CLOUDINARY_CLOUD_NAME=xxxxxxxxxxxxxxxxxxxxxx
CLOUDINARY_API_KEY=xxxxxxxxxxxxxxxxxxxxxx
CLOUDINARY_API_SECRET=xxxxxxxxxxxxxxxxxxxxxx
# Gemini api
GEMINI_API_KEY=xxxxxxxxxxxxxxxxxxxFrom the monorepo root all migration files are given. Copy the commands and run in the postgres db editor or use:
pnpm db:pushIf you have change the database schema then run from the root:
pnpm db:generate
pnpm db:pushRun these commands from the root:
# Backend API
pnpm backend:dev
# Public website
pnpm web:dev
# Admin portal
pnpm admin:devDefault local ports (adjust if needed):
- Web:
http://localhost:5174 - Admin:
http://localhost:5173 - Backend:
http://localhost:3000
ShelterOS is a pnpm + Turborepo monorepo. All Docker images must be built from the repository root so shared packages and root config files are available.
- Docker
- Docker Compose
- A filled
.envfile in the project root
cp .env.example .envdocker build -f apps/admin/Dockerfile -t shelter-os-admin .docker build -f apps/web/Dockerfile -t shelter-os-web .docker build -f apps/backend/Dockerfile -t shelter-os-backend .docker rm -f shelter-os-admin 2>/dev/null || true
docker run --rm \
--env-file .env \
-p 3001:3001 \
--name shelter-os-admin \
shelter-os-adminOpen: http://localhost:3001
docker rm -f shelter-os-web 2>/dev/null || true
docker run --rm \
--env-file .env \
-p 3000:3000 \
--name shelter-os-web \
shelter-os-webOpen: http://localhost:3000
docker rm -f shelter-os-backend 2>/dev/null || true
docker run --rm \
--env-file .env \
-p 4000:4000 \
--name shelter-os-backend \
shelter-os-backendOpen: http://localhost:4000
Make sure docker-compose.yml exists in the repo root:
Start everything:
docker compose up --buildStop:
docker compose downEach app Dockerfile should copy these root files:
package.jsonpnpm-lock.yamlpnpm-workspace.yamlturbo.jsontsconfig.json
And these workspace packages:
packages/dbpackages/auth
Example admin build command used in Docker:
pnpm admin:buildExample admin start command:
pnpm admin:start| Service | URL |
|---|---|
| Public Web | http://localhost:3000 |
| Admin Portal | http://localhost:3001 |
| Backend API | http://localhost:4000 |
- Always build from the monorepo root, not from
apps/adminorapps/web - Make sure
.envcontains all the valid values - If Turbo fails inside Docker, confirm
turbo.jsonis copied - If TypeScript fails inside Docker, confirm root
tsconfig.jsonis copied