Local Development Stack
Complete guide to setting up and running the Easy AppServer development environment with all dependencies.
Overview
The local development stack includes:
Core Services:
- PostgreSQL - Shared database
- Redis - Cache & session store
- RabbitMQ - Message broker & event bus
- Kratos - Identity and user management
- Hydra - OAuth2/OIDC provider
- OpenFGA - Fine-grained authorization
- Oathkeeper - Identity & access proxy
- AppServer - Central orchestration platform
Observability Stack:
- OpenTelemetry Collector - Telemetry aggregation
- Prometheus - Metrics storage
- Loki - Log aggregation
- Tempo - Distributed tracing
- Grafana - Unified visualization
Prerequisites
- Docker & Docker Compose: For running infrastructure
- Go 1.21+: For running AppServer
- Node.js 18+: For running Shell and documentation
- Make: For using makefiles (optional)
Quick Start
1. Clone and Navigate
git clone <repository-url>
cd easy.appserver
2. Run Setup Script
./docker/scripts/setup.sh
This automated script will:
- Create
.envfile from.env.example - Start PostgreSQL
- Run database migrations
- Start all core services (Kratos, Hydra, OpenFGA, Oathkeeper, etc.)
- Initialize OpenFGA with base roles: easy, admin, advertiser, publisher
3. Update Secrets
IMPORTANT: Before running in production or sharing environments, update these values in docker/.env:
# Must be exactly 32 characters
KRATOS_SECRETS_COOKIE=changeme-32-char-secret-cookie-key
KRATOS_SECRETS_CIPHER=changeme-32-char-secret-cipher-k
# Strong secrets
HYDRA_SYSTEM_SECRET=changeme-change-this-system-secret-key
HYDRA_PAIRWISE_SALT=changeme-pairwise-salt-key
POSTGRES_PASSWORD=changeme-in-production
4. Start AppServer
# Set environment variables
export APPSERVER_DB_HOST=localhost
export APPSERVER_DB_PORT=5432
export APPSERVER_DB_USER=partner
export APPSERVER_DB_PASSWORD=changeme-in-production
export APPSERVER_DB_NAME=appserver
export APPSERVER_KRATOS_PUBLIC_URL=http://localhost:4433
export APPSERVER_OPENFGA_API_URL=http://localhost:8090
# Run appserver
go run cmd/appserver-v2/main.go serve
Or using Makefile:
make docker-up # Start all infrastructure
make run # Run appserver
Service URLs
Core Services
| Service | URL | Purpose |
|---|---|---|
| Kratos Public | http://localhost:4433 | User-facing identity APIs |
| Kratos Admin | http://localhost:4434 | Admin identity management |
| Hydra Public | http://localhost:4444 | OAuth2 authorization server |
| Hydra Admin | http://localhost:4445 | OAuth2 admin APIs |
| OpenFGA API | http://localhost:8090 | Authorization API |
| OpenFGA gRPC | http://localhost:8091 | Authorization gRPC |
| OpenFGA Playground | http://localhost:8090/playground | Authorization testing UI |
| Oathkeeper Proxy | http://localhost:4455 | Access control proxy |
| Oathkeeper API | http://localhost:4456 | Proxy configuration |
| PostgreSQL | localhost:5432 | Database |
| Redis | localhost:6379 | Cache |
| RabbitMQ | localhost:5672 | Message broker |
| RabbitMQ Management | http://localhost:15672 | Queue management UI |
| AppServer HTTP | http://localhost:8080 | Main HTTP API |
| AppServer GraphQL | http://localhost:8080/graphql | GraphQL API |
| AppServer gRPC | localhost:9090 | gRPC API |
| Documentation | http://localhost:3030 | Docusaurus docs |
Observability Services
| Service | URL | Credentials |
|---|---|---|
| Grafana | http://localhost:3000 | admin/admin |
| Prometheus | http://localhost:9090 | - |
| Loki | http://localhost:3100 | - |
| Tempo | http://localhost:3200 | - |
| OTel Collector (gRPC) | localhost:4317 | - |
| OTel Collector (HTTP) | http://localhost:4318 | - |
| OTel Collector Metrics | http://localhost:8888 | - |
Architecture
┌─────────────────────────────────────────────────────────────┐
│ Docker Network │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ AppServer │───▶│ Oathkeeper │───▶│ Kratos │ │
│ │ (Go/gRPC) │ │ (Proxy) │ │ (Identity) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │ │ │ │
│ │ │ │ │
│ │ ▼ ▼ │
│ │ ┌──────────────┐ ┌──────────────┐ │
│ └───────────▶│ Hydra │ │ OpenFGA │ │
│ │ (OAuth2) │ │ (AuthZ) │ │
│ └──────────────┘ └──────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────────────────┐ │
│ │ PostgreSQL │ │
│ │ (kratos, hydra, openfga, │ │
│ │ appserver, shell, partner) │ │
│ └─────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Database Setup
The setup script creates the following schemas in PostgreSQL:
Databases:
partner- Main database
Schemas:
kratos- Ory Kratos identity datahydra- Ory Hydra OAuth2 dataopenfga- OpenFGA authorization dataappserver- AppServer application datashell- Shell frontend datapartner- Legacy partner data
Migrations:
- Automatically run during setup
- Located in relevant service directories
- Use Goose for AppServer migrations
OpenFGA Roles
The setup script creates 4 base roles:
Built-in Roles
easy - God mode (full platform access):
- Internal employees
- Full access to all resources
- Can perform any action
admin - Platform administrator:
- Manage applications
- Manage users
- Configure settings
advertiser - Advertiser role:
- Manage own campaigns
- View reports
- Limited platform access
publisher - Publisher role:
- Manage own properties
- View analytics
- Limited platform access
Assign User to Role
curl -X POST 'http://localhost:8090/stores/${STORE_ID}/write' \
-H 'Content-Type: application/json' \
-d '{
"writes": {
"tuple_keys": [
{
"user": "user:<USER_ID>",
"relation": "assignee",
"object": "role:easy"
}
]
}
}'
Replace <USER_ID> with the actual Kratos identity ID.
Grant Role Permission
# Grant 'advertiser' role viewer access to an app
curl -X POST 'http://localhost:8090/stores/${STORE_ID}/write' \
-H 'Content-Type: application/json' \
-d '{
"writes": {
"tuple_keys": [
{
"user": "role:advertiser#assignee",
"relation": "viewer",
"object": "app:<APP_ID>"
}
]
}
}'
Management Commands
View Logs
# All services
docker-compose -f docker/docker-compose.yml logs -f
# Specific service
docker-compose -f docker/docker-compose.yml logs -f kratos
# Or use makefile
make docker-logs
Stop Services
# Stop all services
docker-compose -f docker/docker-compose.yml down
# Stop and remove volumes (clean slate)
docker-compose -f docker/docker-compose.yml down -v
# Or use makefile
make docker-down
Restart Service
# Restart specific service
docker-compose -f docker/docker-compose.yml restart kratos
# Rebuild and restart
docker-compose -f docker/docker-compose.yml up -d --build kratos
Database Access
# Connect to PostgreSQL
docker exec -it easy-appserver-postgres psql -U partner -d partner
# Run query
docker exec -it easy-appserver-postgres psql -U partner -d partner -c "SELECT * FROM appserver.apps"
# Run migrations
make migrate-up
make migrate-down
RabbitMQ Management
# Access management UI
open http://localhost:15672
# Default credentials: guest/guest
# List queues via CLI
docker exec -it easy-appserver-rabbitmq rabbitmqctl list_queues
# List exchanges
docker exec -it easy-appserver-rabbitmq rabbitmqctl list_exchanges
Environment Variables
AppServer Configuration
Key environment variables (see docker/.env.example for full list):
Server:
APPSERVER_HTTP_PORT=8080
APPSERVER_GRPC_PORT=9090
APPSERVER_ENV=development
Database:
APPSERVER_DB_HOST=postgres
APPSERVER_DB_PORT=5432
APPSERVER_DB_NAME=appserver
APPSERVER_DB_USER=partner
APPSERVER_DB_PASSWORD=changeme-in-production
APPSERVER_DB_SSLMODE=disable
Cache:
APPSERVER_REDIS_URL=redis://redis:6379
APPSERVER_CACHE_TTL=300 # 5 minutes
Event Bus:
APPSERVER_EVENTBUS_ENABLED=true
APPSERVER_RABBITMQ_URL=amqp://guest:guest@rabbitmq:5672/
APPSERVER_RABBITMQ_MAX_RETRIES=5
APPSERVER_RABBITMQ_PREFETCH_COUNT=10
Security:
APPSERVER_GRPC_TLS_ENABLED=false # Enable in production
APPSERVER_GRPC_REFLECTION_ENABLED=true # Disable in production
APPSERVER_GRAPHQL_PLAYGROUND_ENABLED=true # Disable in production
APPSERVER_SESSION_COOKIE_NAME=ory_kratos_session
APPSERVER_KRATOS_TIMEOUT=5s
APPSERVER_OPENFGA_TIMEOUT=5s
APPSERVER_SIGNATURE_REPLAY_WINDOW=5m
APPSERVER_CLOCK_SKEW_TOLERANCE=30s
Telemetry:
APPSERVER_LOG_LEVEL=debug
APPSERVER_METRICS_ENABLED=true
APPSERVER_TRACING_ENABLED=false
Troubleshooting
Port Conflicts
OpenFGA ports changed:
- API: 8090 (was 8080, conflicted with AppServer)
- gRPC: 8091 (was 8081, conflicted with AppServer)
Documentation port changed:
- Docs: 3030 (was 8888, conflicted with OTel Collector)
Check for conflicts:
# Check if port is in use
lsof -i :8080
netstat -an | grep 8080
# Kill process using port
kill -9 <PID>
Database Connection Issues
# Check PostgreSQL is running
docker ps | grep postgres
# Check logs
docker logs easy-appserver-postgres
# Test connection
docker exec -it easy-appserver-postgres psql -U partner -d partner -c "SELECT 1"
# Restart PostgreSQL
docker-compose -f docker/docker-compose.yml restart postgres
RabbitMQ Connection Issues
# Check RabbitMQ is running
docker ps | grep rabbitmq
# Check logs
docker logs easy-appserver-rabbitmq
# Check node status
docker exec -it easy-appserver-rabbitmq rabbitmqctl status
# Reset RabbitMQ
docker-compose -f docker/docker-compose.yml restart rabbitmq
Kratos/Hydra Issues
# Run migrations manually
docker exec -it easy-appserver-kratos kratos migrate sql -e --yes
docker exec -it easy-appserver-hydra hydra migrate sql -e --yes
# Check Kratos health
curl http://localhost:4434/health/ready
# Check Hydra health
curl http://localhost:4445/health/ready
OpenFGA Issues
# Check OpenFGA logs
docker logs easy-appserver-openfga
# Test API
curl http://localhost:8090/healthz
# Access playground
open http://localhost:8090/playground
Clean Slate
# Stop all services and remove volumes
docker-compose -f docker/docker-compose.yml down -v
# Remove all AppServer data
docker volume ls | grep easy-appserver | awk '{print $2}' | xargs docker volume rm
# Re-run setup
./docker/scripts/setup.sh
Development Workflow
1. Start Infrastructure
make docker-up
2. Run AppServer
# Terminal 1: AppServer
make run
# Or with custom config
go run cmd/appserver-v2/main.go serve --config custom-config.yaml
3. Run Shell (Optional)
# Terminal 2: Shell
cd web/v2/packages/shell
pnpm install
pnpm dev
4. Run Documentation (Optional)
# Terminal 3: Documentation
cd docs
pnpm install
pnpm start
5. Make Changes
- Edit code
- AppServer auto-recompiles (with air or manual restart)
- Shell hot-reloads automatically
- Documentation hot-reloads automatically
6. Test Changes
# Run tests
make test
# Run integration tests
make test-integration
# Test specific package
go test ./pkg/v2/application/marketplace/...
Useful Commands
Docker
# View running services
docker ps
# View all logs
make docker-logs
# Stop all services
make docker-down
# Restart specific service
docker-compose -f docker/docker-compose.yml restart <service>
Database
# Create migration
make migrate-create NAME=add_new_table
# Run migrations
make migrate-up
# Rollback migration
make migrate-down
# Migration status
make migrate-status
Testing
# Unit tests
make test
# Integration tests
make test-integration
# E2E tests
make test-e2e
# Coverage
make test-coverage
Code Quality
# Lint
make lint
# Format
make fmt
# Type check (for Shell)
cd web/v2/packages/shell && pnpm typecheck
Next Steps
- Building Your First App - Create your first application
- Debugging Guide - Debug applications and services
- Deployment Guide - Deploy to production
Related Topics
- Platform Architecture - Understand the architecture
- Infrastructure Overview - Deep dive into services
- Docker Infrastructure - Production deployment