Renames: - platform/ → workspace-server/ (Go module path stays as "platform" for external dep compat — will update after plugin module republish) - workspace-template/ → workspace/ Removed (moved to separate repos or deleted): - PLAN.md — internal roadmap (move to private project board) - HANDOFF.md, AGENTS.md — one-time internal session docs - .claude/ — gitignored entirely (local agent config) - infra/cloudflare-worker/ → Molecule-AI/molecule-tenant-proxy - org-templates/molecule-dev/ → standalone template repo - .mcp-eval/ → molecule-mcp-server repo - test-results/ — ephemeral, gitignored Security scrubbing: - Cloudflare account/zone/KV IDs → placeholders - Real EC2 IPs → <EC2_IP> in all docs - CF token prefix, Neon project ID, Fly app names → redacted - Langfuse dev credentials → parameterized - Personal runner username/machine name → generic Community files: - CONTRIBUTING.md — build, test, branch conventions - CODE_OF_CONDUCT.md — Contributor Covenant 2.1 All Dockerfiles, CI workflows, docker-compose, railway.toml, render.yaml, README, CLAUDE.md updated for new directory names. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
3.8 KiB
Constraints & Rules
Key design rules and invariants that must be followed throughout the codebase.
1. The Platform Never Routes Agent Messages
A2A messages go workspace-to-workspace directly. The platform only handles:
- Discovery — resolving workspace URLs
- Registry — knowing what workspaces exist
2. Postgres Is Source of Truth, Redis Is Ephemeral
If Redis is wiped, workspaces re-register on next heartbeat and state is restored. Nothing critical lives only in Redis.
3. structure_events Is Append-Only
Never UPDATE or DELETE rows in this table. The workspaces table is the mutable projection. See Event Log.
4. workspace-template Is Generic
It contains no business logic. All business logic lives in workspace-configs-templates/. The template reads config files at startup — it does not know what kind of workspace it is until it loads config.
5. Bundles Do Not Contain Secrets
API keys, passwords, and credentials are never serialized into bundle JSON. The provisioner injects them from the host environment when spinning up a workspace container.
6. No Auth for MVP
The platform API has no authentication. All endpoints are open. This is intentional — the project follows the n8n Community Edition model. Auth is added in a separate SaaS wrapper (molecule-cloud).
7. org_id Is Omitted from MVP Schema
Removed entirely for MVP simplicity. Added in the SaaS migration for multi-tenancy.
8. Tier Determines Provisioner, Not Behavior
The workspace code is the same regardless of tier. The tier only affects how the workspace is deployed:
- Docker flags
- host access level and isolation boundary
- Resource allocation
See Workspace Tiers.
9. The Hierarchy IS the Topology
There is no manual connection wiring. Communication is derived from the parent_id hierarchy:
- Siblings can talk to each other
- Parents can talk to children (and vice versa)
- No skipping levels
The org chart IS the access control policy. See Communication Rules.
10. Discovery-Time Auth for MVP
Direct A2A calls between workspaces are unauthenticated in MVP. Access control is enforced at discovery time via CanCommunicate(). Post-MVP adds platform-issued signed tokens scoped to caller/target pairs. See A2A Protocol — Authentication.
11. Secrets in Postgres, Encrypted
Workspace secrets (API keys, credentials) are stored in Postgres with AES-256 encryption at the application layer. The encryption key comes from the SECRETS_ENCRYPTION_KEY environment variable. Secrets are never included in bundles, never logged, never exposed via API responses.
12. Last-Write-Wins for MVP
Concurrent canvas modifications from multiple clients use last-write-wins. No optimistic locking or CRDTs for MVP.
13. Security Headers on All Responses
The platform applies HTTP security headers via middleware (workspace-server/internal/middleware/securityheaders.go):
X-Content-Type-Options: nosniffX-Frame-Options: DENYX-XSS-Protection: 1; mode=block
These are applied after CORS middleware on every response.
14. No Exposed Database Ports
Postgres and Redis must not expose host ports. They communicate exclusively over the internal Docker network (molecule-monorepo-net). Use docker compose exec for direct access during development.
Related Docs
- SaaS Upgrade Path — How auth and multi-tenancy are added
- Bundle System — Why bundles exclude secrets
- Event Log — The append-only rule
- Communication Rules — Hierarchy = access control