Live App: https://lab-sample-tracker-production.up.railway.app/
A practical laboratory sample management application designed to improve sample registration, traceability, storage visibility, movement tracking, retention control, and retrieval efficiency in petroleum laboratory operations.
This project is being developed as part of my software engineering and DevOps transition journey, using a real petroleum laboratory workflow as the business case.
Many laboratories still manage samples with handwritten registers, informal storage knowledge, and manual follow-up. That creates operational risks such as:
- slow sample retrieval
- incomplete or inconsistent sample records
- weak visibility of current sample location
- duplicate or inconsistent sample identification
- poor visibility of retained quantity
- weak retention and disposal control
- reduced audit readiness
- dependence on staff memory instead of system records
The Lab Sample Tracker App is intended to digitize that workflow through structured sample intake, persistent storage, searchable records, movement history, lifecycle-aware dashboarding, and operational visibility of live sample state.
In petroleum laboratory operations, samples may be received from vessels, offshore operations, shore tanks, clients, or transfer activities. A sample may be:
- received into the laboratory
- stored with a rack, shelf, and position reference
- partially used for testing
- returned to store
- moved from Lomé to Lagos
- moved from Lagos back to Lomé
- fully consumed during testing
- retained under standard 90-day policy
- held under quarantine for longer periods where cargo dispute exists
- disposed after retention obligations expire
A manual process can work at very small scale, but it becomes unreliable as volume grows or when different staff must retrieve samples quickly and accurately.
This application is designed to improve:
- sample traceability
- chain-of-custody visibility
- movement accountability
- live quantity awareness
- storage and retrieval efficiency
- retention and disposal readiness
- dashboard visibility for operations
- audit preparedness
- digital transformation of laboratory workflows
- Node.js 18 or later
- A PostgreSQL database (see providers below)
git clone https://github.com/IbkWilliams1/lab-sample-tracker.git
cd lab-sample-tracker
npm installCopy .env.example to .env and fill in your DATABASE_URL:
cp .env.example .envRecommended free-tier PostgreSQL providers:
| Provider | Free Tier | Notes |
|---|---|---|
| Neon | Yes, no expiry | Serverless PostgreSQL, simple setup |
| Railway | Yes, usage-based | Hosts both app and database |
| Supabase | Yes, no expiry | Includes dashboard and API |
After creating a database, paste the connection string into .env:
DATABASE_URL=postgresql://user:password@host:5432/dbname
The application creates all tables automatically on first run. No manual migrations are needed.
npm run devThe app will be available at http://localhost:3004.
- Batch sample registration form
- Capture of vessel, client, cargo, port, operation stage, chemist, and surveyor details
- Auto-generated sequential Lab IDs backed by PostgreSQL
- Prevention of duplicate Lab ID reuse
- Auto-generated batch description preview
- Tank-based sample entry workflow
- Main tank generation using Port, Center, and Starboard layout logic
- Slop tank handling aligned to operational pair logic
- Dashboard view of registered samples
- Individual sample details page
- Quantity-aware movement logging
- Movement history tracking
- Current quantity tracking
- Current location tracking
- Movement count tracking
- Status updates through movement workflow
- Live sample state initialization at creation
- Retention type capture
- Quarantine end-date capture
- Disposal due date calculation
- Date-based dashboard filtering
- Disposal timeline filtering
- Disposal visibility on dashboard
- Summary cards for receipt and disposal metrics
- Vessel names entered during sample registration are automatically saved to a persistent vessels table
- Typing in the vessel field surfaces matching vessel names from previous records as dropdown suggestions
- Reduces repeated spelling inconsistency across sample entries
- No manual catalog management required — the suggestion pool grows automatically as new vessels are registered
- Cloud PostgreSQL database accessible from any machine
- All sample records, movement logs, and vessel names share a single live data store
- Environment-based configuration via
DATABASE_URL - Application port configurable via
PORTenvironment variable for cloud deployment compatibility
- editing and updating existing sample records
- deletion or archival of obsolete records
- stronger dashboard search refinement
- improved dashboard column prioritization for daily lab use
- export to Excel or PDF
- monthly movement and disposal reporting
- improved input validation and user feedback
- role-based access and authentication
- Dockerized deployment
- CI/CD pipeline with GitHub Actions
- backup automation
The current build milestone is:
Railway deployment — application accessible from any machine via public URL
The application is now deployed to Railway at:
https://lab-sample-tracker-production.up.railway.app/
No local setup is required. Anyone with the URL can open the app in a browser, register samples, view the dashboard, and log movements against the shared Neon PostgreSQL database.
Key changes in this milestone:
- added
enginesfield topackage.jsonto pin the Node.js runtime version on Railway - Railway reads
npm start(node app.js) as the start command — noProcfileorDockerfileneeded DATABASE_URLandPORTare injected as Railway environment variables — no.envfile required in productiondotenvgracefully does nothing when.envis absent, so local and cloud environments use the same code path
With the app deployed and accessible from any machine, the next recommended phase is record editing and CI/CD.
The current workflow is append-only. Once a sample is registered, no fields can be corrected. This creates operational friction when:
- a spelling error is made on the vessel name, client, or cargo
- the chemist or surveyor name needs to be updated
- a rack or shelf position changes
Adding an edit capability is the highest-value feature improvement for daily lab use.
- Refactored the app from a monolithic prototype into a structured Node/Express project
- Implemented unique sequential Lab ID generation
- Added dashboard and sample details workflow
- Added quantity-aware movement logging for sample transfers between labs
- Added movement history tracking
- Added current quantity, location, and movement count tracking
- Added retention-aware workflow support with standard 90-day retention and quarantine handling
- Added disposal timeline logic and dashboard-level disposal visibility
- Added dashboard summary cards and date-based filtering
- Added vessel name autocomplete for sample entry consistency
- Added live inventory state initialization for newly created records
- Removed vessel catalog CRUD feature; scoped vessel functionality to persistent autocomplete only
- Migrated persistence layer from local SQLite to cloud PostgreSQL with environment-based configuration
- Deployed to Railway — accessible from any machine via public URL at https://lab-sample-tracker-production.up.railway.app/
| Area | Technology |
|---|---|
| Runtime | Node.js |
| Backend Framework | Express.js |
| Frontend | HTML, CSS, JavaScript |
| Template Engine | EJS |
| Database | PostgreSQL (cloud-hosted) |
| Database Client | node-postgres (pg) |
| Version Control | Git and GitHub |
| Current App Pattern | Server-rendered internal operations tool |
| Deployment | Railway |
| Future Deployment | Docker, Nginx, GitHub Actions |
lab-sample-tracker/
│
├── app.js # Express app entry point; loads env vars and mounts routes
├── package.json # Project dependencies and scripts
├── package-lock.json # Locked dependency versions
├── .env.example # Environment variable template (copy to .env)
│
├── routes/
│ ├── api.js # API routes: batch save, movement logging, vessel name search
│ └── views.js # Page routes: dashboard, sample details, index
│
├── views/
│ ├── index.ejs # Batch sample registration form
│ ├── dashboard.ejs # Dashboard with filters, summaries, and disposal visibility
│ └── sample-details.ejs # Sample details and movement history view
│
├── public/
│ ├── css/
│ │ └── style.css # Application styles
│ └── js/
│ └── batch-form.js # Frontend form logic, tank generation, and vessel autocomplete
│
├── db/
│ ├── database.js # PostgreSQL pool, schema init, run/get/all/withTransaction helpers
│ ├── seed-vessels.js # One-time vessel name seed utility (SQLite-era, kept for reference)
│ └── backfill-sample-state.js # Legacy backfill utility (SQLite-era, kept for reference)
│
├── data/
│ └── store.js # Legacy in-memory store (unused)
│
├── .gitignore
└── README.md