Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
8 changes: 4 additions & 4 deletions CLA.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Quackback Contributor License Agreement
# RitualChain Contributor License Agreement

Thank you for your interest in contributing to Quackback. This Contributor License Agreement ("Agreement") documents the rights granted by contributors to Quackback Ltd ("Company").
Thank you for your interest in contributing to RitualChain. This Contributor License Agreement ("Agreement") documents the rights granted by contributors to RitualChain Ltd ("Company").

By submitting a Contribution (as defined below) to this project, you agree to the following terms and conditions.

## 1. Definitions

**"Contribution"** means any original work of authorship, including any modifications or additions to an existing work, that you submit to the Company for inclusion in the Quackback project.
**"Contribution"** means any original work of authorship, including any modifications or additions to an existing work, that you submit to the Company for inclusion in the RitualChain project.

**"Submit"** means any form of electronic, verbal, or written communication sent to the Company, including but not limited to pull requests, issues, patches, and emails.

Expand Down Expand Up @@ -48,4 +48,4 @@ You agree to notify the Company of any facts or circumstances of which you becom

By submitting a pull request to this repository, you indicate your agreement to this CLA. A CLA assistant bot will verify your signature on each pull request.

If you have questions about this Agreement, please open an issue or contact legal@quackback.io.
If you have questions about this Agreement, please open an issue or contact legal@ritual.net.
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# CLAUDE.md

Quackback - open-source customer feedback platform. Bun monorepo, TanStack Start, PostgreSQL + Drizzle, Tailwind v4 + shadcn/ui.
RitualChain - open-source customer feedback platform. Bun monorepo, TanStack Start, PostgreSQL + Drizzle, Tailwind v4 + shadcn/ui.

## Commands

Expand All @@ -13,7 +13,7 @@ bun run test && bun run test:e2e && bun run lint && bun run typecheck

## Rules

- Entity IDs are branded TypeIDs via `@quackback/ids`
- Entity IDs are branded TypeIDs via `@ritualchain/ids`
- Never add co-author trailers to git commits
- When cutting a release, bump `version` in `apps/web/package.json` to match the git tag — this is the source of truth for `__APP_VERSION__` (injected at build time via Vite)
- Tier limits live in `settings.tier_limits` (JSON column) and are enforced via `getTierLimits()` + the helpers in `apps/web/src/lib/server/domains/settings/tier-enforce.ts`. The default (no row) is unlimited. The control-plane writes per-tenant limits via `/api/v1/internal/tier-limits` (scope-gated). The OSS code is unaware of "cloud" as a concept — limits and their writer are the same mechanism for self-hosters and cloud tenants.
20 changes: 10 additions & 10 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# Contributing to Quackback
# Contributing to RitualChain

Thank you for your interest in contributing to Quackback! This guide will help you get started.
Thank you for your interest in contributing to RitualChain! This guide will help you get started.

## Quick Start

```bash
# Clone the repository
git clone https://github.com/quackbackio/quackback.git
cd quackback
git clone https://github.com/ritualchain/ritualchain.git
cd ritualchain

# Run setup (installs dependencies, starts Docker, runs migrations, seeds demo data)
bun run setup
Expand All @@ -21,7 +21,7 @@ Open http://localhost:3000 to see the app.
## Project Structure

```
quackback/
ritualchain/
├── apps/web/ # TanStack Start application
│ ├── src/
│ │ ├── routes/ # File-based routing (TanStack Router)
Expand All @@ -38,7 +38,7 @@ quackback/

## Architecture

Quackback uses **TanStack Start** with **TanStack Router** for file-based routing and server functions.
RitualChain uses **TanStack Start** with **TanStack Router** for file-based routing and server functions.

### Server Functions (`apps/web/src/lib/server-functions/`)

Expand Down Expand Up @@ -73,7 +73,7 @@ export async function createPost(input: CreatePostInput, author: Author) {

### Database Access

Always import from `@/lib/db`, not `@quackback/db`:
Always import from `@/lib/db`, not `@ritualchain/db`:

```typescript
import { db, posts, eq } from '@/lib/db'
Expand Down Expand Up @@ -115,7 +115,7 @@ We require all contributors to sign our [Contributor License Agreement (CLA)](CL

**Why a CLA?**

The CLA allows Quackback to:
The CLA allows RitualChain to:

- Offer the software under dual licenses (AGPL-3.0 for open source, commercial for enterprise)
- Defend the project against legal issues
Expand All @@ -128,7 +128,7 @@ The CLA allows Quackback to:
3. If not, the bot will prompt you to sign by commenting on the PR
4. Once signed, your signature applies to all future contributions

The CLA is based on the Apache Individual Contributor License Agreement and grants Quackback the right to use your contributions under any license terms.
The CLA is based on the Apache Individual Contributor License Agreement and grants RitualChain the right to use your contributions under any license terms.

## Pull Request Process

Expand Down Expand Up @@ -162,4 +162,4 @@ When reporting bugs, include:

## License

Quackback core is licensed under AGPL-3.0. See [LICENSE](LICENSE) for details.
RitualChain core is licensed under AGPL-3.0. See [LICENSE](LICENSE) for details.
52 changes: 26 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<p align="center">
<a href="https://quackback.io">
<img src=".github/logo.svg" alt="Quackback Logo" width="80" height="80" />
<a href="https://ritual.net">
<img src=".github/logo.svg" alt="RitualChain Logo" width="80" height="80" />
</a>
</p>

<h1 align="center">Quackback</h1>
<h1 align="center">RitualChain</h1>

<p align="center">
<strong>Open source feedback for teams that ship.</strong>
Expand All @@ -16,46 +16,46 @@
</p>

<p align="center">
<a href="https://quackback.io">Website</a> &middot;
<a href="https://quackback.io/docs">Docs</a> &middot;
<a href="https://ritual.net">Website</a> &middot;
<a href="https://ritual.net/docs">Docs</a> &middot;
<a href="#get-started">Get Started</a>
</p>

<p align="center">
<a href="https://github.com/QuackbackIO/quackback/stargazers"><img src="https://img.shields.io/github/stars/QuackbackIO/quackback?style=flat&color=f5a623" alt="GitHub stars" /></a>
<a href="https://github.com/QuackbackIO/quackback/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-AGPL--3.0-blue" alt="License" /></a>
<a href="https://github.com/QuackbackIO/quackback/actions"><img src="https://img.shields.io/github/actions/workflow/status/QuackbackIO/quackback/ci.yml?label=CI" alt="CI" /></a>
<a href="https://github.com/QuackbackIO/quackback/issues"><img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg" alt="PRs Welcome" /></a>
<a href="https://github.com/RitualChain/ritualchain/stargazers"><img src="https://img.shields.io/github/stars/RitualChain/ritualchain?style=flat&color=f5a623" alt="GitHub stars" /></a>
<a href="https://github.com/RitualChain/ritualchain/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-AGPL--3.0-blue" alt="License" /></a>
<a href="https://github.com/RitualChain/ritualchain/actions"><img src="https://img.shields.io/github/actions/workflow/status/RitualChain/ritualchain/ci.yml?label=CI" alt="CI" /></a>
<a href="https://github.com/RitualChain/ritualchain/issues"><img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg" alt="PRs Welcome" /></a>
</p>

<p align="center">
<img src=".github/screenshot.png" alt="Quackback feedback portal" width="800" />
<img src=".github/screenshot.png" alt="RitualChain feedback portal" width="800" />
</p>

## Get Started

**Cloud** — start free at [app.quackback.io](https://app.quackback.io/signup). We host, scale, and maintain it for you. No setup required.
**Cloud** — start free at [app.ritual.net](https://app.ritual.net/signup). We host, scale, and maintain it for you. No setup required.

**Self-hosted** anywhere with [Docker](#docker) or [one click on Railway](#one-click-deploy).

## Why Quackback?
## Why RitualChain?

Most feedback tools are expensive, closed-source, and lock you in. Quackback gives you a modern feedback system you actually own.
Most feedback tools are expensive, closed-source, and lock you in. RitualChain gives you a modern feedback system you actually own.

- **Self-host for free.** Run on your own infrastructure. No per-seat pricing.
- **Own your data.** Your feedback lives in your own database. No vendor lock-in.
- **AI-powered.** Automatic duplicate detection, AI summaries, feedback extraction from external sources, and an [MCP server](https://quackback.io/docs/mcp) that lets AI agents search, triage, and act on feedback directly.
- **AI-powered.** Automatic duplicate detection, AI summaries, feedback extraction from external sources, and an [MCP server](https://ritual.net/docs/mcp) that lets AI agents search, triage, and act on feedback directly.
- **24 integrations.** Slack, Linear, Jira, GitHub, Intercom, Zendesk, and [more](#integrations) out of the box.

## Features

- **Feedback boards.** Let users vote, comment, and track status on feature requests. Vote on behalf of customers and see a full activity timeline on every post.
- **AI-powered.** Automatically detect duplicates, summarize key themes, and ingest feedback from Slack, email, and other sources so nothing slips through the cracks.
- **Embeddable widget.** Collect feedback right inside your app with a [drop-in widget](https://quackback.io/docs/widget/installation). Works on desktop and mobile, with native SDKs for [iOS](https://github.com/QuackbackIO/quackback-ios) and [Android](https://github.com/QuackbackIO/quackback-android).
- **Embeddable widget.** Collect feedback right inside your app with a [drop-in widget](https://ritual.net/docs/widget/installation). Works on desktop and mobile, with native SDKs for [iOS](https://github.com/RitualChain/ritualchain-ios) and [Android](https://github.com/RitualChain/ritualchain-android).
- **Admin inbox.** Triage incoming feedback in one place. Filter, group, dismiss, and restore deleted posts.
- **Roadmap & changelog.** Show users what's planned, in progress, and shipped. Publish updates and schedule posts for later.
- **Integrations.** [24 integrations](#integrations) including Slack, Linear, Jira, GitHub, Intercom, Zendesk, and two-way issue tracker sync.
- **API, webhooks & MCP.** Automate workflows with the REST API, outbound webhooks, and a 23-tool [MCP server](https://quackback.io/docs/mcp) for AI agents.
- **API, webhooks & MCP.** Automate workflows with the REST API, outbound webhooks, and a 23-tool [MCP server](https://ritual.net/docs/mcp) for AI agents.
- **Internationalization.** Portal and widget available in English, French, German, Spanish, and Arabic with full RTL support. Auto-detects browser language.
- **Flexible auth.** Password, email OTP, Google, GitHub, and SSO with providers like Okta and Auth0.
- **SEO-ready.** Auto-generated sitemap and social sharing previews on every portal page.
Expand All @@ -68,16 +68,16 @@ Slack, Linear, Jira, GitHub, GitLab, Asana, ClickUp, Monday, Trello, Notion, Sho

### One-Click Deploy

[![Deploy on Railway](https://railway.com/button.svg)](https://railway.com/deploy/quackback?referralCode=ez8Slg&utm_source=github&utm_medium=readme&utm_campaign=deploy-button)
[![Deploy on Railway](https://railway.com/button.svg)](https://railway.com/deploy/ritualchain?referralCode=ez8Slg&utm_source=github&utm_medium=readme&utm_campaign=deploy-button)

### Docker

```bash
git clone https://github.com/QuackbackIO/quackback.git
cd quackback
git clone https://github.com/RitualChain/ritualchain.git
cd ritualchain
cp .env.example .env # Edit with your configuration
docker build -t quackback -f apps/web/Dockerfile .
docker run -p 3000:3000 --env-file .env quackback
docker build -t ritualchain -f apps/web/Dockerfile .
docker run -p 3000:3000 --env-file .env ritualchain
```

Requires PostgreSQL and a Redis-compatible store. Set `DATABASE_URL` and `REDIS_URL` in `.env`. Migrations run automatically on startup.
Expand All @@ -86,15 +86,15 @@ Requires PostgreSQL and a Redis-compatible store. Set `DATABASE_URL` and `REDIS_

See the [Contributing Guide](CONTRIBUTING.md) to get started.

- [GitHub Discussions](https://github.com/QuackbackIO/quackback/discussions) — ask questions, share ideas
- [GitHub Discussions](https://github.com/RitualChain/ritualchain/discussions) — ask questions, share ideas

### Local Development

Prerequisites: [Bun](https://bun.sh/) v1.3.7+ and [Docker](https://docker.com/)

```bash
git clone https://github.com/QuackbackIO/quackback.git
cd quackback
git clone https://github.com/RitualChain/ritualchain.git
cd ritualchain
bun run setup # Install deps, start Docker, run migrations
bun run db:seed # Optional: seed demo data
bun run dev # http://localhost:3000
Expand All @@ -111,8 +111,8 @@ Log in with `demo@example.com` / `password`.
- [Tailwind CSS v4](https://tailwindcss.com/) + [shadcn/ui](https://ui.shadcn.com/) · Styling
- [Bun](https://bun.sh/) · Runtime and package manager

<a href="https://github.com/QuackbackIO/quackback/graphs/contributors">
<img src="https://contrib.rocks/image?repo=QuackbackIO/quackback" alt="Contributors" />
<a href="https://github.com/RitualChain/ritualchain/graphs/contributors">
<img src="https://contrib.rocks/image?repo=RitualChain/ritualchain" alt="Contributors" />
</a>

## License
Expand Down
4 changes: 2 additions & 2 deletions apps/web/docker-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
set -e

echo "========================================"
echo " Quackback starting..."
echo " RitualChain starting..."
echo "========================================"

# Migrations: skipped in K8s where a pre-upgrade Helm hook Job runs them
Expand All @@ -28,6 +28,6 @@ fi

# Start the application
echo ""
echo "Starting Quackback server on port ${PORT:-3000}..."
echo "Starting RitualChain server on port ${PORT:-3000}..."
echo "========================================"
exec bun .output/server/index.mjs
2 changes: 1 addition & 1 deletion apps/web/e2e/scripts/get-mention-target.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
* Usage: bun get-mention-target.ts [excludeEmail]
*/
import postgres from 'postgres'
import { fromUuid } from '@quackback/ids'
import { fromUuid } from '@ritualchain/ids'

const excludeEmail = process.argv[2] ?? 'demo@example.com'

Expand Down
8 changes: 4 additions & 4 deletions apps/web/e2e/scripts/seed-identity-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* settings.* columns are JSON text; the provider model lives in the
* `identity_provider`, `sso_verified_domain`, and `integration_platform_credentials`
* tables. We write raw SQL (same style as the other e2e scripts) and generate
* TypeIDs via `@quackback/ids` (the column default is a JS-level drizzle default
* TypeIDs via `@ritualchain/ids` (the column default is a JS-level drizzle default
* that a raw insert wouldn't trigger).
*
* The client secret is encrypted with the SAME AES-256-GCM + HKDF scheme as the
Expand All @@ -31,7 +31,7 @@
*/
import postgres from 'postgres'
import { hkdfSync, randomBytes, createCipheriv, randomUUID } from 'crypto'
import { generateId, toUuid } from '@quackback/ids'
import { generateId, toUuid } from '@ritualchain/ids'

const action = (process.argv[2] || '').toLowerCase()
if (action !== 'seed' && action !== 'remove') {
Expand All @@ -50,8 +50,8 @@ if (!connectionString) {
function encryptPlatformCredentials(creds: Record<string, string>): string {
const secretKey = process.env.SECRET_KEY
if (!secretKey) throw new Error('SECRET_KEY environment variable is required')
const info = 'quackback:v1:integration-platform-credentials'
const key = Buffer.from(hkdfSync('sha256', secretKey, 'quackback-encryption-salt-v1', info, 32))
const info = 'ritualchain:v1:integration-platform-credentials'
const key = Buffer.from(hkdfSync('sha256', secretKey, 'ritualchain-encryption-salt-v1', info, 32))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Encryption HKDF labels changed

High Severity

Integration credential encryption now derives keys with ritualchain HKDF salt and info strings. Ciphertext written under the previous quackback labels cannot be decrypted after upgrade, breaking SSO and integration secrets until credentials are re-entered.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit c2d80a2. Configure here.

const iv = randomBytes(12)
const cipher = createCipheriv('aes-256-gcm', key, iv, { authTagLength: 16 })
const ct = Buffer.concat([cipher.update(JSON.stringify(creds), 'utf8'), cipher.final()])
Expand Down
2 changes: 1 addition & 1 deletion apps/web/e2e/scripts/setup-access-fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
*/
import postgres from 'postgres'
import { randomUUID } from 'crypto'
import { generateId, toUuid, fromUuid } from '@quackback/ids'
import { generateId, toUuid, fromUuid } from '@ritualchain/ids'

const memberEmail = process.argv[2]
if (!memberEmail) {
Expand Down
2 changes: 1 addition & 1 deletion apps/web/e2e/tests/admin/dashboard.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ test.describe('Admin Sidebar Navigation', () => {
})

test('logo links to feedback page', async ({ page }) => {
const logoLink = page.getByRole('link', { name: 'Quackback' }).first()
const logoLink = page.getByRole('link', { name: 'RitualChain' }).first()
await expect(logoLink).toBeVisible({ timeout: 10000 })
await logoLink.click()
await page.waitForLoadState('networkidle')
Expand Down
2 changes: 1 addition & 1 deletion apps/web/e2e/tests/admin/settings-mcp.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ test.describe('Admin MCP Settings', () => {
await expect(referenceLink).toBeVisible({ timeout: 10000 })

const href = await referenceLink.getAttribute('href')
expect(href).toContain('quackback.io/docs/mcp')
expect(href).toContain('ritual.net/docs/mcp')
})

test('Claude Code API Key variant shows Authorization Bearer config', async ({ page }) => {
Expand Down
2 changes: 1 addition & 1 deletion apps/web/e2e/tests/auth/unified-login.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ test('(3) private portal gate: sign-in in the gate lands on /admin', async ({ pa
// router.invalidate() ← re-runs the _portal loader with the now-set admin cookie
// → access granted → router.navigate({ to: callbackUrl='/admin' })
await page.evaluate(() => {
const ch = new BroadcastChannel('quackback-auth')
const ch = new BroadcastChannel('ritualchain-auth')
ch.postMessage({ type: 'auth-success', timestamp: Date.now() })
ch.close()
})
Expand Down
8 changes: 4 additions & 4 deletions apps/web/e2e/utils/access-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,12 @@ export function flushMagicLinkRateLimit(): void {
// calls avoid a shell pipeline (no shell-interpolation risk).
const scan = execFileSync(
'docker',
['exec', 'quackback-dragonfly', 'redis-cli', '--scan', '--pattern', 'signin:magiclink:*'],
['exec', 'ritualchain-dragonfly', 'redis-cli', '--scan', '--pattern', 'signin:magiclink:*'],
{ encoding: 'utf-8' }
)
const keys = scan.split('\n').map((k) => k.trim()).filter(Boolean)
for (const key of keys) {
execFileSync('docker', ['exec', 'quackback-dragonfly', 'redis-cli', 'del', key], {
execFileSync('docker', ['exec', 'ritualchain-dragonfly', 'redis-cli', 'del', key], {
stdio: 'pipe',
})
}
Expand All @@ -111,7 +111,7 @@ export interface SeedIdpConfig {
*/
function invalidateAuthCaches(): void {
for (const key of ['settings:tenant', 'platform-cred:configured-types']) {
execFileSync('docker', ['exec', 'quackback-dragonfly', 'redis-cli', 'del', key], {
execFileSync('docker', ['exec', 'ritualchain-dragonfly', 'redis-cli', 'del', key], {
stdio: 'pipe',
})
}
Expand Down Expand Up @@ -145,7 +145,7 @@ export function setPortalVisibility(visibility: 'private' | 'public'): void {
runScript('../scripts/set-portal-visibility.ts', [visibility])
// The portal-access decision is cached under 'settings:tenant'. Drop it so
// the dev server evaluates the new visibility on the next request.
execFileSync('docker', ['exec', 'quackback-dragonfly', 'redis-cli', 'del', 'settings:tenant'], {
execFileSync('docker', ['exec', 'ritualchain-dragonfly', 'redis-cli', 'del', 'settings:tenant'], {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

E2E Redis container name mismatch

Medium Severity

E2e helpers run docker exec against ritualchain-dragonfly, but local docker-compose.yml still names the Dragonfly service quackback-dragonfly. Magic-link rate-limit flushing and tenant-settings cache invalidation fail silently or error during e2e and local dev.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit c2d80a2. Configure here.

stdio: 'pipe',
})
}
Expand Down
10 changes: 5 additions & 5 deletions apps/web/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "@quackback/web",
"name": "@ritualchain/web",
"version": "0.13.1",
"private": true,
"license": "AGPL-3.0",
Expand Down Expand Up @@ -46,10 +46,10 @@
"@hookform/resolvers": "^5.2.2",
"@modelcontextprotocol/sdk": "^1.29.0",
"@opentelemetry/api": "^1.9.1",
"@quackback/db": "workspace:*",
"@quackback/email": "workspace:*",
"@quackback/ids": "workspace:*",
"@quackback/logger": "workspace:*",
"@ritualchain/db": "workspace:*",
"@ritualchain/email": "workspace:*",
"@ritualchain/ids": "workspace:*",
"@ritualchain/logger": "workspace:*",
"@radix-ui/react-alert-dialog": "^1.1.15",
"@radix-ui/react-avatar": "^1.1.11",
"@radix-ui/react-checkbox": "^1.3.3",
Expand Down
2 changes: 1 addition & 1 deletion apps/web/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { defineConfig, devices } from '@playwright/test'

/**
* Playwright configuration for Quackback E2E tests
* Playwright configuration for RitualChain E2E tests
* @see https://playwright.dev/docs/test-configuration
*/
export default defineConfig({
Expand Down
Loading