data | ||
frontend | ||
.air.toml | ||
.dockerignore | ||
.gitignore | ||
build-and-push.sh | ||
Containerfile | ||
dev-docker.sh | ||
dev.sh | ||
docker-compose.dev.yml | ||
docker-compose.yml | ||
Dockerfile.dev | ||
go.mod | ||
go.sum | ||
main.go | ||
podman-compose.yml | ||
README.md |
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
- 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
- Initial Connection: When a client connects to a checklist, the SSE endpoint sends the complete current state
- Real-time Updates: All subsequent changes (add, update, delete, lock) are broadcast via SSE
- 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
-
Initialize the Go module (already done):
go mod init gocheck
-
Install dependencies:
go mod tidy
-
Build the application:
go build
-
Run the server:
./gocheck
Or use the demo script for a guided experience:
./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:
# 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:
# 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
anddocker-compose
- Alternative compose file available:
podman-compose.yml
Using Docker
# 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)# 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
# 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
- Start the backend server:
./gocheck
- Start the frontend dev server:
cd frontend && npm run dev
- Access the app at:
http://localhost:5173
(frontend dev server) - 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 checklistPOST /api/checklists/{uuid}/items
- Add an item to a checklistPATCH /api/checklists/{uuid}/items/{id}
- Update an itemDELETE /api/checklists/{uuid}/items/{id}
- Delete an itemPOST /api/checklists/{uuid}/items/{id}/lock
- Lock an item for editingGET /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:
{
"success": true,
"message": "Operation completed successfully"
// ... additional data specific to the endpoint
}
Example Responses
Create Checklist:
{
"success": true,
"message": "Checklist created successfully",
"uuid": "123e4567-e89b-12d3-a456-426614174000"
}
Add Item:
{
"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": []
}
}
Update Item:
{
"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]
}
}
Delete Item:
{
"success": true,
"message": "Item deleted successfully",
"id": 1
}
Lock Item:
{
"success": true,
"message": "Item locked successfully",
"id": 1,
"locked_by": "user123",
"expires": "2024-01-01T12:00:00Z"
}
Get Items:
{
"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": []
},
{
"id": 2,
"content": "Item 2",
"checked": true,
"parent_id": null,
"checklist_uuid": "123e4567-e89b-12d3-a456-426614174000",
"dependencies": [1]
}
]
}
Dependencies
github.com/google/uuid
- UUID generationgithub.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 relationshipsdependencies
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
- Add Dependencies: Click the dependency icon (⚡) on any item to open the dependency manager
- Select Prerequisites: Choose which items must be completed first
- Visual Feedback: Items show dependency status with color-coded
indicators:
- 🟠 Orange: Dependencies not met (shows count)
- 🟢 Green: All dependencies met (shows "Ready")
- 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
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:
# 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
# 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
# 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:
- Port conflicts: Ensure ports 8080 and 5173 are not in use
- Permission issues: The container runs with appropriate permissions
- Hot reload not working: Check that your files are being watched by the respective tools
- Container won't start: Check Docker logs with
docker-compose -f docker-compose.dev.yml logs