- Add permissions logic for status options in corrective actions. - Create tests for permissions functionality. - Implement queries for user authentication and actions management. - Develop Actions page to display and manage corrective actions. - Create authentication pages for login, setup, and password reset. - Add IncidentDetail page to view incident details and associated actions. - Implement Settings page for user management and password changes.
Open SafetyLog EHS
Free, open-source accident and safety tracking for manufacturing: incident and near-miss reporting, investigations, corrective actions and (planned) OSHA record keeping.
Status: early development (Phases 0–2 done). Reporting, investigation, corrective actions, email notifications, dashboards and CSV export work end to end. OSHA record keeping and offline shop-floor reporting are next. See docs/ROADMAP.md for the plan and docs/TODO.md for open items.
Getting started
Requires Node.js 22.18 or later (see .nvmrc). No database install is needed for development: the server uses embedded PostgreSQL (PGlite) stored in ./data/.
npm install
npm run db:seed # optional: demo organization, sites, users and incidents
npm run dev # web app on http://localhost:5173, API on http://localhost:3000
Demo users (after seeding): admin@example.com, manager@example.com, supervisor@example.com and reporter@example.com, all with password safetylog-demo. Without seeding, opening the app takes you to first-run setup.
In development, emails (sign-in links, invitations, notifications) are printed in the terminal running the server.
Settings are read from environment variables or a .env file; see .env.example.
Running in production
cp .env.example .env # set POSTGRES_PASSWORD, and PUBLIC_URL if not localhost
docker compose up -d --build
This runs the app and PostgreSQL. The app applies database migrations on startup and serves the web app and API on port 3000. Uploaded photos are kept in the app-data volume.
- Use HTTPS (for example behind a reverse proxy) and set
PUBLIC_URLto thehttps://address so session cookies are marked secure and email links point to the right place. - Set
SMTP_URLandMAIL_FROMso sign-in links, invitations and notifications are delivered. - Set
TZto the plant's time zone (e.g.America/Chicago) so due dates and daily reminders follow local days. - Back up both volumes:
db-data(PostgreSQL) andapp-data(uploads).
For a very small single-machine install, the app image also runs on its own with embedded PostgreSQL: docker run -p 3000:3000 -v safetylog-data:/app/data <image>.
Scripts
| Command | What it does |
|---|---|
npm run dev |
Start the web app and API together with auto-reload |
npm start |
Start the API server (serves dist/ too when built) |
npm run build |
Production build to dist/ |
npm run lint |
Lint with Oxlint (warnings fail) |
npm run typecheck |
Type-check with TypeScript |
npm test |
Web and server tests (Vitest; server tests use an in-memory database) |
npm run db:generate |
Create a migration after changing server/db/schema.ts |
npm run db:seed |
Load demo data into an empty database |
npm run test:e2e |
End-to-end tests (Playwright, desktop and mobile). Run npx playwright install chromium once first |
npm run check |
Lint, typecheck, test and build in one go |
CI runs the same checks on every push and pull request (.gitea/workflows/ci.yml).
Project layout
src/ Web app (React)
pages/ One component per route
components/ Shared UI (layout, tables, form pieces) and shared class strings in styles.ts
lib/ Types, domain logic, demo data; no React components
index.css Tailwind import and design tokens (@theme)
server/ API (Hono on Node)
routes/ One file per resource, with its tests alongside
auth/ Passwords, sessions, permissions
db/ Drizzle schema, migrations, seed script
shared/ Enums and validation schemas used by both
e2e/ Playwright tests
docs/ Roadmap, to-do list, API reference
Styling is Tailwind CSS v4. Colors, fonts and small text sizes are defined as theme tokens in src/index.css. Fonts are bundled through Fontsource, so the app makes no third-party requests and works on isolated plant networks.
Contributing
See CONTRIBUTING.md. Everyone taking part follows our Code of Conduct.
License
GNU Affero General Public License v3.0. If you run a modified version as a network service, you must offer its source code to its users. The app's About page links to the source; set VITE_SOURCE_URL at build time to point it at your fork.