feat(kiosk): implement kiosk report submission functionality with offline support test(outbox): add tests for outbox functionality including report submission and error handling feat(outbox): create outbox management for queued reports with IndexedDB persistence feat(uuid): add UUID generation utility for client IDs feat(qr): implement QR code generation for reporting links by site and area feat(kiosk): create Kiosk page for reporting incidents without an account
89 lines
5.1 KiB
Markdown
89 lines
5.1 KiB
Markdown
# 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–3 done).** Reporting (including offline, kiosk tablets, QR codes and Spanish), investigation, corrective actions, email notifications, dashboards and CSV export work end to end. OSHA record keeping is next. See [docs/ROADMAP.md](docs/ROADMAP.md) for the plan and [docs/TODO.md](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/`.
|
||
|
||
```sh
|
||
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](.env.example).
|
||
|
||
## Running in production
|
||
|
||
```sh
|
||
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_URL` to the `https://` address so session cookies are marked secure and email links point to the right place.
|
||
- Set `SMTP_URL` and `MAIL_FROM` so sign-in links, invitations and notifications are delivered.
|
||
- Set `TZ` to 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) and `app-data` (uploads).
|
||
- Installing the app on phones and opening it offline needs HTTPS (browsers require it for service workers). Over plain HTTP everything else works, and reports made while offline are still queued once the page is open.
|
||
|
||
## Shop-floor reporting
|
||
|
||
- **Kiosk tablets and QR codes:** in **Settings → Reporting links**, create a link. Open it on a shared tablet for a kiosk, or print QR codes for it from **Locations → QR codes**. Anyone can then report without an account; the link can't read anything and can be revoked at any time.
|
||
- **Offline:** reports made without a connection are kept on the device and sent automatically when it returns.
|
||
- **Spanish:** use the language button (sidebar, sign-in page or kiosk header). The choice is remembered on that device.
|
||
|
||
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](CONTRIBUTING.md). Everyone taking part follows our [Code of Conduct](CODE_OF_CONDUCT.md).
|
||
|
||
## License
|
||
|
||
[GNU Affero General Public License v3.0](LICENSE). 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.
|