458 lines
16 KiB
Markdown
458 lines
16 KiB
Markdown
# NocoDB Map Viewer
|
||
|
||
A containerized web application that visualizes geographic data from NocoDB on an interactive map using Leaflet.js.
|
||
|
||
## Features
|
||
|
||
- 🗺️ Interactive map visualization with OpenStreetMap
|
||
- 📍 Real-time geolocation support
|
||
- ➕ Add new locations directly from the map
|
||
- 🔄 Auto-refresh every 30 seconds
|
||
- 📱 Responsive design for mobile devices
|
||
- 🔒 Secure API proxy to protect credentials
|
||
- 👤 User authentication with login system
|
||
- ⚙️ Admin panel for system configuration
|
||
- 🎯 Configurable map start location
|
||
- 📋 Walk Sheet generator for door-to-door canvassing
|
||
- 🔗 QR code integration for digital resources
|
||
- 📅 Volunteer shift management system with calendar and grid views
|
||
- ✋ User shift signup and cancellation with color-coded calendar
|
||
- 👥 Admin shift creation and management
|
||
- 👨💼 User management panel for admin users (create, delete users)
|
||
- 🔐 Role-based access control (Admin vs User permissions)
|
||
- 🐳 Docker containerization for easy deployment
|
||
- 🆓 100% open source (no proprietary dependencies)
|
||
|
||
## Quick Start
|
||
|
||
### Prerequisites
|
||
|
||
- Docker and Docker Compose
|
||
- NocoDB instance with API access
|
||
- NocoDB API token
|
||
|
||
### Installation
|
||
|
||
1. **Get NocoDB API Token**
|
||
|
||
1. Login to your NocoDB instance
|
||
2. Click user icon → **Account Settings** → **API Tokens**
|
||
3. Create new token with read/write permissions
|
||
4. Copy the token for the next step
|
||
|
||
2. **Configure Environment**
|
||
|
||
Edit the `.env` file with your NocoDB API and API Url:
|
||
```env
|
||
# NocoDB API Configuration
|
||
NOCODB_API_URL=https://db.cmlite.org/api/v1
|
||
NOCODB_API_TOKEN=your-api-token-here
|
||
|
||
# These will be populated after running build-nocodb.sh
|
||
NOCODB_VIEW_URL=
|
||
NOCODB_LOGIN_SHEET=
|
||
NOCODB_SETTINGS_SHEET=
|
||
NOCODB_SHIFTS_SHEET=
|
||
NOCODB_SHIFT_SIGNUPS_SHEET=
|
||
|
||
# Domain Configuration
|
||
DOMAIN=cmlite.org
|
||
|
||
# MkDocs Integration
|
||
MKDOCS_URL=https://cmlite.org
|
||
MKDOCS_SEARCH_URL=https://cmlite.org
|
||
MKDOCS_SITE_SERVER_PORT=4002
|
||
|
||
# Server Configuration
|
||
PORT=3000
|
||
NODE_ENV=production
|
||
|
||
# Session Secret (Generate with: openssl rand -hex 32)
|
||
SESSION_SECRET=your-secure-random-string
|
||
|
||
# Map Defaults (Edmonton, Alberta, Canada)
|
||
DEFAULT_LAT=53.5461
|
||
DEFAULT_LNG=-113.4938
|
||
DEFAULT_ZOOM=11
|
||
|
||
# Optional: Map Boundaries (prevents users from adding points outside area)
|
||
# BOUND_NORTH=53.7
|
||
# BOUND_SOUTH=53.4
|
||
# BOUND_EAST=-113.3
|
||
# BOUND_WEST=-113.7
|
||
|
||
# Cloudflare Settings
|
||
TRUST_PROXY=true
|
||
COOKIE_DOMAIN=.cmlite.org
|
||
|
||
# Allowed Origins
|
||
ALLOWED_ORIGINS=https://map.cmlite.org,http://localhost:3000
|
||
```
|
||
|
||
3. **Auto-Create Database Structure**
|
||
|
||
Run the build script to create required tables:
|
||
```bash
|
||
chmod +x build-nocodb.sh
|
||
./build-nocodb.sh
|
||
```
|
||
|
||
This creates five tables:
|
||
- **Locations** - Main map data with geo-location, contact info, support levels
|
||
- **Login** - User authentication (email, name, admin flag)
|
||
- **Settings** - Admin configuration and QR codes
|
||
- **Shifts** - Shift scheduling and management
|
||
- **Shift Signups** - User shift registrations
|
||
|
||
4. **Get Table URLs**
|
||
|
||
After the script completes:
|
||
1. Login to your NocoDB instance at https://db.cmlite.org
|
||
2. Navigate to your project ("Map Viewer Project - TIMESTAMP")
|
||
3. Copy the view URLs for each table from your browser address bar
|
||
4. URLs should look like: `https://db.cmlite.org/dashboard/#/nc/project-id/table-id`
|
||
|
||
5. **Update Environment with URLs**
|
||
|
||
Edit your `.env` file and add the table URLs:
|
||
```env
|
||
NOCODB_VIEW_URL=https://db.cmlite.org/dashboard/#/nc/pnsalzrup2zqvz8/m6g7bkzv7s1w2ur
|
||
NOCODB_LOGIN_SHEET=https://db.cmlite.org/dashboard/#/nc/pnsalzrup2zqvz8/mizyc64e4r7ppzh
|
||
NOCODB_SETTINGS_SHEET=https://db.cmlite.org/dashboard/#/nc/pnsalzrup2zqvz8/mix06f2mlep7gqb
|
||
NOCODB_SHIFTS_SHEET=https://db.cmlite.org/dashboard/#/nc/pnsalzrup2zqvz8/mkx0tex0iquus1u
|
||
NOCODB_SHIFT_SIGNUPS_SHEET=https://db.cmlite.org/dashboard/#/nc/pnsalzrup2zqvz8/mi8jg1tn26mu8fj
|
||
```
|
||
|
||
6. **Build and Deploy**
|
||
|
||
Build the Docker image and start the application:
|
||
```bash
|
||
# Build the Docker image
|
||
docker-compose build
|
||
|
||
# Start the application
|
||
docker-compose up -d
|
||
```
|
||
|
||
7. **Verify Installation**
|
||
|
||
- Check container status: `docker-compose ps`
|
||
- View logs: `docker-compose logs -f map-viewer`
|
||
- Access the application at: http://localhost:3000
|
||
- Access shift management at: http://localhost:3000/shifts.html
|
||
- Access admin panel at: http://localhost:3000/admin.html (admin users only)
|
||
|
||
## Database Schema
|
||
|
||
The build script automatically creates the following table structure:
|
||
|
||
### Main Locations Table
|
||
- `ID` (ID): Auto-incrementing primary key
|
||
- `Geo-Location` (GeoData): Geographic coordinate data
|
||
- `latitude` (Decimal): Precision 8, Scale 8
|
||
- `longitude` (Decimal): Precision 8, Scale 8
|
||
- `First Name` (Single Line Text): Person's first name
|
||
- `Last Name` (Single Line Text): Person's last name
|
||
- `Email` (Email): Email address
|
||
- `Phone` (PhoneNumber): Phone number with validation
|
||
- `Unit Number` (Single Line Text): Unit or apartment number
|
||
- `Support Level` (Single Select): Options: "1" (Green), "2" (Yellow), "3" (Orange), "4" (Red)
|
||
- `Address` (Single Line Text): Street address
|
||
- `Sign` (Checkbox): Has campaign sign
|
||
- `Sign Size` (Single Select): Options: "Regular" (Blue), "Large" (Green), "Unsure" (Orange)
|
||
- `Notes` (Long Text): Additional details and comments
|
||
- `created_by_user` (Single Line Text): Creator email
|
||
- `last_updated_by_user` (Single Line Text): Last updater email
|
||
|
||
### Login Table
|
||
- `ID` (ID): Auto-incrementing primary key
|
||
- `Email` (Email): User email address (required)
|
||
- `Password` (Single Line Text): User password (required)
|
||
- `Name` (Single Line Text): User display name
|
||
- `Admin` (Checkbox): Admin privileges
|
||
- `Created At` (DateTime): Account creation timestamp
|
||
- `Last Login` (DateTime): Last login timestamp
|
||
|
||
### Settings Table
|
||
- `ID` (ID): Auto-incrementing primary key
|
||
- `created_at` (DateTime): Record creation timestamp
|
||
- `created_by` (Single Line Text): Creator identifier
|
||
- `Geo-Location` (Single Line Text): Format "latitude;longitude"
|
||
- `latitude` (Decimal): Precision 8, Scale 8
|
||
- `longitude` (Decimal): Precision 8, Scale 8
|
||
- `zoom` (Number): Map zoom level
|
||
- `Walk Sheet Title` (Single Line Text): Title for walk sheets
|
||
- `Walk Sheet Subtitle` (Single Line Text): Subtitle for walk sheets
|
||
- `Walk Sheet Footer` (Long Text): Footer text for walk sheets
|
||
- `QR Code 1 URL` (URL): First QR code link
|
||
- `QR Code 1 Label` (Single Line Text): First QR code label
|
||
- `QR Code 2 URL` (URL): Second QR code link
|
||
- `QR Code 2 Label` (Single Line Text): Second QR code label
|
||
- `QR Code 3 URL` (URL): Third QR code link
|
||
- `QR Code 3 Label` (Single Line Text): Third QR code label
|
||
|
||
### Shifts Table
|
||
- `ID` (ID): Auto-incrementing primary key
|
||
- `Title` (Single Line Text): Shift title (required)
|
||
- `Description` (Long Text): Detailed shift description
|
||
- `Date` (Date): Shift date (required)
|
||
- `Start Time` (Time): Shift start time (required)
|
||
- `End Time` (Time): Shift end time (required)
|
||
- `Location` (Single Line Text): Shift location
|
||
- `Max Volunteers` (Number): Maximum volunteer capacity (required)
|
||
- `Current Volunteers` (Number): Current volunteer count
|
||
- `Status` (Single Select): Options: "Open" (Green), "Full" (Orange), "Cancelled" (Red)
|
||
- `Created By` (Single Line Text): Creator identifier
|
||
- `Created At` (DateTime): Creation timestamp
|
||
- `Updated At` (DateTime): Last update timestamp
|
||
|
||
### Shift Signups Table
|
||
- `ID` (ID): Auto-incrementing primary key
|
||
- `Shift ID` (Number): Reference to shifts table (required)
|
||
- `Shift Title` (Single Line Text): Copy of shift title for reference
|
||
- `User Email` (Email): User's email address (required)
|
||
- `User Name` (Single Line Text): User's display name
|
||
- `Signup Date` (DateTime): When user signed up
|
||
- `Status` (Single Select): Options: "Confirmed" (Green), "Cancelled" (Red)
|
||
|
||
## API Endpoints
|
||
|
||
### Public Endpoints
|
||
|
||
- `GET /api/locations` - Fetch all locations (requires auth)
|
||
- `POST /api/locations` - Create new location (requires auth)
|
||
- `GET /api/locations/:id` - Get single location (requires auth)
|
||
- `PUT /api/locations/:id` - Update location (requires auth)
|
||
- `DELETE /api/locations/:id` - Delete location (requires auth)
|
||
- `GET /api/config/start-location` - Get map start location
|
||
- `GET /health` - Health check
|
||
|
||
### Shifts Endpoints (requires authentication)
|
||
|
||
- `GET /api/shifts` - Get all available shifts
|
||
- `GET /api/shifts/my-signups` - Get current user's shift signups
|
||
- `POST /api/shifts/:shiftId/signup` - Sign up for a shift
|
||
- `POST /api/shifts/:shiftId/cancel` - Cancel shift signup
|
||
|
||
### Shifts Admin Endpoints (requires admin privileges)
|
||
|
||
- `GET /api/shifts/admin` - Get all shifts including cancelled ones
|
||
- `POST /api/shifts/admin` - Create new shift
|
||
- `PUT /api/shifts/admin/:id` - Update existing shift
|
||
- `DELETE /api/shifts/admin/:id` - Delete shift
|
||
|
||
### Authentication Endpoints
|
||
|
||
- `POST /api/auth/login` - User login
|
||
- `GET /api/auth/check` - Check authentication status
|
||
- `POST /api/auth/logout` - User logout
|
||
|
||
### Admin Endpoints (requires admin privileges)
|
||
|
||
- `GET /api/admin/start-location` - Get start location with source info
|
||
- `POST /api/admin/start-location` - Update map start location
|
||
- `GET /api/admin/walk-sheet-config` - Get walk sheet configuration
|
||
- `POST /api/admin/walk-sheet-config` - Save walk sheet configuration
|
||
|
||
## Shifts Management
|
||
|
||
The application includes a comprehensive volunteer shift management system accessible at `/shifts.html`.
|
||
|
||
### User Features
|
||
|
||
- **Dual View Options**: Toggle between grid view and calendar view for shift display
|
||
- **Calendar View**: Interactive monthly calendar showing shifts with color-coded indicators:
|
||
- Green: Shifts you've signed up for
|
||
- Blue: Available shifts you can join
|
||
- Gray: Full shifts (no spots available)
|
||
- **View Available Shifts**: See all upcoming shifts with date, time, and capacity information
|
||
- **Sign Up for Shifts**: One-click signup for available shifts (works in both views)
|
||
- **My Shifts Dashboard**: View all your current shift signups at the top of the page
|
||
- **Cancel Signups**: Cancel your shift signups when needed
|
||
- **Date Filtering**: Filter shifts by specific dates (applies to both views)
|
||
- **Real-time Updates**: Shift availability updates dynamically
|
||
- **Interactive Calendar**: Click on calendar shifts for detailed popup with signup options
|
||
- **Calendar Navigation**: Navigate between months to view future shifts
|
||
|
||
### Admin Features
|
||
|
||
Administrators have additional capabilities for managing shifts:
|
||
|
||
- **Create New Shifts**: Add new volunteer shifts with date, time, location, and capacity
|
||
- **Edit Existing Shifts**: Modify shift details, times, or capacity
|
||
- **Cancel Shifts**: Mark shifts as cancelled (they remain in system but hidden from users)
|
||
- **View All Signups**: See who has signed up for each shift
|
||
- **Manage Capacity**: Set maximum number of volunteers per shift
|
||
|
||
### Shift Status System
|
||
|
||
- **Active**: Available for signups
|
||
- **Full**: Capacity reached, no more signups accepted
|
||
- **Cancelled**: Hidden from public view but retained in database
|
||
|
||
## Admin Panel
|
||
|
||
Users with admin privileges can access the admin panel at `/admin.html` to configure system settings.
|
||
|
||
### Features
|
||
|
||
#### Start Location Configuration
|
||
|
||
- **Interactive Map**: Visual interface for selecting coordinates
|
||
- **Real-time Preview**: See changes immediately on the admin map
|
||
- **Validation**: Built-in coordinate and zoom level validation
|
||
|
||
#### Walk Sheet Generator
|
||
|
||
- **Printable Forms**: Generate 8.5x11 walk sheets for door-to-door canvassing
|
||
- **QR Code Integration**: Add up to 3 QR codes with custom URLs and labels
|
||
- **Form Field Matching**: Automatically matches fields from the main location form
|
||
- **Live Preview**: See changes as you type
|
||
- **Print Optimization**: Proper formatting for printing or PDF export
|
||
- **Persistent Storage**: All QR codes and settings saved to NocoDB
|
||
|
||
#### Shift Management
|
||
|
||
- **Create Shifts**: Set up volunteer shifts with dates, times, and capacity
|
||
- **Manage Volunteers**: View signups and manage shift participants
|
||
- **Real-time Updates**: See shift status changes immediately
|
||
|
||
#### User Management
|
||
|
||
- **Create Users**: Add new user accounts with email and password
|
||
- **Role Assignment**: Assign admin or user privileges
|
||
- **User List**: View all registered users with their details and creation dates
|
||
- **Delete Users**: Remove user accounts (with confirmation prompts)
|
||
- **Security**: Password validation and admin-only access
|
||
|
||
### Access Control
|
||
|
||
- Admin access is controlled via the `Admin` checkbox in the Login table
|
||
- Only authenticated users with admin privileges can access `/admin.html`
|
||
- Admin status is checked on every request to admin endpoints
|
||
- User management functions are restricted to admin users only
|
||
|
||
### Start Location Priority
|
||
|
||
The system uses a cascading fallback system for map start location:
|
||
1. **Database**: Admin-configured location stored in Settings table (highest priority)
|
||
2. **Environment**: Default values from .env file (medium priority)
|
||
3. **Hardcoded**: Edmonton, Canada coordinates (lowest priority)
|
||
|
||
## Configuration
|
||
|
||
All configuration is done via environment variables:
|
||
|
||
| Variable | Description | Default |
|
||
|----------|-------------|---------|
|
||
| `NOCODB_API_URL` | NocoDB API base URL | Required |
|
||
| `NOCODB_API_TOKEN` | API authentication token | Required |
|
||
| `NOCODB_VIEW_URL` | Full NocoDB view URL for locations table | Required |
|
||
| `NOCODB_LOGIN_SHEET` | Login table URL for authentication | Required |
|
||
| `NOCODB_SETTINGS_SHEET` | Settings table URL for admin config | Required |
|
||
| `NOCODB_SHIFTS_SHEET` | Shifts table URL for shift management | Required |
|
||
| `NOCODB_SHIFT_SIGNUPS_SHEET` | Shift signups table URL for user registrations | Required |
|
||
| `DOMAIN` | Primary domain for the application | Required |
|
||
| `MKDOCS_URL` | MkDocs documentation site URL | Optional |
|
||
| `MKDOCS_SEARCH_URL` | MkDocs search endpoint URL | Optional |
|
||
| `MKDOCS_SITE_SERVER_PORT` | Port for MkDocs integration | 4002 |
|
||
| `PORT` | Server port | 3000 |
|
||
| `NODE_ENV` | Environment mode | production |
|
||
| `SESSION_SECRET` | Session encryption secret (generate with openssl rand -hex 32) | Required |
|
||
| `DEFAULT_LAT` | Default map latitude | 53.5461 |
|
||
| `DEFAULT_LNG` | Default map longitude | -113.4938 |
|
||
| `DEFAULT_ZOOM` | Default map zoom level | 11 |
|
||
| `BOUND_NORTH` | Northern boundary for map points (optional) | None |
|
||
| `BOUND_SOUTH` | Southern boundary for map points (optional) | None |
|
||
| `BOUND_EAST` | Eastern boundary for map points (optional) | None |
|
||
| `BOUND_WEST` | Western boundary for map points (optional) | None |
|
||
| `TRUST_PROXY` | Trust proxy headers (for Cloudflare) | true |
|
||
| `COOKIE_DOMAIN` | Cookie domain setting | .cmlite.org |
|
||
| `ALLOWED_ORIGINS` | CORS allowed origins (comma-separated) | Multiple URLs |
|
||
|
||
## Maintenance Commands
|
||
|
||
### Update Application
|
||
```bash
|
||
docker-compose down
|
||
git pull origin main
|
||
docker-compose build
|
||
docker-compose up -d
|
||
```
|
||
|
||
### Development Mode
|
||
```bash
|
||
cd app
|
||
npm install
|
||
npm run dev
|
||
```
|
||
|
||
### Health Check
|
||
```bash
|
||
curl http://localhost:3000/health
|
||
```
|
||
|
||
## Development
|
||
|
||
To run in development mode:
|
||
|
||
1. Install dependencies:
|
||
```bash
|
||
cd app
|
||
npm install
|
||
```
|
||
|
||
2. Start with hot reload:
|
||
```bash
|
||
npm run dev
|
||
```
|
||
|
||
## Security Considerations
|
||
|
||
- API tokens are kept server-side only
|
||
- CORS is configured for security
|
||
- Rate limiting prevents abuse
|
||
- Input validation on all endpoints
|
||
- Helmet.js for security headers
|
||
|
||
## Troubleshooting
|
||
|
||
### Locations not showing
|
||
|
||
- Verify table has `Geo-Location`, `latitude`, and `longitude` columns
|
||
- Check that coordinates are valid numbers
|
||
- Ensure API token has read permissions
|
||
|
||
### Cannot add locations
|
||
|
||
- Verify API token has write permissions
|
||
- Check browser console for errors
|
||
- Ensure coordinates are within valid ranges
|
||
|
||
### Connection errors
|
||
|
||
- Verify NocoDB instance is accessible
|
||
- Check API URL format
|
||
- Confirm network connectivity
|
||
|
||
### Build Script Issues
|
||
|
||
- Ensure NocoDB instance is accessible
|
||
- Verify API token has admin permissions
|
||
- Check that the NocoDB database is clean (delete all bases before running)
|
||
|
||
## License
|
||
|
||
MIT License - See LICENSE file for details
|
||
|
||
## Support
|
||
|
||
For issues or questions:
|
||
1. Check the troubleshooting section
|
||
2. Review NocoDB documentation
|
||
3. Open an issue on GitHub
|
||
|
||
## Known Bugs
|
||
|
||
- First load of page often fails, need to debug
|
||
- Want UI for dots to have an edit button that then brings up the form |