# Self-hosted work hub: staged build strategy blueprint

_A decision-oriented synthesis for a small team evaluating an alternative to ClickUp. This blueprint reconciles the architecture, feature-scope, and adopt/fork/build workstreams; it is a delivery decision framework, not a claim of ClickUp feature parity or legal advice._

---

## 🎯 Decision: adopt first, prove the gaps, then earn the right to fork or build

**Recommended path:** run a **12-week, configuration-led OpenProject Community Edition pilot** as the initial system of record. Keep it upstream during the pilot. Add a separately deployed, idempotent automation bridge through supported APIs and signed webhooks; never write to the product database directly. In parallel, run two short evidence-gathering spikes in the first two weeks: a narrow **custom-core spike** and a **Plane acceptance spike**. This produces comparable evidence without prematurely committing the team to either a permanent fork or a multi-quarter greenfield program.

This recommendation does not assert that OpenProject is a ClickUp replacement. It is the lowest-risk first foundation among the evaluated options because the reviewed documentation directly supports work packages, agile boards, calendar, Gantt, wiki/history, role-based permissions, dashboards, APIs, and webhooks. The pilot must still validate edition fit, interaction quality, search/embedding behavior, configuration limits, and operational recovery in the team’s own environment. [1] [2] [3] [4] [5] [6] [7] [8] [9] [10]

> **Decision rule:** ClickUp parity is not a release criterion. Release 1 succeeds when one team can plan, execute, document, find, and review work in one operated self-hosted system without a second primary tracker or wiki. A permanent fork or custom product needs evidence that this outcome cannot be achieved with configuration and supported extension points.

The recommended course is deliberately staged because the three credible choices have different risks. Adopting upstream buys down task, planning, wiki, and operations implementation risk. A fork adds ongoing merge, security, migration, and license obligations. A greenfield build restores product control but requires the team to own identity, authorization, real-time collaboration, storage, search, recovery, accessibility, and support before it can approach broad feature parity.

| Decision outcome | Default action | Evidence required | What remains explicitly out of scope |
|---|---|---|---|
| **OpenProject pilot passes** | Operate upstream and add isolated API/webhook extensions only | Workflow, permissions, recovery, integration, usability, and upgrade gates all pass | Source fork and custom parity program |
| **A contained gap remains** | Configure first; otherwise build a companion service or seek an upstream contribution | Reproducible blocker that an API/webhook/configuration solution can solve | Direct database writes and broad source modification |
| **A contained, durable source gap remains** | Approve a minimal maintained fork | License approval, named maintainer, update rehearsal, CI, migration and rollback tests | Replacing core data, identity, authorization, or migration behavior |
| **Foundation model fails** | Fund a narrow custom MVP, not a parity rewrite | User evidence shows essential workflow/data model/retention or collaboration needs cannot be represented or bridged | Broad ClickUp-equivalent views, ecosystem, and scheduling suite |

## 🧭 Evidence-gated delivery path

The plan should reduce irreversible commitments. The OpenProject pilot is the **default product path**, while the custom and Plane spikes are **comparison instruments**, not parallel product builds. Plane remains a candidate rather than a presumed answer: its repository documents work items, pages, saved views, analytics, APIs, and self-hosting, but the tested edition, its detailed permission and planning behavior, and its higher operating surface must be verified. Its Community Edition is AGPL-3.0; external network deployment of modified versions requires legal assessment. [11] [12] [13]

```mermaid
flowchart TB
    accTitle: Evidence-Gated Foundation Decision
    accDescr: The team pilots upstream OpenProject while running narrow comparison spikes. Evidence determines whether to operate upstream, add an external extension, govern a small fork, or fund a narrow custom core.

    controls["Define workflows, role matrix, RPO/RTO, license posture"] --> pilot["OpenProject CE staging pilot\nNo source changes"]
    controls --> custom_spike["Five-day custom-core spike"]
    controls --> plane_spike["Five-day Plane acceptance spike"]
    pilot --> pilot_fit{"Workflow, permission, recovery, usability, upgrade gates pass?"}
    custom_spike --> compare["Compare verified gaps and whole-life cost"]
    plane_spike --> compare
    pilot_fit -->|"Yes"| upstream["Operate upstream + API/webhook automation bridge"]
    pilot_fit -->|"No"| bridge{"Can configuration, API, webhook, or contribution solve the blocker?"}
    bridge -->|"Yes"| extension["Build isolated companion extension"]
    bridge -->|"No"| contained{"Is a source change isolated, durable, licensed, and staffed?"}
    contained -->|"Yes"| fork["Approve minimal maintained fork"]
    contained -->|"No"| fundamental{"Does the core model fail the essential workflow?"}
    fundamental -->|"Yes"| build["Fund narrow custom MVP\nwith architecture gates"]
    fundamental -->|"No"| rescope["Rescope requirements or re-evaluate candidates"]
    compare --> pilot_fit

    classDef decision fill:#fef9c3,stroke:#ca8a04,stroke-width:2px,color:#713f12
    classDef pilot fill:#dbeafe,stroke:#2563eb,stroke-width:2px,color:#1e3a5f
    classDef outcome fill:#dcfce7,stroke:#16a34a,stroke-width:2px,color:#14532d
    classDef risk fill:#fee2e2,stroke:#dc2626,stroke-width:2px,color:#7f1d1d

    class pilot,custom_spike,plane_spike,extension,fork pilot
    class pilot_fit,bridge,contained,fundamental decision
    class upstream,build outcome
    class rescope risk
```

### First two weeks: establish the decision baseline

Before deploying anything, the sponsor, product lead, system owner, and security/operations owner should approve ten representative workflows, a role-permission matrix, a representative non-production dataset, data classification, and required recovery-point and recovery-time objectives (RPO/RTO). The supplied workstreams do **not** define expected users, concurrent editors, document/attachment volume, retention, or availability. Those inputs must be measured or decided before production sizing; “small team” is not a capacity specification.

In the same window, obtain a factual license review for the intended distribution model. OpenProject is GPL-3.0, while Plane and Vikunja are AGPL-3.0. This document makes no legal conclusion. The relevant question is not merely whether code can be deployed internally; it is whether the proposed modifications, hosting arrangement, and any delivery to external users are acceptable to counsel. [12] [13] [14]

Run the following limited spikes against the same workflow catalog.

| Spike | Time box | Required demonstration | Decision value |
|---|---:|---|---|
| **OpenProject configuration pilot** | 12 weeks, with go/no-go gates weekly | Configure hierarchy, roles, board/table/calendar/Gantt, wiki/history, dashboard, API/webhook, backup/restore, and upgrade rehearsal | Tests the recommended default on realistic workflows rather than a feature checklist |
| **Custom-core spike** | 5 working days | One workspace-scoped task model; direct/inherited authorization; one authorized task mutation that writes audit and outbox records; List/Board renderers from one query endpoint; attachment presign; search | Tests whether the team can preserve one work item across surfaces and whether the proposed architecture’s hard invariants are feasible |
| **Plane acceptance spike** | 5 working days | Self-host the current selected edition/release; import representative data; complete the acceptance scenarios; change one UI behavior and one permission/workflow behavior; estimate patch delta | Tests whether Plane’s apparent product head start survives edition, license, deployment, and customization realities |

The spikes should not proceed into feature work. Their output is a comparison record: exact version/commit, deployment manifest, scenarios passed/failed, workarounds, unresolved risks, measured setup and recovery effort, prospective patch list, and license review status.

## 🧱 Non-negotiable architecture decisions for any custom or companion path

The upstream pilot does not require the team to build a new task platform. However, any **custom MVP**, any significant external companion service, and any fork should meet the following architectural boundaries. They prevent the most costly failure mode: a visually plausible product that leaks data, diverges across views, or cannot recover after a routine incident.

### One canonical work graph and one view-query contract

Use a workspace-scoped hierarchy and a single canonical work-item model. A task must have one authoritative identity, status, dates, assignees, relations, activity history, and authorization outcome. List, Board/Kanban, Table, Calendar, Timeline, Roadmap, and Gantt are projections of the same authorized query result, not independent task systems. Saved views should store a **validated, versioned filter and layout abstract syntax tree (AST)**; the server compiles only allowlisted fields and operators into parameterized queries after applying scope and permission predicates. This boundary is the central protection against view-specific data or authorization drift.

For a custom MVP, start with a typed hierarchy such as `workspace → space → project/list → task → one-level subtask`. Carry `workspace_id` on every protected row, use immutable application-generated IDs, version mutable aggregates, and restrict a task to one primary location. Multiple list locations change permissions, completion, ordering, activity, and notification semantics; defer them until product behavior is defined.

### Authorization is a product service, not a page check

Centralize the decision as `can(principal, action, resource)` and enforce it for HTTP endpoints, WebSocket room admission, search snippets and counts, files, exports, dashboards, workers, webhooks, and integrations. Start with a deliberately small capability surface: view, comment, edit, and manage. Maintain an explicit permission matrix for workspace roles, hierarchy inheritance, direct grants, archive state, and guests.

Use PostgreSQL row-level security (RLS) as **defense in depth**, not as the sole policy engine. PostgreSQL documents that RLS is default-deny when enabled without an applicable policy, but table owners and roles with `BYPASSRLS` normally bypass it. The production application role must therefore not own protected tables or bypass RLS, and the real pooled-connection configuration must be integration-tested. OWASP also recommends deny-by-default, least privilege, and validation of permissions on every request. [15] [16]

### Transactional commands and durable effects

For custom services, PostgreSQL is the system of record. Each mutating command should run in a short transaction that: authenticates and authorizes; validates domain rules; writes the aggregate with optimistic version checking; appends an audit event; and inserts an immutable transactional-outbox event. Workers process the outbox at least once. Each handler must deduplicate by event ID or a handler receipt before side effects, expose a retry state, and retain a visible dead-letter queue. `SKIP LOCKED` is appropriate for this narrow queue-consumer pattern, not for general reads. [17]

The same rule applies to the upstream automation bridge. It must verify the inbound signature, persist raw delivery metadata and a deduplication key before acting, return success only after durable acceptance, and call the supported product API rather than its database. A retried or replayed delivery must create **no duplicate side effect**.

### Files, search, and integrations are secure projections

Keep file bytes in private S3-compatible object storage. A browser receives only a short-lived, constrained upload URL after `asset.upload` authorization. A worker verifies metadata and checksum, scans the content, and only then allows an attachment to become visible. Download URLs are issued afresh after `asset.read` authorization. Presigned URLs are time-limited bearer capabilities and must not be logged or substituted for authorization. [18]

Start custom search with a rebuildable PostgreSQL full-text projection, rather than a separate search cluster. PostgreSQL supports indexed `tsvector` data and GIN indexes for this purpose. Search must filter by scope and effective access before ranking, autocomplete, snippets, pagination, and counts, then re-check subject visibility before return. Add OpenSearch only when measured recall, ranking, faceting, or load requirements justify its operational cost. [19]

Put external integrations behind narrow adapters or the automation bridge. Store tokens encrypted, request minimum scopes, verify signatures, use replay-window and event-ID deduplication, and redact secrets from logs/audit. Do not promise a connector ecosystem because an outbound webhook exists.

### Docs are a dedicated subsystem, not a text field

For the custom route, use a schema-controlled rich-text representation—such as Tiptap/ProseMirror JSON—as the canonical document model. Use Yjs for concurrent state and persist durable update streams plus compacted snapshots. Keep document metadata, comments, permission grants, history, and links as relational data. Anchored comments should use Yjs relative positions, which are designed to remain associated with a logical location as edits occur; an unresolvable position should become an explicit unanchored comment rather than attach to arbitrary text. [20] [21]

Markdown is an import/export compatibility format, not canonical storage for rich collaborative Docs. Tiptap’s Markdown documentation identifies limitations including unsupported comments and constrained table cells, so imports must warn about or safely reject lossy conversion. A live-doc release requires a pinned editor schema, schema-version migration process, authenticated/revocable rooms, snapshot-plus-update-tail recovery, and load/reconnect tests. [22]

### Start with a modular monolith; split only under measured pressure

For a custom product, begin with a modular monolith containing an API/policy runtime and worker runtime, plus a separately deployable stateful collaboration runtime. PostgreSQL is authoritative; object storage holds bytes; Redis, if needed, holds only ephemeral presence, cache, rate-limit, or fan-out state. Docker Compose on a single server or small virtual-machine set is a reasonable initial deployment model. Kubernetes, OpenSearch, Temporal, and microservices are later choices when measured scaling, rollout, multi-host recovery, long-running workflow, or operations-team needs justify them. Docker documents Compose production guidance, while Temporal’s own self-hosted checklist illustrates the substantial operating obligations of a durable workflow platform. [23] [24]

## 🚀 MVP and later phases

The scope below applies to a custom fallback or to the requirements used to judge the upstream pilot. It avoids calling a collection of screens an MVP before permissions, audit, recovery, and background effects work end to end.

### Release 1: operated daily-work MVP

Release 1 should enable a team to create, organize, discuss, schedule, document, and find authorized work. The upstream pilot should configure these outcomes wherever available; the custom path should implement them as a vertical slice.

| Scope | Must work in Release 1 | Explicitly deferred |
|---|---|---|
| Work model | Workspace membership; shallow project/list hierarchy; task/subtask; status, assignee, priority, dates, labels, basic typed custom fields, comments, attachments, activity | Multiple task locations, recurrence, templates, goals, arbitrary hierarchy types, workload balancing |
| Views | List, Board, Table, Calendar from one task/query model; saved filters and sort | Formula engine, arbitrary pivots, capacity/workload, every display option |
| Docs | Per-project wiki or simple Docs; page tree; rich text; tables; file links; comments; snapshots/history; Markdown import/export with loss warnings | Full real-time multi-cursor parity, public publishing, arbitrary embeds, whiteboards, AI authoring |
| Access and discovery | Workspace/project roles; inherited access; permission-filtered task/Doc search; secure files; audit trail | Fine-grained custom roles, public sharing by default, enterprise e-discovery |
| Automation and integration | Durable event/outbox foundation; signed webhooks; one source-control or notification integration; operator-visible retries | No-code automation studio, marketplace, unrestricted third-party actions |
| Operations | TLS, backups, restore drill, logs/metrics/alerts, staging, upgrade procedure, secret rotation | Multi-region active-active, formal enterprise availability or compliance claims |

For Gantt, the MVP is not simply a bar chart. It needs one documented date model, dependency cycle rejection, and explicit behavior when users schedule a follower before its predecessor. The product may reject the action or offer a previewed downstream shift; it must not silently alter dates. Critical path, resource leveling, baselines, and sophisticated calendar scheduling are deferred. OpenProject’s Gantt documentation demonstrates the normal user expectations around dates, hierarchy, and predecessor/successor dependencies, but it should be treated as a benchmark rather than a parity promise. [4]

### Phase 2: knowledge and planning after the daily-work core is stable

Add nested Docs, task↔Doc links, document comments, structured history/restore, Timeline, basic Roadmap, and basic Gantt only after the common task model, date semantics, hierarchy queries, permission rules, and backups are proven. For a custom product, live collaboration stays behind a feature flag until convergence, schema-compatibility, revocation, and snapshot-recovery tests pass. A Roadmap should represent explicit initiatives or projects with a committed range, owner, and health status; a calculated range from task dates must be labeled and must not silently overwrite a commitment.

### Phase 3: reporting, automation, and integration

Build fixed dashboard widgets as typed aggregates over the same authorized saved-query model: tasks by status, overdue work, work by assignee, completion trend, and a filtered table. Show an `as_of` time and avoid building a general business-intelligence language. Add a constrained automation model with event triggers, validated conditions, small action sets, versioning, causation IDs, hop limits, deduplication, run logs, and manual replay. Add one well-operated source-control connector before expanding to broader OAuth or marketplace integrations.

### Phase 4: parity decisions, not a roadmap promise

Guests, share links, custom roles, real-time Docs, scheduled reporting, importers, recurrence, templates, advanced scheduling, workload/capacity, broad integrations, and richer collaboration should each require observed demand, an accountable owner, a scoped product contract, and a costed operations plan. ClickUp itself documents many distinct views, Docs, permissions, automations, dashboards, and a broad connected-tool surface; reproducing all of them is a continuing product program, not a finite finishing phase. [25] [26] [27] [28] [29]

## ⚖️ Build-versus-fork criteria

The correct choice is based on **whole-life delivery cost and evidence**, not whether an upstream UI looks close enough in a demo. The pilot must make the following decision tests falsifiable.

### Adopt upstream when the pilot passes all six gates

Operate OpenProject upstream if at least eight of ten representative workflows complete without code changes; permissions are acceptable with test accounts; a signed webhook triggers exactly one idempotent bridge action; a clean-environment restore succeeds; an upgrade rehearsal succeeds in staging; and at least five intended users complete the workflows without critical usability failure. The pre-agreed usability metric should include a median completion-time threshold and a definition of critical failure. A system that has the listed modules but fails ordinary team behavior should not be treated as fit.

### Build a companion before considering a fork

Use configuration, supported APIs/webhooks, an isolated automation bridge, or an upstream contribution where they can solve the gap. A companion service is the default extension mechanism because it protects upgradeability and keeps organization-specific logic outside the upstream core. It may integrate through authenticated APIs and signed webhooks; it must not mutate the upstream database.

### Approve a fork only when every condition is true

| Required condition | Evidence that must exist before approval |
|---|---|
| **Specific, durable gap** | Reproduction steps, affected roles, business impact, and an acceptance test from the pilot |
| **No supported alternative** | Written analysis of configuration, API/webhook companion, integration, and upstream-contribution options |
| **Contained change** | A small versioned extension boundary; no first-release changes to core identity, authorization, persistence, or migration semantics |
| **License is acceptable** | Counsel-approved license/distribution position, retained notices, and an inventory of upstream components |
| **Maintenance is funded** | Named owner for release intake, security advisories, CI, regression suite, migration tests, and rollback |
| **Upstream survival is proven** | An unmodified upstream build in CI and a successful merge/rebase rehearsal before feature work |

Maintain the fork as `upstream/<version>` plus a small `product/main` delta. Keep a patch ledger with the upstream SHA, rationale, owner, tests, expected upgrade conflict, and contribution status. Stop further fork feature work if the first change touches authorization/data migrations, cannot rebase cleanly at the next upstream rehearsal, or needs more than one release cycle to stabilize.

### Authorize a custom build only when the foundation fails

Fund a custom MVP only if representative users and technical assessment show that an essential workflow, authorization model, document-retention requirement, or collaboration interaction cannot be represented by the candidate’s core model or safely bridged. A source build is not justified merely by visual preference or an untested feature gap. Sponsors must accept in writing a narrow scope, the exclusions above, and the capacity for a multi-quarter program. The architecture workstream’s estimate of **6–9 months for a narrow MVP with 4–6 dedicated engineers** is a planning assumption, not a vendor-derived promise; it should be re-estimated after Stage 0 measurement.

## 🛠️ Operating requirements and ownership

Self-hosting transfers operating responsibility even when the application is adopted upstream. Production authorization should be contingent on named owners and written runbooks for the following controls.

| Control | Minimum requirement | Evidence / cadence | Accountable owner |
|---|---|---|---|
| Identity and access | TLS; secure sessions; least-privilege roles; approval for role/configuration changes; token and secret rotation | Role-matrix test on every material permissions/configuration change | Security/operations owner |
| Data recovery | Encrypted, off-host database and file backups with retention appropriate to the approved RPO/RTO | Clean-room restore at least quarterly; record observed RPO/RTO and sampled task/Doc/file integrity | System owner |
| Upgrades | Pinned application images/packages; staging mirrors production topology; backward-compatible migration/rollback plan | Staging upgrade, smoke suite, permission/integration tests before every production update | Platform owner |
| Automation bridge | Signature verification; durable inbound log; idempotency key; retries with backoff; dead-letter queue; replay requires operator role | Duplicate, invalid-signature, failure, restart, and replay tests | Integration engineer |
| File safety | Private bucket; short-lived signed URLs; type/size/checksum checks; malware/quarantine flow where content is accepted | Rejected object cannot attach or download; access revocation test | Platform owner |
| Observability | Structured logs, correlation IDs, request/error latency, worker lag, backup status, storage capacity, authorization-denial telemetry | Alerts tested by simulated worker and backup failure; no document bodies/secrets in logs | System owner |
| Support and governance | Incident, restore, upgrade, and token-rotation runbooks; change control for custom fields/views/automations | Named on-call/escalation route and post-incident review process | Sponsor and system owner |

For a custom deployment, run API, worker, collaboration service, reverse proxy, database, and object storage as separate deployable processes. Collect request, event, and correlation IDs across their handoffs. OpenTelemetry identifies traces, metrics, and logs as core telemetry signals; use those signals without putting document bodies, access tokens, or sensitive personal data in observability systems. [30]

## ✅ Proof-of-concept and release gates

No path should pass on a feature walkthrough alone. These gates are release blockers because they test the cross-cutting properties most likely to fail after a seemingly successful demo.

### Common pilot gates

| Gate | Required proof | Pass condition |
|---|---|---|
| **Workflow coherence** | Create/edit one work item from each configured view and reopen it elsewhere | Status, hierarchy, dates, assignees, order, files, and activity remain consistent |
| **Permission and revocation** | Six-account role matrix plus user removal test | A revoked user loses task, Doc, file, live channel, dashboard, export, search, and cached-data access; a commenter cannot change task fields |
| **Docs/history** | Create a table/image page, revise it, inspect history/diff, export Markdown, and test denied access | History and export behave as documented; lossy constructs are warned; unauthorized changes fail |
| **Automation reliability** | Valid, invalid, duplicate, failed, restarted, and replayed webhook deliveries | One intended side effect at most; failure is durable, inspectable, and recoverable |
| **Restore** | Restore database and file data into clean staging | Named operator achieves the approved recovery target and demonstrates sampled task/Doc/file integrity |
| **Upgrade** | Upgrade the pinned upstream release in staging | Smoke suite, role matrix, and API/webhook contracts pass before production approval |
| **Usability** | At least five intended users complete the ten workflows independently | Pre-agreed time/error thresholds pass with no critical usability failure |

### Custom-path Stage 0 gates

If the team chooses the custom fallback, do not build advanced views, integrations, or planning features until all three hard properties below are proven:

1. **Workspace isolation:** a principal from Workspace A cannot discover, read, count, download, search, export, or join a resource in Workspace B by changing an identifier or through background/real-time paths.
2. **Collaborative-document convergence and recovery:** two users can edit, disconnect, reconnect, and converge; a snapshot plus update tail recovers current state; a user who loses access is removed or made read-only; incompatible schema clients cannot silently destroy nodes.
3. **One audited, idempotent vertical slice:** an authorized task mutation uses optimistic concurrency, writes exactly one audit event and one outbox event transactionally, drives a retry-safe effect, and appears consistently in List and Board.

The subsequent custom gates are: secure upload/scan and permission-aware search; document snapshots, comment anchors, and Markdown-loss fixtures; then dependency cycle rejection, automation loop prevention, credential revocation, and dashboard freshness. This order is intentionally architecture-first: new views and integrations multiply the impact of a broken policy or event model.

## ⚠️ Uncertainties that remain decisions, not assumptions

The workstreams establish an evidence-based route but not several product and operating facts. The team should record the following as open decisions before production: required tenancy model; internal-only versus external-user distribution; data residency; RPO/RTO; availability objective; concurrent editors; expected task/document/attachment growth; retention and deletion rules; required identity federation; mobile/offline needs; and which integrations must be bi-directional. These inputs determine sizing, backup design, license interpretation, editor scope, and whether the recommended upstream foundation remains appropriate.

The largest known technical uncertainty is rich collaborative Docs. Yjs supports mergeable shared data and idempotent update delivery, but it does not solve editor schema compatibility, authorization, persistence, indexing, backup, anchoring, or document-product behavior by itself. [20] [21] The largest operational uncertainty is the maintenance budget: upstream adoption reduces implementation work but does not remove responsibility for backups, secrets, storage, email, monitoring, security patches, role configuration, and recovery. The largest product uncertainty is whether the team needs a lightweight daily-work experience or a more formal project-management interaction model. The usability pilot, not a feature inventory, resolves that uncertainty.

## 📌 Immediate authorization request

Authorize **Weeks 0–2** only: name owners; approve the Release-1 exclusions; define ten workflows and success metrics; complete the license posture review; deploy OpenProject Community Edition to reproducible staging; and run the custom-core and Plane acceptance spikes. At the end of Week 2, confirm the 12-week OpenProject pilot plan or stop/rescope based on evidence. Do **not** authorize a source fork or a greenfield parity program before the Week 11 decision record evaluates the gates above.

## References

[1]: https://www.openproject.org/docs/user-guide/work-packages/ "OpenProject: Work packages"
[2]: https://www.openproject.org/docs/user-guide/agile-boards/ "OpenProject: Boards for Agile Project Management"
[3]: https://www.openproject.org/docs/user-guide/calendar/ "OpenProject: Calendar"
[4]: https://www.openproject.org/docs/user-guide/gantt-chart/ "OpenProject: Gantt charts"
[5]: https://www.openproject.org/docs/user-guide/wiki/ "OpenProject: Wiki"
[6]: https://www.openproject.org/docs/user-guide/wiki/create-edit-wiki/ "OpenProject: Create and edit a wiki page"
[7]: https://www.openproject.org/docs/system-admin-guide/users-permissions/roles-permissions/ "OpenProject: Roles and permissions"
[8]: https://www.openproject.org/docs/user-guide/projects/project-home/project-widgets/ "OpenProject: Project widgets"
[9]: https://www.openproject.org/docs/system-admin-guide/api-and-webhooks/ "OpenProject: API and webhooks"
[10]: https://www.openproject.org/docs/installation-and-operations/ "OpenProject: Installation & operations guide"
[11]: https://github.com/makeplane/plane "Plane primary repository"
[12]: https://developers.plane.so/self-hosting/self-hosting-101 "Plane: Self-hosting 101"
[13]: https://github.com/makeplane/plane/blob/preview/LICENSE.txt "Plane — GNU Affero General Public License v3"
[14]: https://github.com/go-vikunja/vikunja "Vikunja primary repository"
[15]: https://www.postgresql.org/docs/current/ddl-rowsecurity.html "PostgreSQL documentation: Row Security Policies"
[16]: https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html "OWASP Authorization Cheat Sheet"
[17]: https://www.postgresql.org/docs/current/sql-select.html "PostgreSQL documentation: SELECT locking clause and SKIP LOCKED"
[18]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-presigned-url.html "Amazon S3 User Guide: Download and upload objects with presigned URLs"
[19]: https://www.postgresql.org/docs/current/textsearch-tables.html "PostgreSQL documentation: Full Text Search Tables and Indexes"
[20]: https://docs.yjs.dev/ "Yjs Documentation: Introduction"
[21]: https://docs.yjs.dev/api/relative-positions "Yjs Documentation: Relative Positions"
[22]: https://tiptap.dev/docs/editor/markdown "Tiptap documentation: Markdown"
[23]: https://docs.docker.com/compose/how-tos/production/ "Docker documentation: Use Compose in production"
[24]: https://docs.temporal.io/self-hosted-guide/production-checklist "Temporal documentation: Self-hosted production readiness checklist"
[25]: https://clickup.com/features "ClickUp features — all-in-one work management platform"
[26]: https://help.clickup.com/hc/en-us/articles/13856392825367-Intro-to-the-Hierarchy "ClickUp Help: Intro to the Hierarchy"
[27]: https://help.clickup.com/hc/en-us/articles/6328174371351-Intro-to-Docs "ClickUp Help: Intro to Docs"
[28]: https://help.clickup.com/hc/en-us/articles/6312102752791-Intro-to-Automations "ClickUp Help: Intro to Automations"
[29]: https://help.clickup.com/hc/en-us/articles/6312197753239-Intro-to-Dashboards "ClickUp Help: Intro to Dashboards"
[30]: https://opentelemetry.io/docs/concepts/signals/ "OpenTelemetry documentation: Signals"
