bizzleandClaude Fable 5.1 5cfcce0b64 fix: keep entry form mounted when a new entry is first saved
On mobile, typing the first characters of a work description on a new
entry caused the form to remount: the auto-save POST replaced the temp
entry with the server copy, changing its React key, which destroyed the
textarea, dropped focus and closed the keyboard.

- Key EntryForm on a stable clientKey that survives the id swap
- Merge only the server id into the local entry so keystrokes typed
  while the create request is in flight are kept
- Track temp-id -> real-id and in-flight creates so queued changes
  become PUTs instead of duplicate POSTs; deletes resolve to the real row

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 20:01:59 -04:00

Coastal Timesheet

Coastal Timesheet v2

A modern, mobile-first time tracking application for Coastal Contracting of FL

React 18 Express PostgreSQL Prisma Docker Tailwind


✨ Features

  • 📱 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
  • 📋 Copy Previous Week — One tap to duplicate last week's entries as a template
  • ✅ Submit → Approve workflow — Employees submit, admins approve or reject
  • ⚡ Bulk Approve/Reject — Select all + approve 40 timesheets in one click
  • ⏱️ Overtime Tracking — Real-time OT warnings for employees, admin reports with per-employee weekly breakdown
  • 📄 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, homeowner, date range, status
  • 🏡 Homeowner management — Add, edit, search, activate/deactivate with address fields
  • 🌙 Dark mode — System-aware with manual toggle
  • 🐳 One-command deploy — Single docker compose up for the entire stack

📸 Screenshots

Timesheet Entry Copy Previous Week Dark Mode
Bulk Approve Overtime Tracking Reports & Filters
Homeowner Management History Entry Form

Desktop


🚀 Quick Start

Prerequisites

  • Docker and Docker Compose
  • That's it. Everything else runs in containers.

Deploy

# 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 app will be available at http://localhost (port 80).

Default Admin Account

Field Value
Email admin@coastal.com
Password CoastalAdmin2026!

⚠️ Change the admin password after first login.


⚙️ Configuration

Copy .env.example to .env and configure:

# 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

Email Setup (Gmail)

  1. Enable 2FA on your Google account
  2. Go to App Passwords
  3. Generate a new app password for "Mail"
  4. Use that as SMTP_PASS

🏗️ Architecture

┌─────────────────────────────────────────────┐
│                   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)      │
└──────────────────┴──────────────────────────┘

Tech Stack

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

📁 Project Structure

.
├── 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

🔒 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.


Built with ☀️ in Florida

S
Description
Modern, mobile-first time tracking app for Coastal Contracting of FL — React + Express + PostgreSQL + Docker
Readme
6.5 MiB
Languages
JavaScript 95.1%
CSS 2.8%
Dockerfile 1.8%
HTML 0.3%