|
||
---|---|---|
.forgejo/workflows | ||
.github | ||
docs | ||
public | ||
scripts | ||
src | ||
tests | ||
.env.example | ||
.gitignore | ||
CLAUDE.md | ||
eslint.config.mjs | ||
jest.config.js | ||
original-style.css | ||
package-lock.json | ||
package.json | ||
README.md | ||
s3-bucket-policy.json | ||
tsconfig.json |
Great Lakes Ice Report
A community-driven web application for tracking winter road conditions and icy hazards in the Great Lakes region. Reports automatically expire after 48 hours to maintain current information.
Features
- 🗺️ Interactive Map - Real-time location tracking centered on Grand Rapids
- ⚡ Fast Geocoding - Lightning-fast address lookup with Mapbox API
- 📱 Progressive Web App - Install on mobile home screen, works offline
- 🚫 JavaScript-Free Mode - Complete functionality without JavaScript via server-side rendering
- 🖼️ Static Maps - Auto-generated Mapbox static images for non-JS users
- 🔄 Auto-Expiration - Reports automatically removed after 48 hours
- 👨💼 Admin Panel - Manage and moderate location reports
- 📱 Responsive Design - Works on desktop and mobile devices
- ♿ Accessibility First - Progressive enhancement with noscript fallbacks
- 🔒 Privacy-Focused - No user tracking, community safety oriented
- 🛡️ Enhanced Security - Coordinate validation, rate limiting, and content filtering
- 🌐 Internationalization - Full i18n support with English and Spanish (Mexico) languages
Quick Start
Prerequisites
- Node.js 18+
- Mapbox API token (free tier available)
- Important: For server-side static maps, use an unrestricted token (no URL restrictions)
Local Development
-
Clone the repository:
git clone https://git.deco.sh/deco/ice.git cd ice
-
Install dependencies:
npm install
Note: CSS is automatically built via the
postinstall
script -
Configure environment variables:
cp .env.example .env # Edit .env with your Mapbox token
-
Start the server:
npm start # Production mode (builds everything) npm run dev:ts # TypeScript development mode npm run dev-with-css:ts # TypeScript + CSS watching (recommended) npm run dev:full # Full development (TypeScript + frontend + CSS)
Development Commands
Code Quality
# Run ESLint to check code style and quality
npm run lint
# Auto-fix ESLint issues where possible
npm run lint:fix
Testing
# Run all tests (128+ tests with TypeScript)
npm test
# Run tests with coverage report (76% overall coverage)
npm run test:coverage
- Visit the application:
http://localhost:3000
Build System
This project uses TypeScript for both backend and frontend code, with SCSS for styling.
Backend (TypeScript → Node.js):
npm run build:ts # Compile TypeScript backend
npm run dev:ts # TypeScript development with auto-reload
Frontend (TypeScript → Browser JavaScript):
npm run build:frontend # Compile frontend TypeScript with esbuild
npm run watch:frontend # Watch frontend TypeScript for changes
CSS (SCSS → CSS):
npm run build-css # Build CSS once (production)
npm run build-css:dev # Build CSS with source maps
npm run watch-css # Watch SCSS files for changes
Development Commands:
npm run dev:full # Watch all: TypeScript backend + frontend + CSS
npm run dev-with-css:ts # Watch TypeScript backend + CSS
npm run build # Build everything for production
File Organization:
src/
- TypeScript backend codesrc/frontend/
- TypeScript frontend code (compiled topublic/dist/
)src/scss/
- SCSS stylesheets (compiled topublic/style.css
)dist/
- Compiled backend JavaScriptpublic/dist/
- Compiled frontend JavaScript
Note: Generated files (dist/
, public/dist/
, public/style.css
) should not be committed to git.
Environment Variables
# Required for geocoding and static map generation
MAPBOX_ACCESS_TOKEN=pk.your_mapbox_token_here
# Admin panel access
ADMIN_PASSWORD=your_secure_password
# Server configuration
PORT=3000
Mapbox Token Requirements:
- For interactive geocoding: Token can have URL restrictions
- For server-side static maps: Must use unrestricted token (no URL restrictions)
- Recommended: Use one unrestricted token for both features
Deployment
Deployment Scripts
The scripts/
directory contains all deployment-related files:
deploy.sh
- Automated deployment script for Debian 12 (ARM64/x86_64)icewatch.service
- Systemd service file for the applicationCaddyfile
- Caddy reverse proxy configurationgenerate-icons.js
- Script to generate PWA icons
Quick Deployment (Recommended)
See docs/deployment-quickstart.md
for a simplified deployment guide.
Automated Deployment (Debian 12 ARM64/x86_64)
-
Run the deployment script on your server:
Option A: Use the local deployment script (Recommended)
# Clone the repository first git clone https://git.deco.sh/deco/ice.git cd ice # Run the local deployment script sudo bash scripts/deploy.sh
Option B: Download from S3
# Default: Downloads config from S3 curl -sSL https://ice-puremichigan-lol.s3.amazonaws.com/scripts/deploy.sh | bash # Alternative: Use local files only (no S3) curl -sSL https://ice-puremichigan-lol.s3.amazonaws.com/scripts/deploy.sh | S3_BUCKET_NAME=none bash
The deployment script (
scripts/deploy.sh
) automates the entire setup process including:- Installing required dependencies (Node.js, Git, Caddy)
- Creating system user and directories
- Setting up systemd services
- Configuring Caddy reverse proxy
-
Deploy your application:
sudo git clone https://git.deco.sh/deco/ice.git /opt/icewatch cd /opt/icewatch sudo chown -R $USER:$USER /opt/icewatch npm install # This automatically builds CSS via postinstall npm run build # Build everything: TypeScript backend + frontend + CSS
-
Configure environment:
cp .env.example .env nano .env # Add your API keys
-
Create databases and set permissions:
touch icewatch.db profanity.db sudo chown -R icewatch:icewatch /opt/icewatch
-
Start services:
sudo systemctl enable icewatch sudo systemctl start icewatch sudo systemctl enable caddy sudo systemctl start caddy
Manual Deployment
See docs/deployment.md
for detailed manual deployment instructions.
API Endpoints
Public Endpoints
GET /api/locations
- Get active location reportsPOST /api/locations
- Submit new location report (rate limited: 10/15min per IP)GET /api/config
- Get API configuration
Progressive Enhancement Routes
GET /
- Main application page with JavaScript-enhanced featuresGET /table
- Non-JavaScript table view with static map and HTML formsPOST /submit-report
- Server-side form submission for non-JavaScript usersGET /map-image.png
- Dynamic static map generation using Mapbox Static Images API- Query parameters:
?width=800&height=600&padding=50
for customization - Auto-fit positioning centers on actual location coordinates
- Color-coded pins: red for regular reports, orange for persistent
- Query parameters:
Admin Endpoints (Authentication Required)
GET /admin
- Admin panel (password protected)GET /api/admin/locations
- Get all location reportsPUT /api/admin/locations/:id
- Update location reportPATCH /api/admin/locations/:id/persistent
- Toggle persistent statusDELETE /api/admin/locations/:id
- Delete location reportGET /api/admin/profanity-words
- Manage profanity filterPOST /api/admin/profanity-words
- Add custom profanity wordPUT /api/admin/profanity-words/:id
- Update profanity wordDELETE /api/admin/profanity-words/:id
- Delete profanity word
API Documentation
Interactive API documentation available at /api-docs
when running the server.
PWA Installation
Mobile Devices
- Open the app in your mobile browser
- Look for the "Add to Home Screen" prompt
- Tap "Add" to install the app on your home screen
- The app will work offline and behave like a native app
Desktop Browsers
- Visit the app in Chrome, Edge, or Safari
- Look for the install icon in the address bar
- Click "Install" to add the app to your desktop
- Launch from your applications folder or start menu
PWA Features
- Offline Access: View cached reports when disconnected
- App-like Experience: Standalone window, no browser UI
- Home Screen Icon: Quick access like native apps
- Automatic Updates: Always stay current when online
Technology Stack
- Backend: Node.js, Express.js, SQLite, TypeScript
- Frontend: Progressive Web App with Progressive Enhancement
- PWA: Installable, offline-capable, service worker caching
- Enhanced: Leaflet.js interactive maps with real-time updates
- Fallback: Server-side HTML tables with static Mapbox images
- Geocoding: Mapbox API (with Nominatim fallback)
- Maps: Leaflet.js (interactive) + Mapbox Static Images API (server-side)
- Security: Rate limiting, input validation, authentication
- Testing: Jest, TypeScript, 128+ tests with 76% coverage
- Reverse Proxy: Caddy (automatic HTTPS)
- Database: SQLite (lightweight, serverless)
- Accessibility: Full progressive enhancement with noscript support
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Test thoroughly
- Submit a pull request
Security
- Authentication: Admin routes protected with bearer token authentication
- Rate Limiting: Public endpoints limited to prevent abuse (10 requests/15min per IP)
- Input Validation: Strict length limits and type checking on all user inputs
- Data Protection: API keys stored in environment variables only
- Database Security: Parameterized queries prevent SQL injection
- Content Filtering: Built-in profanity filter with custom word management
- HTTPS: Enforced in production via Caddy reverse proxy
- Audit Logging: Suspicious activity and abuse attempts are logged
Input Limits
- Address: Maximum 500 characters
- Description: Maximum 1000 characters
- Latitude: Must be between -90 and 90 degrees
- Longitude: Must be between -180 and 180 degrees
- Submissions: 10 per 15 minutes per IP address
License
MIT License - see LICENSE file for details
Support
This is a community safety tool. For issues or questions:
- Create an issue on our git repository
- Check existing documentation
- Review security guidelines
⚠️ Safety Notice: This tool is for community awareness. Always prioritize personal safety and know your rights.