v2.0.0: Complete rewrite — React + Express + PostgreSQL + Docker

BREAKING: Full rewrite from static HTML to production-grade stack.

Features:
- React 18 + Vite + Tailwind CSS (mobile-first)
- Express + Prisma + PostgreSQL backend
- JWT authentication with role-based access
- Weekly Mon-Sun timesheets with auto-save
- Multiple homeowner entries per day
- Submit → Approve/Reject workflow
- Server-side PDF generation
- SMTP email integration
- Admin panel with reporting & filters
- Dark mode (system-aware)
- Docker Compose one-command deploy
- Non-root containers, Helmet, bcrypt, Zod validation
This commit is contained in:
BizzleBot
2026-02-15 20:16:46 +00:00
parent 68832bd958
commit a7c138add1
88 changed files with 5522 additions and 9159 deletions
+248 -150
View File
@@ -1,189 +1,287 @@
# Coastal Contracting Timesheet App
<p align="center">
<img src="docs/screenshots/01-login-mobile.png" alt="Coastal Timesheet" width="200" />
</p>
A modern, responsive timesheet application built with React for tracking work hours and generating professional PDF timesheets. Features comprehensive validation, dynamic field layouts, and seamless data management.
<h1 align="center">Coastal Timesheet v2</h1>
![Coastal Timesheet App Screenshot](./screenshot.png)
*Screenshot showing the timesheet interface with validation, dynamic fields, and professional layout*
<p align="center">
<strong>A modern, mobile-first time tracking application for Coastal Contracting of FL</strong>
</p>
<p align="center">
<img src="https://img.shields.io/badge/React-18-61DAFB?logo=react&logoColor=white" alt="React 18" />
<img src="https://img.shields.io/badge/Express-4-000000?logo=express&logoColor=white" alt="Express" />
<img src="https://img.shields.io/badge/PostgreSQL-16-4169E1?logo=postgresql&logoColor=white" alt="PostgreSQL" />
<img src="https://img.shields.io/badge/Prisma-ORM-2D3748?logo=prisma&logoColor=white" alt="Prisma" />
<img src="https://img.shields.io/badge/Docker-Compose-2496ED?logo=docker&logoColor=white" alt="Docker" />
<img src="https://img.shields.io/badge/TailwindCSS-3-06B6D4?logo=tailwindcss&logoColor=white" alt="Tailwind" />
</p>
---
## ✨ Features
### 📊 **Time Tracking & Management**
- **Weekly Time Tracking**: Track work hours for each day of the week with multiple entries per day
- **Dynamic Date Navigation**: Navigate between weeks with intuitive date picker controls
- **Flexible Entry Management**: Add, remove, and modify time entries as needed
- **Auto-saving**: Automatically saves all data to browser localStorage
- **📱 Mobile-first design** — Built for field workers, optimized for phones
- **🔐 JWT authentication** — Secure login with access/refresh tokens + rate limiting
- **📅 Weekly timesheets** — Monday–Sunday pay period with auto-save
- **🏠 Multiple homeowners per day** — Track work at different job sites
- **✅ Submit → Approve workflow** — Employees submit, admins approve or reject
- **📄 PDF generation** — Professional server-side PDF export
- **📧 Email integration** — Send timesheets via email with SMTP
- **👥 Admin panel** — Manage employees, homeowners, review timesheets
- **📊 Reporting** — Filter by employee, date range, status with summary stats
- **🌙 Dark mode** — System-aware with manual toggle
- **🐳 One-command deploy** — Single `docker compose up` for the entire stack
### 🏠 **Homeowner Management**
- **Pre-loaded Homeowners**: Comprehensive list of default homeowner names and addresses
- **Custom Homeowners**: Add and save custom homeowner names that persist across sessions
- **Smart Dropdown**: Searchable dropdown with autocomplete functionality
---
### ✅ **Smart Validation System**
- **Required Employee Name**: Employee name must be entered before exporting timesheets
- **Complete Entry Validation**: When any field is filled, all three fields (homeowner, hours, work description) become required
- **Visual Feedback**: Red borders, asterisks, and warning messages guide users to complete entries
- **Export Protection**: PDF generation disabled until all validation requirements are met
## 📸 Screenshots
### 📝 **Enhanced User Interface**
- **Dynamic Work Description Fields**: Auto-resizing text areas that expand to show all content without scrolling
- **Optimized Field Layout**: Homeowner → Hours → Work Description order with maximum space for descriptions
- **Today Highlighting**: Current day is visually highlighted for easy identification
- **Dark/Light Mode**: Toggle between themes with persistent user preference
<table>
<tr>
<td align="center"><strong>Timesheet Entry</strong></td>
<td align="center"><strong>Entry Form</strong></td>
<td align="center"><strong>Dark Mode</strong></td>
</tr>
<tr>
<td><img src="docs/screenshots/02-timesheet-mobile.png" width="250" /></td>
<td><img src="docs/screenshots/03-entry-form-mobile.png" width="250" /></td>
<td><img src="docs/screenshots/07-dark-mode-mobile.png" width="250" /></td>
</tr>
</table>
### 📄 **Professional PDF Export**
- **Download PDF**: Generate and download professional timesheet PDFs
- **Email Integration**: Share PDFs via device share sheet or download with pre-filled email subject
- **Optimized Layout**: PDF layout matches UI with proper field sizing and professional formatting
- **Validation Integration**: Only complete, valid timesheets can be exported
<table>
<tr>
<td align="center"><strong>Admin Panel</strong></td>
<td align="center"><strong>Reports & Filters</strong></td>
<td align="center"><strong>History</strong></td>
</tr>
<tr>
<td><img src="docs/screenshots/05-admin-mobile.png" width="250" /></td>
<td><img src="docs/screenshots/06-admin-reports-mobile.png" width="250" /></td>
<td><img src="docs/screenshots/04-history-mobile.png" width="250" /></td>
</tr>
</table>
### 💾 **Data Management**
- **Import/Export**: Backup and restore timesheet data with JSON export/import
- **Week-based Storage**: Each week's data stored separately for better organization
- **Custom Homeowner Persistence**: Added homeowners saved across all sessions
- **Cross-device Compatibility**: Works on desktop, tablet, and mobile devices
### Desktop
### 📱 **Responsive Design**
- **Mobile-first**: Optimized for touch interfaces and small screens
- **Adaptive Layouts**: Fields reorganize appropriately for different screen sizes
- **Touch-friendly**: Large buttons and touch targets for mobile users
<img src="docs/screenshots/02-timesheet-desktop.png" width="700" />
<img src="docs/screenshots/06-admin-reports-desktop.png" width="700" />
## 🚀 Getting Started
---
## 🚀 Quick Start
### Prerequisites
- Node.js (version 16 or higher)
- npm or yarn
- [Docker](https://docs.docker.com/get-docker/) and Docker Compose
- That's it. Everything else runs in containers.
### Installation
1. Clone or download the project files
2. Install dependencies:
```bash
npm install
```
3. Start the development server:
```bash
npm run dev
```
4. Open [http://localhost:5173](http://localhost:5173) in your browser
### Building for Production
### Deploy
```bash
npm run build
# Clone the repo
git clone https://git.bizzle.lol/bizzle/coastal_timesheet.git
cd coastal_timesheet
git checkout v2
# Configure environment
cp .env.example .env
# Edit .env with your secrets (see Configuration below)
# Launch
cd docker
docker compose up -d
```
The built files will be in the `dist/` directory, ready for web hosting.
The app will be available at `http://localhost` (port 80).
### Preview Production Build
### Default Admin Account
```bash
npm run preview
| Field | Value |
|----------|-------------------------|
| Email | `admin@coastal.com` |
| Password | `CoastalAdmin2026!` |
> ⚠️ **Change the admin password after first login.**
---
## ⚙️ Configuration
Copy `.env.example` to `.env` and configure:
```env
# Database (auto-configured in Docker)
DB_PASSWORD=your-secure-db-password
# JWT Secrets (CHANGE THESE!)
JWT_SECRET=your-jwt-secret-min-32-chars
JWT_REFRESH_SECRET=your-refresh-secret-min-32-chars
# CORS (add your domain)
CORS_ORIGINS=https://timesheets.yourdomain.com
# Email (optional — for sending timesheets)
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASS=your-app-password
SMTP_FROM=timesheets@yourdomain.com
ADMIN_EMAIL=admin@yourdomain.com
```
## 📖 Usage Guide
### Email Setup (Gmail)
### 1. **Setup**
- Enter your **Employee Name** (required for all exports)
- Select the week you want to track using the date picker
1. Enable 2FA on your Google account
2. Go to [App Passwords](https://myaccount.google.com/apppasswords)
3. Generate a new app password for "Mail"
4. Use that as `SMTP_PASS`
### 2. **Adding Time Entries**
- Click "Add Entry" for any day to create multiple entries
- Fill in all three fields for each entry:
- **Homeowner**: Select from dropdown or add custom names
- **Hours Worked**: Enter decimal hours (e.g., 2.5 for 2 hours 30 minutes)
- **Work Description**: Detailed description of work performed (auto-expanding field)
---
### 3. **Validation & Completion**
- **Red asterisks (*)** indicate required fields
- **Warning messages** appear for incomplete entries
- **Export buttons** are disabled until all requirements are met
## 🏗️ Architecture
### 4. **Export Options**
- **Download PDF**: Save a printable PDF to your device
- **Share/Email PDF**: Use device share functionality or download with email setup
- **Import/Export Data**: Backup/restore your timesheet data
```
┌─────────────────────────────────────────────┐
│ Nginx │
│ (reverse proxy) │
│ /api/* → backend:3001 │
│ /* → static frontend │
├──────────────────┬──────────────────────────┤
│ Frontend │ Backend │
│ React + Vite │ Express + Prisma │
│ Tailwind CSS │ JWT Auth │
│ Lucide Icons │ @react-pdf/renderer │
│ │ Nodemailer │
│ ├──────────────────────────┤
│ │ PostgreSQL 16 │
│ │ (persistent volume) │
└──────────────────┴──────────────────────────┘
```
### 5. **Additional Features**
- **Theme Toggle**: Switch between light and dark modes
- **Office Contact**: Download contact card for easy email setup
### Tech Stack
## 🗂️ Data Storage
| Layer | Technology |
|-----------|-----------------------------------------------|
| Frontend | React 18, Vite 6, Tailwind CSS 3, Lucide |
| Backend | Express 4, Prisma ORM, bcryptjs, jsonwebtoken |
| Database | PostgreSQL 16 (Alpine) |
| PDF | @react-pdf/renderer (server-side) |
| Email | Nodemailer + SMTP |
| Proxy | Nginx 1.27 (Alpine) |
| Container | Docker Compose v3.9 |
- **Local Browser Storage**: All data stored locally, no external servers
- **Weekly Organization**: Each week stored as separate dataset
- **Persistent Settings**: Theme preferences and custom homeowners preserved
- **Privacy-focused**: Your data never leaves your device
## 🛠️ Tech Stack
- **Frontend Framework**: React 18 with Vite
- **Styling**: Tailwind CSS with responsive design
- **PDF Generation**: @react-pdf/renderer for professional documents
- **Icons**: Lucide React icon library
- **Storage**: Browser localStorage API
- **Build Tool**: Vite for fast development and optimized builds
---
## 📁 Project Structure
```
src/
├── components/ # React components
│ ├── TimeSheet.jsx # Main timesheet interface
│ ├── DayEntries.jsx # Day-specific entry management
│ ├── TimeEntryRow.jsx # Individual entry row (legacy)
│ ├── DatePicker.jsx # Week navigation
│ ├── HomeownerDropdown.jsx # Homeowner selection
│ ├── ThemeToggle.jsx # Dark/light mode toggle
│ ├── PDFExport.jsx # PDF download functionality
│ ├── EmailPDF.jsx # PDF sharing functionality
│ ├── TimesheetPDF.jsx # PDF document structure
│ ├── ImportExport.jsx # Data backup/restore
│ └── MiniCalendar.jsx # Calendar widget
├── hooks/ # Custom React hooks
│ ├── useTimeSheet.js # Timesheet state & validation
│ └── useTheme.js # Theme management
├── utils/ # Utility functions
│ └── dateUtils.js # Date manipulation helpers
├── App.jsx # Main application component
├── main.jsx # Application entry point
└── index.css # Global styles
.
├── frontend/ # React SPA
│ ├── src/
│ │ ├── api/ # Axios client with token refresh
│ │ ├── components/ # Reusable UI components
│ │ ├── contexts/ # Auth context (JWT)
│ │ ├── hooks/ # Custom hooks (theme, swipe, auto-save)
│ │ └── pages/ # Route pages
│ └── vite.config.js
├── backend/ # Express API
│ ├── prisma/
│ │ ├── schema.prisma # Database schema
│ │ └── seed.js # Seed admin + homeowners
│ └── src/
│ ├── middleware/ # Auth middleware
│ ├── routes/ # API routes
│ └── utils/ # PDF, email, validation
├── docker/ # Deployment
│ ├── docker-compose.yml
│ ├── backend/Dockerfile
│ ├── frontend/Dockerfile
│ └── nginx/default.conf
└── docs/screenshots/ # App screenshots
```
## 🔧 Configuration Files
- `vite.config.js` - Vite build configuration
- `tailwind.config.js` - Tailwind CSS customization
- `postcss.config.js` - PostCSS processing
- `package.json` - Dependencies and scripts
## 🌐 Deployment
The built application is a static site that can be deployed to any web hosting service:
1. Run `npm run build`
2. Upload the contents of the `dist/` directory to your web server
3. Ensure your server serves `index.html` for all routes (SPA configuration)
Compatible with: Netlify, Vercel, GitHub Pages, traditional web hosting, and more.
## 📋 Features Summary
✅ **Employee name validation**
✅ **Complete entry validation (all fields required when any field has input)**
✅ **Dynamic auto-resizing work description fields**
✅ **Optimized field order (Homeowner → Hours → Work Description)**
✅ **Professional PDF generation with validation**
✅ **Email/share functionality**
✅ **Data import/export**
✅ **Dark/light theme support**
✅ **Mobile-responsive design**
✅ **Local data persistence**
✅ **Multiple entries per day**
✅ **Custom homeowner management**
---
*Built for Coastal Contracting of FL - Making timesheet management simple and professional.*
## 🔒 Security
- **bcrypt** password hashing (12 rounds)
- **JWT** access tokens (15min) + refresh tokens (7 days)
- **Helmet** security headers
- **Rate limiting** on auth endpoints (50 req / 15 min)
- **Zod** input validation on all endpoints
- **Prisma ORM** — parameterized queries (no SQL injection)
- **Non-root Docker** containers
- **CORS** origin whitelist
---
## 📡 API Endpoints
### Auth
| Method | Endpoint | Description |
|--------|----------------------|----------------------|
| POST | `/api/auth/login` | Login, get tokens |
| POST | `/api/auth/refresh` | Refresh access token |
| GET | `/api/auth/me` | Current user info |
### Entries
| Method | Endpoint | Description |
|--------|---------------------|------------------------|
| GET | `/api/entries` | List entries (by week) |
| POST | `/api/entries` | Create entry |
| PUT | `/api/entries/:id` | Update entry |
| DELETE | `/api/entries/:id` | Delete entry |
### Timesheets
| Method | Endpoint | Description |
|--------|------------------------------|----------------------|
| GET | `/api/timesheets` | Get current week |
| GET | `/api/timesheets/history` | All user timesheets |
| POST | `/api/timesheets/submit` | Submit for approval |
| GET | `/api/timesheets/:id/pdf` | Download PDF |
### Admin
| Method | Endpoint | Description |
|--------|-------------------------------------|-------------------------|
| GET | `/api/admin/timesheets` | All timesheets (filter) |
| GET | `/api/admin/timesheets/:id` | Timesheet detail |
| PUT | `/api/admin/timesheets/:id/approve` | Approve timesheet |
| PUT | `/api/admin/timesheets/:id/reject` | Reject timesheet |
| PUT | `/api/admin/timesheets/:id/reopen` | Reopen for editing |
| GET | `/api/admin/users` | List employees |
| POST | `/api/admin/users` | Create employee |
| GET | `/api/admin/homeowners` | List homeowners |
| POST | `/api/admin/homeowners` | Add homeowner |
| GET | `/api/admin/reports` | Reporting with filters |
---
## 🔄 Upgrading from v1
v2 is a complete rewrite. Key differences:
| Feature | v1 | v2 |
|-----------------|-----------------------------|----------------------------------|
| Storage | Browser localStorage | PostgreSQL database |
| Auth | None | JWT with roles |
| Multi-user | No | Yes — unlimited employees |
| Approval flow | No | Submit → Approve/Reject |
| PDF | Client-side (jsPDF) | Server-side (@react-pdf) |
| Email | mailto: link | SMTP with PDF attachment |
| Deploy | Static HTML | Docker Compose (one command) |
| Admin panel | No | Full admin with reporting |
| Dark mode | No | System-aware + manual toggle |
---
## 📝 License
Private — Coastal Contracting of FL. All rights reserved.
---
<p align="center">
Built with ☀️ in Florida
</p>