A comprehensive field operations management platform for tracking work orders, site visits, and assets across multiple locations. Built for telecom and infrastructure field service organizations.
- π« Ticket Management - Create, track, and manage work orders with customizable templates
- π Site Management - Organize and monitor sites with custom fields and ownership tracking
- π¦ Asset Tracking - Track equipment and assets across sites
- π Visit Logging - Record site visits with notes, custom fields, and photo attachments
- π Attachment Management - Upload and manage photos, documents, and files with thumbnail previews
- π₯ Multi-tenant Support - Company-based isolation with role-based access control
- π¨ Custom Templates - Define custom ticket templates with configurable fields (text, number, date, select, multi-select, etc.)
- π Advanced Search & Filtering - Server-backed search and filtering across tickets and sites
- π Table Views - Professional data tables with sortable columns, pagination, and column visibility controls
- π’ Site Owner Management - Organize sites by owners with granular access controls
- π± Offline-First Architecture - Dexie-powered IndexedDB cache plus sync runner for tickets, visits, templates, and attachment uploads
- π Secure Authentication - JWT-based authentication with role-based permissions (ADMIN, MANAGER, TECH)
- π₯ Bulk Downloads - Download all attachments as ZIP archives
- π€ Admin Import/Export - CSV-based bulk import/export for Site Owners, Sites, Ticket Templates, and Tickets with custom field support
- π¨ Company Branding - Token-based theming with preset palettes, dark mode toggle, and tenant-specific logos
- πΊ Map View - Leaflet-powered ticket map with live bounding-box filtering, owner/template filters, clustering, hover previews, and click-to-pin popups for rapid situational awareness
- Runtime: Node.js 20+
- Framework: Fastify 4.x
- Database: PostgreSQL with Prisma ORM
- Authentication: JWT + bcrypt
- File Storage: Local filesystem with @fastify/static
- Validation: Zod schemas
- File Processing: Archiver for ZIP generation
- Framework: React 18 + TypeScript
- Build Tool: Vite 5
- Routing: React Router v6
- State Management: TanStack Query (React Query)
- Data Tables: TanStack Table
- Offline Storage: Dexie (IndexedDB wrapper)
- Styling: Token-driven CSS variables with a ThemeProvider
- Companies, Users, Sites, Assets
- Tickets, Templates, Visits
- Attachments, Custom Fields
- Role-based access controls
- Node.js: v20.0.0 or higher
- PostgreSQL: v14 or higher
- npm: v9.0.0 or higher
git clone <repository-url>
cd SiteTrackr# Install API dependencies
cd apps/api
npm install
# Install Web dependencies
cd ../web
npm installCreate a PostgreSQL database:
create database sitetrackrConfigure environment variables in apps/api/.env:
DATABASE_URL="postgresql://user:password@localhost:5432/sitetrackr"
JWT_SECRET="your-secret-key-here"
PORT=3001Run migrations:
cd apps/api
npm run prisma:migrateRun the helper script for a full reset plus demo data:
./scripts/reset-db.shThe script drops the database referenced by DATABASE_URL, reruns Prisma migrations, and then applies the expanded seed file at apps/api/seed-demo.sql.
The API will automatically create a demo company and admin user on first run:
- Company ID:
11111111-1111-1111-1111-111111111111 - Admin User:
00000000-0000-0000-0000-000000000001 - Email:
admin@demo.com - Password:
change-me
Terminal 1 - API Server:
cd apps/api
npm run devAPI will run on http://localhost:3001
Terminal 2 - Web Client:
cd apps/web
npm run devWeb app will run on http://localhost:5173
# Build API
cd apps/api
npm run build
npm start
# Build Web
cd apps/web
npm run build
npm run previewSiteTrackr/
βββ apps/
β βββ api/ # Backend API
β β βββ prisma/
β β β βββ schema.prisma # Database schema
β β β βββ migrations/ # Database migrations
β β βββ src/
β β β βββ modules/ # Feature modules
β β β β βββ auth/ # Authentication
β β β β βββ tickets/ # Ticket management
β β β β βββ sites/ # Site management
β β β β βββ visits/ # Visit logging
β β β β βββ assets/ # Asset tracking
β β β β βββ adminImportExport/ # CSV import/export
β β β β βββ ...
β β β βββ plugins/ # Fastify plugins
β β β βββ index.ts # API entry point
β β βββ uploads/ # File storage
β β
β βββ web/ # Frontend Web App
β βββ src/
β β βββ features/ # Feature modules
β β β βββ auth/ # Login, auth hooks
β β β βββ tickets/ # Ticket pages & API
β β β βββ sites/ # Site pages & API
β β β βββ visits/ # Visit pages & API
β β β βββ admin/ # Admin import/export
β β β βββ ...
β β βββ components/ # Shared components
β β β βββ common/ # Button, Input, Card
β β β βββ layout/ # AppLayout, navigation
β β βββ lib/ # API client, utilities
β β βββ main.tsx # App entry point
β βββ public/ # Static assets
β
βββ packages/ # Shared packages (future)
Define reusable templates with custom fields:
- Text, Textarea, Number
- Date, Time, DateTime
- Boolean (checkbox)
- Select (dropdown)
- Multi-Select
- Field validation and required/optional settings
- Sortable columns (client + server)
- Server-side pagination
- Search with debouncing
- Show/hide columns (saved per user in localStorage)
- Clickable rows for navigation
- Visit-level attachments: Photos/files tied to specific visits
- Ticket-level attachments: Documents for the entire ticket (timesheets, work orders)
- Unique display names to prevent filename conflicts
- Thumbnail preview for images
- Bulk download as ZIP
- Offline capture queue with pending/failed status badges and automatic retries
- ADMIN: Full system access including import/export
- MANAGER: Limited administrative access
- TECH: Field technician access
- Site owner-based filtering for non-admin users
CSV-based bulk data management (Admin only):
- Site Owners: Export/import owner definitions with custom field schemas using
field:key:labelcolumn format - Sites: Export/import sites with owner assignments and custom field values using
cf:fieldKeycolumn format - Ticket Templates: Export/import templates with field definitions and sections using
field:key:labelcolumn format - Tickets: Export/import tickets with template assignments and custom field values using
cf:fieldKeycolumn format
Key Features:
- UPSERT Logic: Intelligently creates new records or updates existing ones based on ID, external ID, or unique identifiers
- Row Validation: Detailed error reporting with row numbers and field-specific errors
- Custom Field Support: Import/export custom field definitions and values using special column naming conventions
- Reference Validation: Validates relationships (e.g., siteOwnerId, templateId) and provides clear error messages
- Automatic Ticket Numbering: Generates globally unique ticket numbers (ST00001, ST00002, etc.) when not provided
- No Destructive Actions: Import only creates or updates records; never deletes existing data
- JWT token-based authentication
- Password hashing with bcrypt
- Role-based route protection
- Helmet.js security headers
- CORS configuration
- SQL injection protection via Prisma
http://localhost:3001/api/v1
Authentication:
POST /auth/login- User loginPOST /auth/register- User registration
Tickets:
GET /tickets- List tickets (paginated, searchable, filterable)GET /tickets/:id- Get ticket detailsPOST /tickets- Create ticketPATCH /tickets/:id- Update ticket (status, priority, fields)GET /tickets/:id/attachments/download- Download all visit attachments as ZIP
Sites:
GET /sites- List sites (paginated, searchable)GET /sites/:id- Get site detailsPATCH /sites/:id- Update site
Visits:
POST /tickets/:ticketId/visits- Create visitPOST /visits/:visitId/attachments- Upload attachment
Attachments:
POST /tickets/:ticketId/attachments- Upload ticket-level attachmentPOST /tickets/:ticketId/attachments/metadata- Create attachment metadata (idempotent/offline)GET /uploads/:companyId/:filename- Retrieve filePOST /visits/:visitId/attachments- Upload visit attachmentPOST /visits/:visitId/attachments/metadata- Create visit attachment metadataPUT /attachments/:id/content- Upload attachment bytes for a pending metadata record
Branding (Admin):
GET /company/branding- Retrieve theme tokens for the active companyPUT /company/branding- Update branding (primary color, logo URL, mode)
Admin Import/Export:
POST /admin/import/site-owners- Import Site Owners from CSVGET /admin/export/site-owners- Export Site Owners to CSVPOST /admin/import/sites- Import Sites from CSVGET /admin/export/sites- Export Sites to CSVPOST /admin/import/ticket-templates- Import Ticket Templates from CSVGET /admin/export/ticket-templates- Export Ticket Templates to CSVPOST /admin/import/tickets- Import Tickets from CSVGET /admin/export/tickets- Export Tickets to CSV
# API tests (if configured)
cd apps/api
npm test
# Web tests (if configured)
cd apps/web
npm test- Admin CSV Import/Export
- Excel (XLSX) import/export support
- Mobile app (React Native)
- Offline-first sync engine (Phase 1-2 web cache + outbox)
- Real-time notifications
- Advanced reporting & analytics
- Equipment maintenance scheduling
- Integration with third-party systems
- Geolocation tracking
- Time tracking & billing
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- TypeScript is used throughout for type safety
- Prisma migrations are version controlled
- File uploads stored in
apps/api/uploads/{companyId}/ - Column visibility preferences stored in browser localStorage
- Search queries debounced at 300ms
- Default page size: 25 items
- CSV import/export uses
csv-parseandcsv-stringifylibraries - Ticket numbers are globally unique with format ST00001-ST99999
- Custom fields support both field definitions (
field:key:label) and values (cf:key) in CSV imports
- Mobile responsive design needs improvement
- Performance optimization needed for large datasets
- Attachment uploads limited to 25MB per file
For questions or issues, please open a GitHub issue or contact the development team.
Built with β€οΈ for field service teams | Free and Open Source Software
