A multi-tenant web application for tracking the accuracy of mechanical watches over time.
Watch Deviation Tracker allows watch enthusiasts to track their mechanical watch accuracy by recording deviation measurements. The application supports multiple users, each with multiple watches, and calculates drift statistics based on measurement history.
- Runtime: Deno with TypeScript
- Web Framework: Hono - Fast, lightweight web framework
- Database: SQLite with Prisma 6 ORM
- Frontend: HTMX + Handlebars templates + Bootstrap 5
- Session Management: Memcached-backed cookie sessions
- Authentication: External API verification (with test users in development)
The application follows a layered architecture pattern:
┌─────────────────────────────────────┐
│ HTTP Requests │
└─────────────┬───────────────────────┘
│
┌─────────────▼───────────────────────┐
│ Routes Layer │
│ - Request handling │
│ - Input validation │
│ - HTMX response formatting │
└─────────────┬───────────────────────┘
│
┌─────────────▼───────────────────────┐
│ Service Layer │
│ - Business logic │
│ - Data transformation │
│ - Drift calculations │
└─────────────┬───────────────────────┘
│
┌─────────────▼───────────────────────┐
│ Repository Layer │
│ - Prisma ORM wrappers │
│ - Database queries │
└─────────────┬───────────────────────┘
│
┌─────────────▼───────────────────────┐
│ Database Layer │
│ - SQLite │
└─────────────────────────────────────┘
lib/ # Utilities: config, db, auth, hbs, views, session store, types
middleware/ # Session middleware, ownership validation
routers/ # Router setup (sessionRouter, authRouter)
routes/ # Route handlers (watch, measure, login, etc.)
service/ # Business logic layer
repo/ # Data access layer (Prisma wrappers)
prisma/ # Schema, migrations, generated client
static/ # Static assets (CSS, JS, images)
views/ # Handlebars templates (.hbs)
Create a .env file in the project root:
# Database
DATABASE_URL=file:../watchtracker.db
# Server Configuration
APP_HOST=0.0.0.0
APP_PORT=<port-from-.env>
APP_PATH=/watchtracker
APP_URL=http://localhost:<port-from-.env>/watchtracker
# Authentication
AUTH_API_URL=https://your-auth-api.com/verify
# Session Cookies
COOKIE_NAME=watchtracker_sid
COOKIE_SECRET=your-secret-key-here
COOKIE_MAX_AGE="40 weeks"
# Memcached (Session Store)
MEMCACHE_HOST=127.0.0.1
MEMCACHE_PORT=11211
MEMCACHE_PREFIX=watchtracker
# Environment
DENO_ENV=developmentNote: For detailed development guidelines, see AGENTS.md.
-
Generate Prisma client:
deno task pg
-
Run migrations:
deno task pmd
Start the development server with hot reload:
deno task devThe server will be available at the APP_URL configured in .env.
deno task pg # Generate Prisma client
deno task pmd # Run Prisma migrations (dev)
deno task pms # Check migration status
deno task pmr # Reset database
deno task lint # Run linter
deno task check # TypeScript type checking
deno task start # Production server
deno task dev # Development server with hot reload
deno task test # Run tests (resets DB automatically)
deno task replacedb # Reset database to clean test state
deno task purgecss # Optimize CSSThe application supports two authentication modes:
- Test users:
test/testandgrafg/grafg - Credentials are checked locally before falling back to API
- All authentication is handled via the external API
- No hardcoded test users
User: Application users with timezone preference Watch: Mechanical watches owned by users Measurement: Time deviation recordings for watches
See prisma/schema.prisma for the complete schema definition.
For detailed development guidelines, code style, and architecture patterns, please refer to AGENTS.md.
Key points:
- Follow the layered architecture (routes → service → repo → db)
- Use class-based static methods for Service and Repository layers
- Run
deno task lintanddeno task checkbefore committing - HTMX requests return partials, regular requests return full pages
- Replace hono-sessions with custom session middleware - issue #95
- Fix double session middleware execution - issue #94
- Implement environment-based authentication for test users
- Fix lint errors and dev script task name
- upgrades
- fixed
- init migration for prod
- issue #52: Convert measurements table to CSS Grid layout
- Implement typed wrappers for Handlebars templates - issue #63
- Security: Implement resource ownership middleware - issue #76
- UX/Error: Implement centralized HTMX-aware error handler - issue #75
- DevOps: Verify Prisma client generation in dev workflow - issue #74
- Refactor: Consolidate data enrichment logic in WatchService - issue #72
- DX: Monitor static/ directory in deno task dev - issue #73
- Cleanup: Remove obsolete classes_old/ directory - issue #71
- Add pms task for prisma migrate status
- Fix NaN in Entry date: use getWatchForDisplay in user and slash routes - issue #69
- Fix deviation input UX: use placeholder instead of value, add views to watch task - issue #54
- Fix deviation input cursor issue with onfocus select - issue #54
- Fix broken app: routing, session, measurements display - issue #68
- #68 fix routing: trailing slash redirect, static files path, add warning to AGENTS.md
- #67 add agent-browser workflow and dev instructions to AGENTS.md
Please see AGENTS.md for contribution guidelines and development workflow.
[Add your license information here]