* feat(api): add webhook delivery utility and card event integration Add the core webhook delivery logic and wire it into card mutations: - Add sendWebhookToUrl() with HMAC-SHA256 signing, 10s timeout - Add sendWebhooksForWorkspace() for fan-out delivery (fire-and-forget) - Add createCardWebhookPayload() for building webhook payloads - Fire webhooks on card create, update, move, and delete events - Add unit tests for webhook utility functions Depends on #391 (DB schema & repository). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(api): use correct boardId in webhook payloads and add rejection safety - Fix bug where workspaceId was incorrectly passed as boardId in all webhook payloads — now uses board's publicId via boardPublicId - Replace void sendWebhooksForWorkspace() with .catch() to prevent unhandled promise rejections if the DB query inside fails Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(api): add SSRF protection to webhook delivery Block webhook URLs targeting internal networks: - Require HTTPS (reject HTTP) - Block localhost, 127.0.0.1, ::1, 0.0.0.0 - Block cloud metadata endpoints (169.254.169.254, metadata.google.internal) - Block private IP ranges (10.x, 172.16-31.x, 192.168.x) - Add tests for all blocked URL patterns Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(api): use WebhookEvent type from schema instead of duplicating Replace the hardcoded WebhookEventType union with the canonical WebhookEvent type from @kan/db/schema, addressing reviewer feedback on PR #392. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(api): improve webhook delivery safety and validation Cherry-pick delivery-related changes from b2cc9ac: - Extract URL validation into reusable webhookUrlSchema zod validator for SSRF checks - Wrap sendWebhooksForWorkspace in try/catch to prevent unhandled promise rejections - Document SSRF risk mitigation on sendWebhookToUrl - Add corresponding tests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Kan
The open-source project management alternative to Trello.
Roadmap · Website · Docs · Discord
Features 💫
- 👁️ Board Visibility: Control who can view and edit your boards
- 🤝 Workspace Members: Invite members and collaborate with your team
- 🚀 Trello Imports: Easily import your Trello boards
- 🔍 Labels & Filters: Organise and find cards quickly
- 💬 Comments: Discuss and collaborate with your team
- 📝 Activity Log: Track all card changes with detailed activity history
- 🎨 Templates : Save time with reusable custom board templates
- ⚡️ Integrations (coming soon) : Connect your favourite tools
See our roadmap for upcoming features.
Screenshot 👁️
Made With 🛠️
Self Hosting 🐳
One-click Deployments
The easiest way to deploy Kan is through Railway. We've partnered with Railway to maintain an official template that supports the development of the project.
Docker Compose
Alternatively, you can self-host Kan with Docker Compose. This will set up everything for you including your postgres database.
- Create a new file called
docker-compose.ymland paste the following configuration:
services:
web:
image: ghcr.io/kanbn/kan:latest
container_name: kan-web
ports:
- "3000:3000"
networks:
- kan-network
environment:
NEXT_PUBLIC_BASE_URL: http://localhost:3000
BETTER_AUTH_SECRET: your_auth_secret
POSTGRES_URL: postgresql://kan:your_postgres_password@postgres:5432/kan_db
NEXT_PUBLIC_ALLOW_CREDENTIALS: true
depends_on:
- postgres
restart: unless-stopped
postgres:
image: postgres:15
container_name: kan-db
environment:
POSTGRES_DB: kan_db
POSTGRES_USER: kan
POSTGRES_PASSWORD: your_postgres_password
ports:
- 5432:5432
volumes:
- kan_postgres_data:/var/lib/postgresql/data
restart: unless-stopped
networks:
- kan-network
networks:
kan-network:
volumes:
kan_postgres_data:
- Start the containers in detached mode:
docker compose up -d
- Access Kan at http://localhost:3000
The application will be running in the background. You can manage the containers using these commands:
- To stop the containers:
docker compose down - To view logs:
docker compose logs -f - To restart the containers:
docker compose restart
For the complete Docker Compose configuration, see docker-compose.yml in the repository.
Note
: The Docker Compose configuration shown above is a minimal example. For a complete setup with all features (email, OAuth, file uploads, etc.), you'll need to create a
.envfile with the required environment variables. See the Environment Variables section below for the full list of available options.
Local Development 🧑💻
- Clone the repository (or fork)
git clone https://github.com/kanbn/kan.git
- Install dependencies
pnpm install
- Copy
.env.exampleto.envand configure your environment variables - Migrate database
pnpm db:migrate
- Start the development server
pnpm dev
Environment Variables 🔐
| Variable | Description | Required | Example |
|---|---|---|---|
POSTGRES_URL |
PostgreSQL connection URL | To use external database | postgres://user:pass@localhost:5432/db |
REDIS_URL |
Redis connection URL | For rate limiting (optional) | redis://localhost:6379 or redis://redis:6379 (Docker) |
EMAIL_FROM |
Sender email address | For Email | "Kan <hello@mail.kan.bn>" |
SMTP_HOST |
SMTP server hostname | For Email | smtp.resend.com |
SMTP_PORT |
SMTP server port | For Email | 465 |
SMTP_USER |
SMTP username/email | No | resend |
SMTP_PASSWORD |
SMTP password/token | No | re_xxxx |
SMTP_SECURE |
Use secure SMTP connection (defaults to true if not set) | For Email | true |
SMTP_REJECT_UNAUTHORIZED |
Reject invalid certificates (defaults to true if not set) | For Email | false |
NEXT_PUBLIC_DISABLE_EMAIL |
To disable all email features | For Email | true |
NEXT_PUBLIC_BASE_URL |
Base URL of your installation | Yes | http://localhost:3000 |
NEXT_API_BODY_SIZE_LIMIT |
Maximum API request body size (defaults to 1mb) | No | 50mb |
BETTER_AUTH_ALLOWED_DOMAINS |
Comma-separated list of allowed domains for OIDC logins | For OIDC/Social login | example.com,subsidiary.com |
BETTER_AUTH_SECRET |
Auth encryption secret | Yes | Random 32+ char string |
BETTER_AUTH_TRUSTED_ORIGINS |
Allowed callback origins | No | http://localhost:3000,http://localhost:3001 |
GOOGLE_CLIENT_ID |
Google OAuth client ID | For Google login | xxx.apps.googleusercontent.com |
GOOGLE_CLIENT_SECRET |
Google OAuth client secret | For Google login | xxx |
DISCORD_CLIENT_ID |
Discord OAuth client ID | For Discord login | xxx |
DISCORD_CLIENT_SECRET |
Discord OAuth client secret | For Discord login | xxx |
GITHUB_CLIENT_ID |
GitHub OAuth client ID | For GitHub login | xxx |
GITHUB_CLIENT_SECRET |
GitHub OAuth client secret | For GitHub login | xxx |
OIDC_CLIENT_ID |
Generic OIDC client ID | For OIDC login | xxx |
OIDC_CLIENT_SECRET |
Generic OIDC client secret | For OIDC login | xxx |
OIDC_DISCOVERY_URL |
OIDC discovery URL | For OIDC login | https://auth.example.com/.well-known/openid-configuration |
TRELLO_APP_API_KEY |
Trello app API key | For Trello import | xxx |
TRELLO_APP_API_SECRET |
Trello app API secret | For Trello import | xxx |
S3_REGION |
S3 storage region | For file uploads | WEUR |
S3_ENDPOINT |
S3 endpoint URL | For file uploads | https://xxx.r2.cloudflarestorage.com |
S3_ACCESS_KEY_ID |
S3 access key | For file uploads (optional with IRSA) | xxx |
S3_SECRET_ACCESS_KEY |
S3 secret key | For file uploads (optional with IRSA) | xxx |
S3_FORCE_PATH_STYLE |
Use path-style URLs for S3 | For file uploads | true |
NEXT_PUBLIC_STORAGE_URL |
Storage service URL | For file uploads | https://storage.kanbn.com |
NEXT_PUBLIC_STORAGE_DOMAIN |
Storage domain name | For file uploads | kanbn.com |
NEXT_PUBLIC_USE_VIRTUAL_HOSTED_URLS |
Use virtual-hosted style URLs (bucket.domain.com) | For file uploads (optional) | true |
NEXT_PUBLIC_AVATAR_BUCKET_NAME |
S3 bucket name for avatars | For file uploads | avatars |
NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME |
S3 bucket name for attachments | For file uploads | attachments |
NEXT_PUBLIC_ALLOW_CREDENTIALS |
Allow email & password login | For authentication | true |
NEXT_PUBLIC_DISABLE_SIGN_UP |
Disable sign up | For authentication | false |
NEXT_PUBLIC_WHITE_LABEL_HIDE_POWERED_BY |
Hide “Powered by kan.bn” on public boards (self-host) | For white labelling | true |
KAN_ADMIN_API_KEY |
Admin API key for stats and admin endpoints | For admin/monitoring | your-secret-admin-key |
See .env.example for a complete list of supported environment variables.
Contributing 🤝
We welcome contributions! Please read our contribution guidelines before submitting a pull request.
Contributors 👥
License 📝
Kan is licensed under the AGPLv3 license.
Contact 📧
For support or to get in touch, please email henry@kan.bn or join our Discord server.