| .. | ||
| app | ||
| cmd | ||
| config | ||
| docs | ||
| internal | ||
| migrations | ||
| pkg | ||
| static/blacklist | ||
| .claudeignore | ||
| .dockerignore | ||
| .env.sample | ||
| .gitignore | ||
| dev.Dockerfile | ||
| docker-compose.dev.yml | ||
| Dockerfile | ||
| go.mod | ||
| go.sum | ||
| main.go | ||
| README.md | ||
| Taskfile.yml | ||
🚀 MaplePress Backend
Cloud-powered services platform for WordPress sites - Multi-tenant SaaS backend built with Go.
MaplePress offloads computationally intensive tasks from WordPress to improve site performance. Features include cloud-powered search (Meilisearch), JWT authentication for users, API key authentication for WordPress plugins, and multi-tenant architecture.
📋 Prerequisites
⚠️ Required: You must have the infrastructure running first.
If you haven't set up the infrastructure yet:
- Go to
../infrastructure/README.md - Follow the setup instructions
- Come back here once infrastructure is running
Verify infrastructure is healthy:
cd cloud/infrastructure/development
task dev:status
# All services should show (healthy)
🏁 Getting Started
Installation
# From the monorepo root:
cd cloud/maplepress-backend
# Create environment file:
cp .env.sample .env
# Start the backend:
task dev
The backend runs at http://localhost:8000
Verify Installation
Open a new terminal (leave task dev running):
curl http://localhost:8000/health
# Should return: {"status":"healthy"}
Note: Your first terminal shows backend logs. Keep it running and use a second terminal for testing.
💻 Developing
Initial Configuration
Environment Files:
.env.sample- Template with defaults (committed to git).env- Your local configuration (git-ignored, created from.env.sample)- Use only
.envfor configuration (docker-compose loads this file)
The .env file defaults work for Docker development. Optional: Change APP_JWT_SECRET to a random string (use a password generator).
Running in Development Mode
# Start backend with hot-reload
task dev
# View logs (in another terminal)
docker logs -f maplepress-backend-dev
# Stop backend
task dev:down
# Or press Ctrl+C in the task dev terminal
What happens when you run task dev:
- Docker starts the backend container
- Auto-migrates database tables
- Starts HTTP server on port 8000
- Enables hot-reload (auto-restarts on code changes)
Wait for: Server started on :8000 in the logs
Daily Workflow
# Morning - check infrastructure (from monorepo root)
cd cloud/infrastructure/development && task dev:status
# Start backend (from monorepo root)
cd cloud/maplepress-backend && task dev
# Make code changes - backend auto-restarts
# Stop backend when done
# Press Ctrl+C
Testing
# Run all tests
task test
# Code quality checks
task format # Format code
task lint # Run linters
Database Operations
View database:
# From monorepo root
cd cloud/infrastructure/development
task cql
# Inside cqlsh:
USE maplepress;
DESCRIBE TABLES;
SELECT * FROM sites_by_id;
Reset database (⚠️ deletes all data):
task db:clear
🔧 Usage
Testing the API
Create a test user and site to verify the backend works:
1. Register a user:
curl -X POST http://localhost:8000/api/v1/register \
-H "Content-Type: application/json" \
-d '{
"email": "test@example.com",
"password": "MySecureP@ssw0rd2024!XyZ",
"name": "Test User",
"tenant_name": "Test Organization",
"tenant_slug": "test-org",
"agree_terms_of_service": true
}'
Note: MaplePress checks passwords against the Have I Been Pwned database. If your password has been found in data breaches, registration will fail. Use a strong, unique password that hasn't been compromised.
Response:
{
"user_id": "uuid-here",
"user_email": "test@example.com",
"user_name": "Test User",
"tenant_id": "uuid-here",
"tenant_name": "Test Organization",
"access_token": "eyJhbGci...",
"refresh_token": "eyJhbGci...",
"access_expiry": "2025-10-29T12:00:00Z",
"refresh_expiry": "2025-11-05T12:00:00Z"
}
Save the access_token from the response:
export TOKEN="eyJhbGci...your-access-token-here"
2. Get your profile:
curl http://localhost:8000/api/v1/me \
-H "Authorization: JWT $TOKEN"
3. Create a WordPress site:
curl -X POST http://localhost:8000/api/v1/sites \
-H "Content-Type: application/json" \
-H "Authorization: JWT $TOKEN" \
-d '{
"domain": "localhost:8081",
"site_url": "http://localhost:8081"
}'
Save the api_key from the response (shown only once):
export API_KEY="your-api-key-here"
4. Test plugin authentication:
curl http://localhost:8000/api/v1/plugin/status \
-H "Authorization: Bearer $API_KEY"
WordPress Plugin Integration
Access WordPress:
- URL: http://localhost:8081/wp-admin
- Credentials: admin / admin
Configure the plugin:
- Go to Settings → MaplePress
- Enter:
- API URL:
http://maplepress-backend-dev:8000 - API Key: Your API key from step 3 above
- API URL:
- Click Save Settings & Verify Connection
⚠️ Important: Use the container name (maplepress-backend-dev), not localhost, because WordPress runs in Docker.
Next steps:
- WordPress plugin setup:
../../native/wordpress/README.md - Complete API documentation:
docs/API/README.md
Error Handling
MaplePress uses RFC 9457 (Problem Details for HTTP APIs) for standardized error responses. All errors return a consistent, machine-readable format:
{
"type": "about:blank",
"title": "Validation Error",
"status": 400,
"detail": "One or more validation errors occurred",
"errors": {
"email": ["Invalid email format"],
"password": ["Password must be at least 8 characters"]
}
}
Benefits:
- 📋 Structured, predictable error format
- 🤖 Machine-readable for frontend parsing
- 🌍 Industry standard (RFC 9457)
- 🔍 Field-level validation errors
See docs/API/README.md#error-handling for complete error documentation.
⚙️ Configuration
Environment Variables
Key variables in .env:
| Variable | Default | Description |
|---|---|---|
APP_JWT_SECRET |
change-me-in-production-use-a-long-random-string |
Secret for JWT token signing |
SERVER_PORT |
8000 |
HTTP server port |
DATABASE_HOSTS |
cassandra-1,cassandra-2,cassandra-3 |
Cassandra cluster nodes |
CACHE_HOST |
redis |
Redis cache host |
MEILISEARCH_HOST |
http://meilisearch:7700 |
Search engine URL |
Docker vs Local:
- Docker: Uses container names (
cassandra-1,redis) - Local: Change to
localhost
See .env.sample for complete documentation.
Task Commands
| Command | Description |
|---|---|
task dev |
Start backend (auto-migrate + hot-reload) |
task dev:down |
Stop backend |
task test |
Run tests |
task format |
Format code |
task lint |
Run linters |
task db:clear |
Reset database (⚠️ deletes data) |
task migrate:up |
Manual migration |
🔍 Troubleshooting
Backend won't start - "connection refused"
Error: dial tcp 127.0.0.1:9042: connect: connection refused
Cause: .env file has localhost instead of container names.
Fix:
cd cloud/maplepress-backend
rm .env
cp .env.sample .env
task dev
Infrastructure not running
Error: Cassandra or Redis not available
Fix:
cd cloud/infrastructure/development
task dev:start
task dev:status # Wait until all show (healthy)
Port 8000 already in use
Fix:
lsof -i :8000 # Find what's using the port
# Stop the other service, or change SERVER_PORT in .env
Token expired (401 errors)
JWT tokens expire after 60 minutes. Re-run the registration step to get a new token.
WordPress can't connect
Problem: WordPress using localhost:8000 instead of container name
Fix: In WordPress settings, use http://maplepress-backend-dev:8000
Verify:
docker exec maple-wordpress-dev curl http://maplepress-backend-dev:8000/health
🛠️ Technology Stack
- Go 1.23+ - Programming language
- Clean Architecture - Code organization
- Wire - Dependency injection
- Cassandra - Multi-tenant database (3-node cluster)
- Redis - Caching layer
- Meilisearch - Full-text search
- JWT - User authentication
- API Keys - Plugin authentication
🌐 Services
When you run MaplePress, these services are available:
| Service | Port | Purpose | Access |
|---|---|---|---|
| MaplePress Backend | 8000 | HTTP API | http://localhost:8000 |
| Cassandra | 9042 | Database | task cql (from infrastructure dir) |
| Redis | 6379 | Cache | task redis (from infrastructure dir) |
| Meilisearch | 7700 | Search | http://localhost:7700 |
| WordPress | 8081 | Plugin testing | http://localhost:8081 |
🧪 Test Mode vs Live Mode
MaplePress automatically generates the correct API key type based on your environment:
Automatic Behavior
| Environment | API Key Type | When to Use |
|---|---|---|
development |
test_sk_* |
Local development, testing |
production |
live_sk_* |
Production sites |
Configuration (.env):
# Development - automatically generates test_sk_ keys
APP_ENVIRONMENT=development
# Production - automatically generates live_sk_ keys
APP_ENVIRONMENT=production
No manual parameter needed! The backend determines the key type from APP_ENVIRONMENT.
See docs/API.md#test-mode-vs-live-mode for details.
🔗 Links
- API Documentation:
docs/API.md - Developer Guide:
docs/DEVELOPER_GUIDE.md - Getting Started Guide:
docs/GETTING-STARTED.md - WordPress Plugin:
../../native/wordpress/README.md - Architecture Details:
../../CLAUDE.md - Repository: Codeberg - mapleopentech/monorepo
🤝 Contributing
Found a bug? Want a feature to improve MaplePress? Please create an issue.
📝 License
This application is licensed under the GNU Affero General Public License v3.0. See LICENSE for more information.