{"id":20236215,"url":"https://github.com/bakaphp/kanvas-ecosystem-api","last_synced_at":"2026-06-08T00:02:28.091Z","repository":{"id":45462753,"uuid":"513624614","full_name":"bakaphp/kanvas-ecosystem-api","owner":"bakaphp","description":"Kanvas, graph Api's (crm, inventory, social, workflows) to develop your headless app's","archived":false,"fork":false,"pushed_at":"2025-04-09T16:44:21.000Z","size":18701,"stargazers_count":17,"open_issues_count":23,"forks_count":4,"subscribers_count":3,"default_branch":"development","last_synced_at":"2025-04-09T16:50:13.955Z","etag":null,"topics":["crm","graphql","headless","inventory","laravel","php","social"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bakaphp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-07-13T18:09:13.000Z","updated_at":"2025-04-09T15:50:56.000Z","dependencies_parsed_at":"2022-07-15T05:00:37.144Z","dependency_job_id":"60eadf4c-749d-42f8-997d-f75317f76ee1","html_url":"https://github.com/bakaphp/kanvas-ecosystem-api","commit_stats":null,"previous_names":[],"tags_count":123,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bakaphp%2Fkanvas-ecosystem-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bakaphp%2Fkanvas-ecosystem-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bakaphp%2Fkanvas-ecosystem-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bakaphp%2Fkanvas-ecosystem-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bakaphp","download_url":"https://codeload.github.com/bakaphp/kanvas-ecosystem-api/tar.gz/refs/heads/development","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248278783,"owners_count":21077314,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["crm","graphql","headless","inventory","laravel","php","social"],"created_at":"2024-11-14T08:19:34.314Z","updated_at":"2026-06-08T00:02:28.084Z","avatar_url":"https://github.com/bakaphp.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cbr /\u003e\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"https://cdn.prod.website-files.com/66c9f056ff6b7f7ba51cdf21/66ccb2a881e7036ab59136f2_Logo_Kanvas_3.png\" alt=\"Kanvas Logo\" style=\"width: 20%; height: auto;\"\u003e\n    \u003cbr /\u003e\n    \u003cbr /\u003e\n\u003c/p\u003e\n\n[![static analysis](https://github.com/bakaphp/kanvas-ecosystem-api/actions/workflows/static-analysis.yml/badge.svg)](https://github.com/bakaphp/kanvas-ecosystem-api/actions/workflows/static-analysis.yml)\n[![CI](https://github.com/bakaphp/kanvas-ecosystem-api/actions/workflows/tests.yml/badge.svg)](https://github.com/bakaphp/kanvas-ecosystem-api/actions/workflows/tests.yml)\n\n**Kanvas is the nervous system for modern operations.**  \nIt connects your systems, orchestrates workflows, and enables AI agents and humans to execute real operational work across your business.\n\nThink of Kanvas as the layer where operations become executable.\n\nNot a storefront.  \nNot just a CRM.  \nNot another automation tool.\n\nKanvas is the **operational execution layer** that unifies your stack and allows intelligence to act on it.\n\n## Why Kanvas Exists\n\nModern companies operate across fragmented systems:\n\n- Shopify for commerce  \n- NetSuite for operations  \n- HubSpot for CRM  \n- Slack for communication  \n- Internal tools and spreadsheets everywhere  \n- AI tools disconnected from execution  \n\nEvery company ends up rebuilding the same operational infrastructure: authentication, permissions, product synchronization, lead routing, workflow orchestration, integrations, event pipelines, operational APIs.\n\nAnd even with AI, most systems still stop at conversation instead of execution.\n\nKanvas was built to solve that.\n\nIt provides a **modular operational nervous system** where APIs, workflows, events, and AI agents work together to run real operations.\n\n## What Kanvas Is\n\nKanvas is a **Laravel + GraphQL operational backend** designed to unify operational logic across systems.\n\nIt provides:\n\n- Unified operational APIs  \n- Cross-system workflows  \n- Event-driven infrastructure  \n- Multi-tenant architecture  \n- Agent-ready execution primitives  \n- Operational memory and orchestration layers  \n\nSo you can build systems where:\n\n- Products sync automatically  \n- Inventory propagates across channels  \n- Leads route themselves  \n- Teams operate from unified data  \n- AI agents execute operational tasks  \n- Business logic lives in one place  \n\n## The Nervous System Model\n\nWithout a nervous system, AI is just a chatbot.\n\nKanvas gives AI agents operational awareness and execution capabilities by connecting products, customers, inventory, CRMs, internal APIs, workflows, and operational events.\n\nThis allows agents to move from:\n\n```text\n\"Here's what you should do\"\n```\n\nto:\n\n```text\n\"I've already done it.\"\n```\n\n## Core Domains\n\nKanvas is composed of operational building blocks:\n\n- **Ecosystem** – authentication, apps, teams, multi-tenancy  \n- **Inventory** – products, variants, channels, catalogs  \n- **CRM** – people, leads, pipelines, organizations  \n- **Workflow** – actions, automations, orchestration  \n- **Commerce** – orders, fulfillment, operational logic  \n- **Social** – messaging, feeds, interactions  \n- **Agents** – execution, orchestration, operational memory  \n\nYou don’t install disconnected features.  \nYou assemble an **operational nervous system** for your business.\n\n## What People Use Kanvas For\n\n- 🚘 Dealer platforms (inventory + CRM + lead routing)  \n- 🛍 Marketplaces (products, vendors, fulfillment workflows)  \n- 🏪 B2B commerce systems (pricing, approvals, operations)  \n- 🧩 Product configurators and bundlers  \n- 📱 Headless commerce applications  \n- 🤖 AI agent infrastructure and execution systems  \n- 🧠 Internal operational platforms and AI desks  \n\n## The Mental Model\n\nKanvas is not your app.\n\nKanvas is the **operational layer your apps, agents, and teams run on.**\n\nYour frontends, dashboards, workflows, and AI agents connect to Kanvas — and Kanvas connects to the rest of your infrastructure.\n\n```text\nUI / Mobile / Dashboards / AI Agents\n                 ↓\n             Kanvas\n                 ↓\nShopify • NetSuite • CRMs • Internal APIs • Workflows\n```\n\n## Prerequisites\n\n- PHP ^8.5\n- Laravel ^13.0\n\n## Initial Setup\n\n1. Use the ``docker compose up --build -d`` to bring up the containers. Make sure to have Docker Desktop active and have no other containers running that may cause conflict with this project's containers(There may be conflicts port wise if more than one container uses the same ports).\n\n2. Check the status of containers using the command ```docker-compose ps```. Make sure they are running and services are healthy.\n\n3. Get inside the database container using ```docker exec -it mysqlLaravel /bin/bash```. Then, create 7 databases: `inventory`, `social`, `crm`, `workflow`, `commerce`, `action_engine`, `event`.\n\n4. Set up your .env: You can start by copying the `.env.example setup`. Next, update it with the database and Redis connection info, making sure that the host values match your container's name.\n\n5. Get inside the php container using ```docker exec -it phpLaravel bash```.\n\n6. Generate app keys with `php artisan key:generate`.\n**Note:** Confirm that your app key is correctly registered in the `apps` table within the `kanvas_laravel` database.\n\n7. Update the app variables in your .env `APP_JWT_TOKEN`, `APP_KEY`, `KANVAS_APP_ID` before running the setup-ecosystem.\n**Note:** You can use the default values provided in `tests.yml`.\n\n8. Use the command ```php artisan kanvas:setup-ecosystem``` to run the kanvas setup.\n\n9. If you're presenting some errors after running the command from before, drop all the tables from the schema `kanvas_laravel` and run it again.\n\n10. To check if the API is working just make a GET request to  ```http://localhost:80/v1/``` and see if the response returns ```\"Woot Kanvas\"```.\n\n### Setup Inventory\n1. composer migrate-inventory\n2. Set env var in .env\n```\nDB_INVENTORY_HOST=mysqlLaravel\nDB_INVENTORY_PORT=3306\nDB_INVENTORY_DATABASE=inventory\nDB_INVENTORY_USERNAME=root\nDB_INVENTORY_PASSWORD=password\n```\n\n`php artisan inventory:setup` to create and initialize the inventory module for a current company\n\n### Setup Social\n1. composer migrate-social\n2. Set env var in .env\n```\nDB_SOCIAL_HOST=mysqlLaravel\nDB_SOCIAL_PORT=3306\nDB_SOCIAL_DATABASE=social\nDB_SOCIAL_USERNAME=root\nDB_SOCIAL_PASSWORD=password\n```\n\n`php artisan social:setup` to create and initialize the social module for a current company\n\n### Setup Guild\n1. composer migrate-crm\n2. Set env var in .env\n```\nDB_CRM_HOST=mysqlLaravel\nDB_CRM_PORT=3306\nDB_CRM_DATABASE=cr\nDB_CRM_USERNAME=root\nDB_CRM_PASSWORD=password\n```\n\n\n`php artisan guild:setup` to create and initialize the crm module for a current company\n\n## Running the project with Laravel Octane\n\nAfter doing all the steps above, you could run the project with Laravel Octane by using the command ```php artisan octane:start --server=swoole --host=0.0.0.0 --port=8000```. \n\nUse `--watch` in development allowing you to refresh modified files, this works assuming to have `npm install chokidar` installed in the project.\n****\n\n## Deployment to GCP with Ansible\n\nThis project uses GitHub Actions with Ansible to deploy to Google Cloud Platform (GCP) compute instances using Workload Identity Federation for secure authentication.\n\n### Architecture Overview\n\n- **GitHub Actions**: Orchestrates the deployment workflow\n- **Workload Identity Federation**: Secure authentication to GCP without storing service account keys\n- **Ansible**: Automates deployment tasks across GCP compute instances\n- **Dynamic Inventory**: Automatically discovers GCP instances based on naming patterns\n\n### GCP Setup\n\n#### 1. Create Workload Identity Pool\n\n```bash\nexport PROJECT_ID=\"your-project-id\"\nexport PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format=\"value(projectNumber)\")\nexport REPO=\"bakaphp/kanvas-ecosystem-api\"\n\n# Create Workload Identity Pool\ngcloud iam workload-identity-pools create \"github-pool\" \\\n  --project=\"${PROJECT_ID}\" \\\n  --location=\"global\" \\\n  --display-name=\"GitHub Actions Pool\"\n```\n\n#### 2. Create OIDC Provider\n\n```bash\ngcloud iam workload-identity-pools providers create-oidc \"github-provider\" \\\n  --project=\"${PROJECT_ID}\" \\\n  --location=\"global\" \\\n  --workload-identity-pool=\"github-pool\" \\\n  --display-name=\"GitHub Actions Provider\" \\\n  --issuer-uri=\"https://token.actions.githubusercontent.com\" \\\n  --attribute-mapping=\"google.subject=assertion.sub,attribute.actor=assertion.actor,attribute.repository=assertion.repository,attribute.repository_owner=assertion.repository_owner\" \\\n  --attribute-condition=\"assertion.repository_owner=='bakaphp'\"\n```\n\n#### 3. Create Service Account\n\n```bash\n# Create service account\ngcloud iam service-accounts create github-actions-sa \\\n  --project=\"${PROJECT_ID}\" \\\n  --display-name=\"GitHub Actions Service Account\"\n\nexport SA_EMAIL=\"github-actions-sa@${PROJECT_ID}.iam.gserviceaccount.com\"\n\n# Grant necessary permissions\ngcloud projects add-iam-policy-binding $PROJECT_ID \\\n  --member=\"serviceAccount:${SA_EMAIL}\" \\\n  --role=\"roles/compute.viewer\"\n\n# Grant OS Login permissions for SSH access (replaces SSH keys)\ngcloud projects add-iam-policy-binding $PROJECT_ID \\\n  --member=\"serviceAccount:${SA_EMAIL}\" \\\n  --role=\"roles/compute.osAdminLogin\"\n\n# Allow Workload Identity to impersonate the service account\ngcloud iam service-accounts add-iam-policy-binding \"${SA_EMAIL}\" \\\n  --project=\"${PROJECT_ID}\" \\\n  --role=\"roles/iam.workloadIdentityUser\" \\\n  --member=\"principalSet://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/github-pool/attribute.repository/${REPO}\"\n```\n\n#### 4. Get Provider Path\n\n```bash\n# Get the full provider path for GitHub secrets\ngcloud iam workload-identity-pools providers describe github-provider \\\n  --workload-identity-pool=github-pool \\\n  --location=global \\\n  --project=$PROJECT_ID \\\n  --format=\"value(name)\"\n```\n\n#### 5. Enable OS Login (Replaces SSH Key Management)\n\nOS Login uses IAM for SSH authentication, eliminating the need to manage SSH keys. This is more secure and provides automatic key rotation.\n\n```bash\n# Enable OS Login at project level (applies to all instances)\ngcloud compute project-info add-metadata \\\n  --metadata enable-oslogin=TRUE \\\n  --project=$PROJECT_ID\n\n# Verify OS Login is enabled\ngcloud compute project-info describe \\\n  --project=$PROJECT_ID \\\n  --format=\"value(commonInstanceMetadata.items.filter(key:enable-oslogin))\"\n```\n\n**Benefits of OS Login:**\n- No SSH keys to store in GitHub Secrets\n- Automatic credential rotation via IAM\n- Centralized access control\n- Full audit logging via Cloud Audit Logs\n- Works seamlessly with Workload Identity Federation\n\n**For Managed Instance Groups:**\nOS Login is automatically applied to all current and future instances when enabled at the project level. No changes to instance templates required.\n\n### GitHub Configuration\n\n#### Required Secrets\n\nGo to: **Repository Settings → Secrets and variables → Actions → New repository secret**\n\n| Secret Name | Value | Example |\n|------------|-------|---------|\n| `GCP_WORKLOAD_IDENTITY_PROVIDER` | Full provider path from step 4 | `projects/123456789/locations/global/workloadIdentityPools/github-pool/providers/github-provider` |\n| `GCP_SERVICE_ACCOUNT` | Service account email | `github-actions-sa@your-project.iam.gserviceaccount.com` |\n| `GCP_PROJECT_ID` | Your GCP project ID | `your-project-id` |\n| `GCP_REGION` | Your GCP region | `us-central1` |\n| `INSTANCE_GROUP_NAME` | Name pattern for instances | `development` |\n| `GCP_COMPUTE_SSH_PRIVATE_KEY` | SSH private key for compute instances | (your SSH private key) |\n\n#### Required Variables\n\nGo to: **Repository Settings → Secrets and variables → Actions → Variables**\n\n| Variable Name | Value | Example |\n|------------|-------|---------|\n| `SSH_USER` | SSH username | `ubuntu` or `your-username` |\n\n#### GitHub Environments\n\nCreate environments matching your branch names (e.g., `development`, `staging`, `main`) in:\n**Repository Settings → Environments**\n\nThis allows branch-specific configurations and deployment protection rules.\n\n### Deployment Workflow\n\nThe deployment is triggered manually via `workflow_dispatch`. To deploy:\n\n1. Go to **Actions** tab in GitHub\n2. Select **\"Ansible GCP Compute Deploy\"** workflow\n3. Click **\"Run workflow\"**\n4. Select the branch to deploy\n5. Click **\"Run workflow\"**\n\n#### What Happens During Deployment\n\n1. **Authentication**: Authenticates to GCP using Workload Identity Federation\n2. **Dynamic Inventory**: Discovers running GCP instances in the specified region matching the instance group name\n3. **File Sync**: Syncs application files to remote servers (excluding git, node_modules, vendor, etc.)\n4. **Dependencies**: Installs Composer dependencies\n5. **Migrations** (optional): Runs database migrations\n6. **Cache**: Clears and rebuilds Laravel config/route/view cache\n7. **Docker**: Restarts Docker containers with updated code\n\n### Ansible Playbooks\n\nPlaybooks are organized by environment in `ansible/playbooks/`:\n- `development-deploy.yaml`\n- `staging-deploy.yaml` (if applicable)\n- `production-deploy.yaml` (if applicable)\n\n#### Playbook Structure\n\n```yaml\n---\n- name: Deploy app to all instances\n  hosts: development  # Matches the group created by dynamic inventory\n  become: true\n  strategy: free  # Run on all hosts in parallel\n\n  tasks:\n    - name: Sync app files\n      ansible.posix.synchronize: ...\n\n    - name: Install dependencies\n      command: composer install ...\n\n    - name: Redeploy docker containers\n      docker_compose: ...\n```\n\n### GCP Instance Requirements\n\nInstances must:\n- Be named with the pattern matching `INSTANCE_GROUP_NAME` (e.g., `development-api-01`)\n- Be in `RUNNING` state\n- Have SSH access configured with the provided private key\n- Have Docker and Docker Compose installed\n- Have the application directory structure in place\n\n### Troubleshooting\n\n#### Authentication Errors\n\n```\nError: invalid_target\n```\n\n**Solution**: Verify the Workload Identity Provider path and ensure pool/provider are ACTIVE:\n\n```bash\ngcloud iam workload-identity-pools describe github-pool \\\n  --location=global \\\n  --project=YOUR_PROJECT_ID \\\n  --format=\"value(state)\"\n\ngcloud iam workload-identity-pools providers describe github-provider \\\n  --workload-identity-pool=github-pool \\\n  --location=global \\\n  --project=YOUR_PROJECT_ID \\\n  --format=\"value(state)\"\n```\n\nBoth should return `ACTIVE`.\n\n#### No Hosts Found\n\n**Solution**: Check that:\n- Instances are running\n- Instance names contain the `INSTANCE_GROUP_NAME` value\n- Instances are in the specified `GCP_REGION`\n\n```bash\ngcloud compute instances list \\\n  --project=YOUR_PROJECT_ID \\\n  --filter=\"name~INSTANCE_GROUP_NAME AND status=RUNNING\"\n```\n\n#### SSH Connection Issues\n\n**Solution**: Verify SSH key is correct and user has access:\n\n```bash\n# Test SSH connection manually\nssh -i path/to/private-key username@instance-ip\n```\n\n### Local Testing\n\nTest the Ansible playbook locally:\n\n```bash\ncd ansible\n\n# Test inventory discovery\nansible-inventory -i inventory.gcp.yml --list\n\n# Run playbook with dry-run\nansible-playbook playbooks/development-deploy.yaml \\\n  -i inventory.gcp.yml \\\n  --check \\\n  --diff\n```\n\n## Working with kanvas\n- [Coding guideline](https://github.com/bakaphp/kanvas-ecosystem-api/wiki/Coding-Guidelines)\n- [Wiki](https://github.com/alexeymezenin/laravel-best-practices#follow-laravel-naming-conventions)\n- [TypeScript SDK](https://github.com/bakaphp/kanvas-core-js)\n- [Documentation](https://github.com/bakaphp/kanvas-doc)\n\nNote: \n- To install Swoole you can use the command ```pecl install swoole``` \n- For production remove `--watch` from the command.\n- roles_kanvas_legacy will be deleted in the future\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbakaphp%2Fkanvas-ecosystem-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbakaphp%2Fkanvas-ecosystem-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbakaphp%2Fkanvas-ecosystem-api/lists"}