571 lines
16 KiB
Markdown
571 lines
16 KiB
Markdown
# GoCheck - Collaborative Checklist Application
|
|
|
|
A real-time collaborative checklist application built with Go and React,
|
|
featuring Server-Sent Events (SSE) for live updates and SQLite for data
|
|
persistence.
|
|
|
|
## Features
|
|
|
|
- Create and manage checklists
|
|
- Add, update, and delete checklist items
|
|
- Real-time collaboration with Server-Sent Events
|
|
- Item locking mechanism to prevent conflicts
|
|
- Hierarchical items (parent-child relationships)
|
|
- **Item dependencies: Define prerequisites for completing items**
|
|
- **Date constraints: Set "not before" and "not after" times for item
|
|
completion**
|
|
- SQLite database for data persistence
|
|
- **Modern web frontend with React and TypeScript**
|
|
- **Real-time updates across multiple browser tabs/windows**
|
|
- **SSE-first architecture: All data flows through Server-Sent Events**
|
|
|
|
## Architecture
|
|
|
|
### SSE-First Design
|
|
|
|
This application follows an **SSE-first architecture** where all checklist data
|
|
flows through Server-Sent Events:
|
|
|
|
- **No API calls for data retrieval**: The frontend never calls the
|
|
`/api/checklists/{uuid}/items` endpoint
|
|
- **SSE as primary data source**: All checklist items are received via SSE
|
|
streaming
|
|
- **Real-time state management**: The frontend maintains state purely through
|
|
SSE events
|
|
- **Immediate updates**: Changes appear instantly across all connected clients
|
|
|
|
#### Data Flow
|
|
|
|
1. **Initial Connection**: When a client connects to a checklist, the SSE
|
|
endpoint sends the complete current state
|
|
2. **Real-time Updates**: All subsequent changes (add, update, delete, lock) are
|
|
broadcast via SSE
|
|
3. **State Synchronization**: The frontend updates its local state based on SSE
|
|
events without API calls
|
|
|
|
This design ensures:
|
|
|
|
- **Consistency**: All clients see the same data at the same time
|
|
- **Performance**: No unnecessary API calls to reload data
|
|
- **Real-time Experience**: Changes appear instantly across all connected
|
|
browsers
|
|
- **Scalability**: Reduces server load by eliminating polling
|
|
|
|
## Prerequisites
|
|
|
|
- Go 1.16 or later
|
|
- SQLite3 (usually included with Go)
|
|
|
|
## Setup
|
|
|
|
1. **Initialize the Go module** (already done):
|
|
```bash
|
|
go mod init gocheck
|
|
```
|
|
|
|
2. **Install dependencies**:
|
|
```bash
|
|
go mod tidy
|
|
```
|
|
|
|
3. **Build the application**:
|
|
```bash
|
|
go build
|
|
```
|
|
|
|
4. **Run the server**:
|
|
```bash
|
|
./gocheck
|
|
```
|
|
|
|
Or use the demo script for a guided experience:
|
|
```bash
|
|
./demo.sh
|
|
```
|
|
|
|
The server will start on `http://localhost:8080`
|
|
|
|
## Deployment
|
|
|
|
The application is built as a single binary with embedded static files, making
|
|
deployment simple:
|
|
|
|
- **Single Executable**: The `gocheck` binary contains all necessary files
|
|
- **No External Dependencies**: Just copy the binary to your server
|
|
- **Cross-Platform**: Build for different platforms as needed
|
|
|
|
### Binary Deployment
|
|
|
|
To build for different platforms:
|
|
|
|
```bash
|
|
# Linux
|
|
GOOS=linux GOARCH=amd64 go build -o gocheck-linux
|
|
|
|
# Windows
|
|
GOOS=windows GOARCH=amd64 go build -o gocheck.exe
|
|
|
|
# macOS
|
|
GOOS=darwin GOARCH=amd64 go build -o gocheck-macos
|
|
```
|
|
|
|
### Container Deployment
|
|
|
|
The application includes a multi-stage Containerfile for containerized
|
|
deployment:
|
|
|
|
#### Using Podman (Recommended)
|
|
|
|
The application is optimized for rootless Podman operation:
|
|
|
|
```bash
|
|
# Build and run with the provided script
|
|
./build-container.sh
|
|
|
|
# Or manually:
|
|
podman build -t gocheck -f Containerfile .
|
|
podman run -d --name gocheck-container -p 8080:8080 -v gocheck-data:/app gocheck
|
|
|
|
# With custom port:
|
|
PORT=3000 ./build-container.sh
|
|
# Or manually:
|
|
podman run -d --name gocheck-container -p 3000:8080 -e PORT=8080 -v gocheck-data:/app gocheck
|
|
|
|
# Using Podman Compose (recommended for rootless):
|
|
podman-compose -f podman-compose.yml up -d
|
|
|
|
# Or with Docker Compose (also works with Podman):
|
|
docker-compose up -d
|
|
```
|
|
|
|
**Rootless Podman Compatibility:**
|
|
|
|
- Uses UID/GID 1000 for better user mapping
|
|
- Includes security options for rootless operation
|
|
- Supports both `podman-compose` and `docker-compose`
|
|
- Alternative compose file available: `podman-compose.yml`
|
|
|
|
#### Using Docker
|
|
|
|
```bash
|
|
# Build the image
|
|
docker build -t gocheck -f Containerfile .
|
|
|
|
# Run the container
|
|
docker run -d --name gocheck-container -p 8080:8080 -v gocheck-data:/app gocheck
|
|
|
|
# With custom port:
|
|
docker run -d --name gocheck-container -p 3000:8080 -e PORT=8080 -v gocheck-data:/app gocheck
|
|
```
|
|
|
|
#### Container Features
|
|
|
|
- **Multi-stage build**: Uses Go Alpine for building, Alpine for runtime
|
|
- **Minimal footprint**: Runtime container is optimized for size
|
|
- **Persistent data**: SQLite database is stored in a named volume
|
|
- **Security**: Runs as non-root user with UID 1000
|
|
- **Rootless Podman compatible**: Optimized for rootless container operation
|
|
- **Configurable**: Supports environment variables for customization
|
|
|
|
#### Environment Variables
|
|
|
|
- `PORT`: Set the port the application listens on (default: 8080)
|
|
```bash
|
|
# Example: Run on port 3000
|
|
PORT=3000 ./build-container.sh
|
|
```
|
|
|
|
## Frontend
|
|
|
|
The application includes a modern web frontend built with **React**:
|
|
|
|
- **Single Page Application**: No page reloads needed
|
|
- **Home Page**: Welcome page for creating new checklists
|
|
- **Checklist Page**: Dedicated page for viewing and editing checklists
|
|
- **Local Storage**: Automatically saves and lists your checklists
|
|
- **Real-time Updates**: Changes appear instantly across all connected browsers
|
|
- **Responsive Design**: Works on desktop and mobile devices
|
|
- **Item Locking**: Visual indicators when items are being edited
|
|
- **Hierarchical Items**: Support for parent-child relationships
|
|
- **Modern UI**: Clean, intuitive interface
|
|
- **TypeScript**: Full type safety and better developer experience
|
|
- **Component-based**: Modular, maintainable code structure
|
|
- **URL-based Routing**: Share checklist URLs directly
|
|
- **ESLint**: Code quality enforcement with no-semicolon style
|
|
|
|
### Frontend Development
|
|
|
|
The frontend is located in the `frontend/` directory and uses:
|
|
|
|
- **React**: Modern JavaScript library for building user interfaces
|
|
- **TypeScript**: Type-safe JavaScript
|
|
- **Vite**: Fast build tool and dev server
|
|
- **CSS Modules**: Scoped styling
|
|
|
|
#### Development Commands
|
|
|
|
```bash
|
|
# Install dependencies
|
|
cd frontend && npm install
|
|
|
|
# Start development server (with API proxy)
|
|
cd frontend && npm run dev
|
|
|
|
# Build for production
|
|
cd frontend && npm run build
|
|
|
|
# Lint code (check for issues)
|
|
cd frontend && npm run lint
|
|
|
|
# Lint and auto-fix issues
|
|
cd frontend && npm run lint:fix
|
|
|
|
# Build frontend and copy to static directory
|
|
./build-frontend.sh
|
|
```
|
|
|
|
#### Development Workflow
|
|
|
|
1. Start the backend server: `./gocheck`
|
|
2. Start the frontend dev server: `cd frontend && npm run dev`
|
|
3. Access the app at: `http://localhost:5173` (frontend dev server)
|
|
4. The frontend will proxy API requests to the backend at
|
|
`http://localhost:8080`
|
|
|
|
Simply open `http://localhost:8080` in your browser to use the production
|
|
application.
|
|
|
|
#### Page Structure
|
|
|
|
- **Home Page** (`/`): Welcome page with option to create new checklists and
|
|
view saved checklists
|
|
- **Checklist Page** (/{uuid}`): View and edit specific checklists
|
|
- when opening this route and that checklistid is not yet saved into
|
|
localstorage it should be committed there
|
|
- **URL Sharing**: Share checklist URLs directly with others for collaboration
|
|
- **Local Storage**: Checklists are automatically saved and can be renamed or
|
|
removed from the home page
|
|
|
|
## API Endpoints
|
|
|
|
### Checklists
|
|
|
|
- `POST /api/checklists` - Create a new checklist
|
|
- `POST /api/checklists/{uuid}/items` - Add an item to a checklist
|
|
- `PATCH /api/checklists/{uuid}/items/{id}` - Update an item
|
|
- `DELETE /api/checklists/{uuid}/items/{id}` - Delete an item
|
|
- `POST /api/checklists/{uuid}/items/{id}/lock` - Lock an item for editing
|
|
- `GET /api/checklists/{uuid}/sse` - Server-Sent Events stream for real-time
|
|
updates (primary data source)
|
|
|
|
**Note**: The `GET /api/checklists/{uuid}/items` endpoint exists but is not used
|
|
by the frontend. All data flows through the SSE endpoint for real-time updates.
|
|
|
|
### API Response Format
|
|
|
|
All API endpoints return JSON responses with a consistent format:
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Operation completed successfully"
|
|
// ... additional data specific to the endpoint
|
|
}
|
|
```
|
|
|
|
#### Example Responses
|
|
|
|
**Create Checklist:**
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Checklist created successfully",
|
|
"uuid": "123e4567-e89b-12d3-a456-426614174000"
|
|
}
|
|
```
|
|
|
|
**Add Item:**
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Item added successfully",
|
|
"item": {
|
|
"id": 1,
|
|
"content": "New item",
|
|
"checked": false,
|
|
"parent_id": null,
|
|
"checklist_uuid": "123e4567-e89b-12d3-a456-426614174000",
|
|
"dependencies": [],
|
|
"not_before": "2025-07-25T16:20:00Z",
|
|
"not_after": "2025-07-25T18:00:00Z"
|
|
}
|
|
}
|
|
```
|
|
|
|
**Update Item:**
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Item updated successfully",
|
|
"item": {
|
|
"id": 1,
|
|
"content": "Updated content",
|
|
"checked": true,
|
|
"parent_id": null,
|
|
"checklist_uuid": "123e4567-e89b-12d3-a456-426614174000",
|
|
"dependencies": [2, 3],
|
|
"not_before": "2025-07-25T16:20:00Z",
|
|
"not_after": "2025-07-25T18:00:00Z"
|
|
}
|
|
}
|
|
```
|
|
|
|
**Delete Item:**
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Item deleted successfully",
|
|
"id": 1
|
|
}
|
|
```
|
|
|
|
**Lock Item:**
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Item locked successfully",
|
|
"id": 1,
|
|
"locked_by": "user123",
|
|
"expires": "2024-01-01T12:00:00Z"
|
|
}
|
|
```
|
|
|
|
**Get Items:**
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Items loaded successfully",
|
|
"items": [
|
|
{
|
|
"id": 1,
|
|
"content": "Item 1",
|
|
"checked": false,
|
|
"parent_id": null,
|
|
"checklist_uuid": "123e4567-e89b-12d3-a456-426614174000",
|
|
"dependencies": [],
|
|
"not_before": null,
|
|
"not_after": null
|
|
},
|
|
{
|
|
"id": 2,
|
|
"content": "Item 2",
|
|
"checked": true,
|
|
"parent_id": null,
|
|
"checklist_uuid": "123e4567-e89b-12d3-a456-426614174000",
|
|
"dependencies": [1],
|
|
"not_before": "2025-07-25T16:20:00Z",
|
|
"not_after": null
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
## Dependencies
|
|
|
|
- `github.com/google/uuid` - UUID generation
|
|
- `github.com/mattn/go-sqlite3` - SQLite driver for Go
|
|
|
|
## Database
|
|
|
|
The application uses SQLite with the following schema:
|
|
|
|
- `checklist_info` table: Stores checklist metadata (uuid, name)
|
|
- `items` table: Stores checklist items with hierarchical relationships and date
|
|
constraints
|
|
- `dependencies` table: Stores item dependencies (item_id, dependency_id)
|
|
|
|
## Real-time Features
|
|
|
|
- **SSE-first architecture**: All data flows through Server-Sent Events
|
|
- **Real-time state synchronization**: No API polling required
|
|
- **Item locking with automatic expiration** (30 seconds)
|
|
- **Broadcast updates to all connected clients**
|
|
- **Immediate UI updates**: Changes appear instantly across all browsers
|
|
|
|
## Item Dependencies
|
|
|
|
The application supports item dependencies, allowing you to define prerequisites
|
|
that must be completed before an item can be marked as done.
|
|
|
|
### How Dependencies Work
|
|
|
|
- **Prerequisites**: Items can depend on other items being completed first
|
|
- **Visual Indicators**: Items with unmet dependencies show warning indicators
|
|
- **Prevention**: Items cannot be completed until all dependencies are satisfied
|
|
- **Circular Prevention**: The system prevents circular dependencies
|
|
- **Real-time Updates**: Dependency status updates in real-time across all
|
|
clients
|
|
|
|
### Managing Dependencies
|
|
|
|
1. **Add Dependencies**: Click the dependency icon (⚡) on any item to open the
|
|
dependency manager
|
|
2. **Select Prerequisites**: Choose which items must be completed first
|
|
3. **Visual Feedback**: Items show dependency status with color-coded
|
|
indicators:
|
|
- 🟠 Orange: Dependencies not met (shows count)
|
|
- 🟢 Green: All dependencies met (shows "Ready")
|
|
4. **Completion Prevention**: Items with unmet dependencies cannot be checked
|
|
off
|
|
|
|
### Dependency Features
|
|
|
|
- **Flexible Dependencies**: Items can depend on any number of other items
|
|
- **Hierarchical Support**: Dependencies work with parent-child relationships
|
|
- **Real-time Validation**: Dependency status updates immediately when items are
|
|
completed
|
|
- **Clear Feedback**: Users see exactly which items need to be completed first
|
|
- **Error Prevention**: System prevents circular dependencies automatically
|
|
|
|
## Item Date Constraints
|
|
|
|
The application supports date constraints, allowing you to set time windows when
|
|
items can be completed.
|
|
|
|
### How Date Constraints Work
|
|
|
|
- **Not Before**: Set the earliest time an item can be completed
|
|
- **Not After**: Set the latest time an item can be completed
|
|
- **Validation**: Items cannot be completed outside their allowed time window
|
|
- **Visual Indicators**: Items show date constraint status with color-coded
|
|
indicators
|
|
- **Real-time Updates**: Constraint status updates in real-time
|
|
|
|
### Managing Date Constraints
|
|
|
|
1. **Set Constraints**: Click the clock icon (🕐) on any item to open the date
|
|
constraint manager
|
|
2. **Configure Times**: Set "not before" and/or "not after" times
|
|
3. **Visual Feedback**: Items show constraint status:
|
|
- 🟢 Green: Time constraints met (shows "Ready")
|
|
- 🔴 Red: Time constraints not met (shows "Time locked")
|
|
4. **Completion Prevention**: Items cannot be checked off outside their time
|
|
window
|
|
|
|
### Date Constraint Features
|
|
|
|
- **Flexible Scheduling**: Set any combination of start and end times
|
|
- **ISO 8601 Format**: Uses standard datetime format for precision
|
|
- **Real-time Validation**: Constraint status updates immediately
|
|
- **Clear Feedback**: Users see exactly when items can be completed
|
|
- **Error Prevention**: System prevents completion outside allowed times
|
|
|
|
### Example Use Cases
|
|
|
|
- **Meeting Preparation**: Set items to be completed before a meeting starts
|
|
- **Deadline Management**: Set items to be completed by a specific deadline
|
|
- **Time-sensitive Tasks**: Ensure tasks are completed within business hours
|
|
- **Sequential Workflows**: Use in combination with dependencies for complex
|
|
workflows
|
|
|
|
## Development
|
|
|
|
### Local Development
|
|
|
|
To run in development mode with automatic reloading, you can use tools like
|
|
`air` or `realize`.
|
|
|
|
#### Using the Development Script
|
|
|
|
The project includes a development script that runs both backend and frontend
|
|
with hot reloading:
|
|
|
|
```bash
|
|
# Start development environment
|
|
./dev.sh
|
|
```
|
|
|
|
This will:
|
|
|
|
- Start the Go backend with Air for hot reloading
|
|
- Start the React frontend with Vite for hot reloading
|
|
- Proxy API requests from frontend to backend
|
|
- Clean up processes on exit
|
|
|
|
### Docker Development
|
|
|
|
For a consistent development environment using Docker with hot reloading:
|
|
|
|
#### Prerequisites
|
|
|
|
- Docker and Docker Compose installed
|
|
- Ports 8080 and 5173 available
|
|
|
|
#### Quick Start
|
|
|
|
```bash
|
|
# Start development environment with Docker
|
|
./dev-docker.sh
|
|
```
|
|
|
|
This will:
|
|
|
|
- Build a development container with all dependencies
|
|
- Mount your source code for hot reloading
|
|
- Start both backend (Air) and frontend (Vite) with hot reloading
|
|
- Make the application available at:
|
|
- Backend: http://localhost:8080
|
|
- Frontend: http://localhost:5173
|
|
|
|
#### Manual Docker Commands
|
|
|
|
```bash
|
|
# Build and start the development container
|
|
docker-compose -f docker-compose.dev.yml up --build
|
|
|
|
# Stop the development container
|
|
docker-compose -f docker-compose.dev.yml down
|
|
|
|
# View logs
|
|
docker-compose -f docker-compose.dev.yml logs -f
|
|
|
|
# Rebuild the container
|
|
docker-compose -f docker-compose.dev.yml up --build --force-recreate
|
|
```
|
|
|
|
#### Development Features
|
|
|
|
The Docker development environment includes:
|
|
|
|
- **Hot Reloading**: Both Go backend and React frontend reload automatically on
|
|
code changes
|
|
- **Volume Mounts**: Your local code is mounted into the container for live
|
|
editing
|
|
- **Dependency Management**: All dependencies are pre-installed in the container
|
|
- **Consistent Environment**: Same environment across all developers
|
|
- **Easy Cleanup**: Simple commands to start/stop the development environment
|
|
|
|
#### File Watching
|
|
|
|
The development container uses:
|
|
|
|
- **Air** for Go backend hot reloading (watches `.go` files)
|
|
- **Vite** for React frontend hot reloading (watches all frontend files)
|
|
- **inotify-tools** for efficient file system watching
|
|
|
|
#### Troubleshooting
|
|
|
|
If you encounter issues:
|
|
|
|
1. **Port conflicts**: Ensure ports 8080 and 5173 are not in use
|
|
2. **Permission issues**: The container runs with appropriate permissions
|
|
3. **Hot reload not working**: Check that your files are being watched by the
|
|
respective tools
|
|
4. **Container won't start**: Check Docker logs with
|
|
`docker-compose -f docker-compose.dev.yml logs`
|