mirror of
https://github.com/makeplane/plane.git
synced 2026-05-18 21:25:41 +02:00
* fix(flux): resolve workspace identifier mismatch between frontend, server, and consumer
The flux service had a fundamental identifier mismatch:
- Frontend connects to /events/{workspaceSlug} (slug)
- Consumer receives events with workspace_id (UUID from outbox)
- Auth middleware needs slug for Django API calls
Solution: Redis-backed WorkspaceRegistry for UUID↔slug mapping
Changes:
- Add WorkspaceRegistry service backed by Redis with bidirectional
UUID↔slug mapping (24h TTL per key)
- Add getWorkspace method to AuthService (calls GET /api/workspaces/{slug}/)
- Update auth middleware to fetch workspace UUID on connection and
register the mapping; store both workspaceSlug and workspaceId on socket
- Update consumer to resolve workspace_id→slug via registry before emitting
- Remove workspace_slug field from EventMessage schema (uses registry instead)
- Fix lint warnings: use Effect.async/Effect.promise idiomatically,
wrap async middleware to avoid no-misused-promises
- Frontend already updated to use workspaceSlug throughout (prior work)
* refactor(web): improve socket client with useSyncExternalStore
- Use useSyncExternalStore for tear-safe status reads from SocketClient
- Replace single statusChangeHandler with Set for multi-listener support
- Simplify work-item-detail revalidation with inverse logic instead of
fragile 15-item event type list
- Rename work-item.tsx → work-item.ts (pure type file, no JSX)
* fix(flux): update .env.example AMQP_URL with credentials and vhost
The consumer needs the RabbitMQ user, password, and vhost to connect
to the correct virtual host where plane.event_stream exchange exists.
* fix(flux): handle registry errors in consumer, remove redundant httpServer.close
- Wrap registry.getSlugById() with Effect.either in consumer to catch
Redis errors, log them, and ack the message instead of crashing the
stream and leaving messages stuck/unacked.
- Remove redundant httpServer.close() in server shutdown — io.close()
already closes the underlying httpServer when one was passed to the
constructor.
* fix: update lockfile after removing axios from flux
* fix(flux): sliding TTL on registry reads, isolate status listeners
- Add sliding TTL (expire refresh) on successful WorkspaceRegistry reads
to prevent mappings expiring while actively used by the consumer.
- Wrap status change listener calls in try/catch to prevent one failing
listener from blocking others.
- Remove void prefix on socket.join() calls (synchronous at runtime).
* Remove dead code from events handler and client types
- Remove unused workspace:/user: room joins (nothing emits to them)
- Remove unused connected event emit and client type
- Remove onAny logger (production noise)
- Add ALLOWED_ENTITY_TYPES validation on subscribe/unsubscribe
- Use namespace.sockets.size for connection stats
* fix(flux): refactor socket system to minimal signal architecture
Flux server:
- AMQP service with acquireRelease lifecycle and reconnect loop
- Consumer parses outbox events, builds minimal signals, emits via Redis
- SocketEmitter uses @socket.io/redis-emitter for cross-process delivery
- Room-based routing: only subscribed clients receive entity events
- WorkspaceRegistry with bidirectional slug/UUID mapping and sliding TTL
- RedisClient as shared Context.Tag singleton
Web client:
- Replace verbose type system with minimal TEntityEvent
- Replace useSocketEvent/useFilteredSocketEvent with useEntityEvent
- Room-based subscriptions via subscribe:entity/unsubscribe:entity
- Remove deleted work-item.ts types file
- Simplify provider context to status + subscribeEntity
* docs(flux): document TODO for excluding originating connection from broadcast
* fix(flux): update stale JSDoc and use register() for resilient registry refresh
- Fix JSDoc on setupEventsNamespace to reflect current room-based architecture
- Use register() instead of refreshTtl() for periodic refresh so mappings
survive Redis eviction/restart instead of silently no-oping on EXPIRE
46 lines
1.1 KiB
Plaintext
46 lines
1.1 KiB
Plaintext
# Database Settings
|
|
POSTGRES_USER="plane"
|
|
POSTGRES_PASSWORD="plane"
|
|
POSTGRES_DB="plane"
|
|
PGDATA="/var/lib/postgresql/data"
|
|
|
|
# Redis Settings
|
|
REDIS_HOST="plane-redis"
|
|
REDIS_PORT="6379"
|
|
|
|
# RabbitMQ Settings
|
|
RABBITMQ_HOST="plane-mq"
|
|
RABBITMQ_PORT="5672"
|
|
RABBITMQ_USER="plane"
|
|
RABBITMQ_PASSWORD="plane"
|
|
RABBITMQ_VHOST="plane"
|
|
|
|
LISTEN_HTTP_PORT=80
|
|
LISTEN_HTTPS_PORT=443
|
|
|
|
# AWS Settings
|
|
AWS_REGION=""
|
|
AWS_ACCESS_KEY_ID="access-key"
|
|
AWS_SECRET_ACCESS_KEY="secret-key"
|
|
AWS_S3_ENDPOINT_URL="http://plane-minio:9000"
|
|
# Changing this requires change in the proxy config for uploads if using minio setup
|
|
AWS_S3_BUCKET_NAME="uploads"
|
|
# Maximum file upload limit
|
|
FILE_SIZE_LIMIT=5242880
|
|
|
|
# Settings related to Docker
|
|
DOCKERIZED=1 # deprecated
|
|
|
|
# set to 1 If using the pre-configured minio setup
|
|
USE_MINIO=1
|
|
|
|
# If SSL Cert to be generated, set CERT_EMAIl="email <EMAIL_ADDRESS>"
|
|
CERT_ACME_CA=https://acme-v02.api.letsencrypt.org/directory
|
|
TRUSTED_PROXIES=0.0.0.0/0
|
|
SITE_ADDRESS=:80
|
|
CERT_EMAIL=
|
|
|
|
# For DNS Challenge based certificate generation, set the CERT_ACME_DNS, CERT_EMAIL
|
|
# CERT_ACME_DNS="acme_dns <CERT_DNS_PROVIDER> <CERT_DNS_PROVIDER_API_KEY>"
|
|
CERT_ACME_DNS=
|