Skip to content

Comments

feat: 🎸 sandbox docker container#790

Open
SirTenzin wants to merge 1 commit intodevfrom
feat/throwaway-docker-containers
Open

feat: 🎸 sandbox docker container#790
SirTenzin wants to merge 1 commit intodevfrom
feat/throwaway-docker-containers

Conversation

@SirTenzin
Copy link
Member

@SirTenzin SirTenzin commented Feb 21, 2026

Summary by cubic

Adds a self-contained sandbox Docker stack with mocked auth so the app runs locally without external services. It auto-generates the DB schema, starts API, workers, and Vite, and provides a fake session/org for the UI.

  • New Features

    • Docker sandbox: compose file with Postgres + Valkey sidecars, dev image, schema generation, and entrypoint that starts Vite, workers, and API with hot reload.
    • Mock mode: server-wide mock auth (Hono + Express), /api/mock-session endpoint, and startup bootstrap for a mock org (optional Stripe Connect and Svix if keys are set).
    • Routing: secret/session auth is swapped for mockAuthMiddleware when MOCK_MODE=true; admin routes remain protected only outside mock mode.
    • Frontend: VITE_MOCK_MODE skips sign-in, uses a mock session hook, and bypasses active org handling.
  • Refactors

    • Workers prefer BullMQ (QUEUE_URL) over SQS (SQS_QUEUE_URL) to ensure Redis queues in sandbox.
  • Migration

    • Run: docker compose -f docker-compose.sandbox.yml up --build, then visit http://localhost:3000.
    • Optional: set STRIPE_SANDBOX_SECRET_KEY and SVIX_API_KEY to create real sandbox integrations; otherwise everything runs fully local.

Written for commit 6c84d47. Summary will update on new commits.

Greptile Summary

This PR implements a fully self-contained Docker sandbox environment for Autumn, enabling AI agents and developers to spin up the entire stack locally without requiring external services like Stripe or Svix. The implementation introduces MOCK_MODE functionality that bypasses authentication and uses a pre-initialized mock organization.

Key Changes:

Improvements:

  • Created comprehensive Docker Compose setup with Postgres, Valkey (Redis), and the Autumn stack with hot-reload support
  • Implemented automatic schema migration at container startup using Drizzle-generated SQL
  • Added mock authentication middleware for both Hono and Express routes that injects a cached mock organization context
  • Created /api/mock-session endpoint and corresponding frontend hook to bypass Better Auth entirely in mock mode
  • Made all external integrations (Stripe Connect, Svix) optional with graceful fallbacks
  • Implemented idempotent mock org initialization with proper caching to avoid redundant database queries

Bug fixes:

  • Changed worker queue detection to prioritize QUEUE_URL (BullMQ) over SQS_QUEUE_URL to prevent local environment variables from leaking into Docker sandbox

API changes:

  • Added /api/mock-session endpoint (only available when MOCK_MODE=true)
  • Modified authentication flow for all /api/* and /internal/* routes to use mock middleware when in mock mode

Issues Found:

  • Both mock auth middleware files use c.json() and res.status().json() patterns for error responses instead of throwing InternalError as specified in CLAUDE.md

Confidence Score: 4/5

  • This PR is safe to merge with minor style improvements recommended
  • The implementation is well-architected and follows good patterns (idempotent initialization, optional external services, proper caching). The code is clean and handles edge cases appropriately. Score reduced by 1 point due to error handling not following project guidelines in two middleware files - these use direct JSON responses instead of throwing InternalError as specified in CLAUDE.md
  • Pay attention to server/src/honoMiddlewares/mockAuthMiddleware.ts and server/src/middleware/mockAuthMiddleware.ts - both should use InternalError instead of direct JSON error responses

Important Files Changed

Filename Overview
docker-compose.sandbox.yml Added comprehensive Docker Compose configuration for fully self-contained sandbox environment with Postgres, Valkey (Redis), and hot-reload support
docker/sandbox.dockerfile Created Dockerfile with Bun runtime, dependency installation, and automatic schema generation at build time
docker/sandbox-entrypoint.sh Added entrypoint script that applies schema, starts Vite, workers, and API server in proper sequence
server/src/honoMiddlewares/mockAuthMiddleware.ts Created Hono mock auth middleware that bypasses API key validation and injects mock org context for sandbox mode
server/src/middleware/mockAuthMiddleware.ts Created Express mock auth middleware with same logic as Hono version for legacy routes
server/src/utils/mockMode/initMockOrg.ts Implemented comprehensive mock org initialization with optional Stripe Connect and Svix integration, fully idempotent
server/src/workers.ts Changed queue detection priority to prefer QUEUE_URL (BullMQ) over SQS_QUEUE_URL for sandbox environments
vite/src/lib/mockSession.ts Created mock session hook that fetches fake session from /api/mock-session endpoint with infinite stale time

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Docker Compose Start] --> B[PostgreSQL Container]
    A --> C[Valkey/Redis Container]
    A --> D[Sandbox Container Build]
    
    D --> E[Install Bun Dependencies]
    E --> F[Generate Schema SQL to /tmp/drizzle-gen]
    F --> G[Container Ready]
    
    G --> H[Entrypoint: Apply Schema to Postgres]
    H --> I[Start Vite Dev Server :3000]
    H --> J[Start BullMQ Workers]
    H --> K[Start API Server :8080]
    
    K --> L{MOCK_MODE=true?}
    L -->|Yes| M[Initialize Mock Org in DB]
    M --> N[Create Stripe Connect Account]
    M --> O[Create Svix Apps]
    M --> P[Cache Mock Org Context]
    
    K --> Q[API Requests]
    Q --> R{Route Type?}
    
    R -->|/api/*| S{MOCK_MODE?}
    S -->|Yes| T[mockAuthMiddleware - Inject Mock Org]
    S -->|No| U[secretKeyMiddleware - Validate API Key]
    
    R -->|/internal/*| V{MOCK_MODE?}
    V -->|Yes| W[mockAuthMiddleware - Inject Mock Org]
    V -->|No| X[betterAuthMiddleware - Validate Session]
    
    I --> Y[Frontend Requests]
    Y --> Z{VITE_MOCK_MODE?}
    Z -->|Yes| AA[Fetch /api/mock-session]
    Z -->|No| AB[Better Auth useSession]
    
    AA --> AC[useMockSession Hook]
    AC --> AD[Skip Auth Flows]
Loading

Last reviewed commit: 6c84d47

Context used:

  • Context from dashboard - CLAUDE.md (source)

@vercel
Copy link

vercel bot commented Feb 21, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
autumn-vite Ready Ready Preview, Comment Feb 21, 2026 11:24pm

Request Review

@use-tusk
Copy link

use-tusk bot commented Feb 21, 2026

⚠️ Additional setup required (6c84d47) View output ↗

Tip

New to Tusk? Learn more here.
Follow the setup instructions so Tusk can start generating tests.


View check history

Commit Status Output Created (UTC)
6c84d47 ⚠️ Additional setup required Output Feb 21, 2026 11:24PM

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

18 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +38 to +45
return c.json(
{
message:
"Mock org not initialised yet — server may still be starting up",
code: "mock_org_not_ready",
},
503,
);
Copy link
Contributor

Choose a reason for hiding this comment

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

Should throw InternalError instead of using c.json() pattern per CLAUDE.md error handling guidelines

Suggested change
return c.json(
{
message:
"Mock org not initialised yet — server may still be starting up",
code: "mock_org_not_ready",
},
503,
);
throw new InternalError({
message: "Mock org not initialised yet — server may still be starting up",
code: "mock_org_not_ready",
});

Context Used: Context from dashboard - CLAUDE.md (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: server/src/honoMiddlewares/mockAuthMiddleware.ts
Line: 38-45

Comment:
Should throw `InternalError` instead of using `c.json()` pattern per CLAUDE.md error handling guidelines

```suggestion
		throw new InternalError({
			message: "Mock org not initialised yet — server may still be starting up",
			code: "mock_org_not_ready",
		});
```

**Context Used:** Context from `dashboard` - CLAUDE.md ([source](https://app.greptile.com/review/custom-context?memory=7dd29fca-a6f0-4168-be5b-a3ea3d587c1c))

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +34 to +37
return res.status(503).json({
message: "Mock org not initialised yet — server may still be starting up",
code: "mock_org_not_ready",
});
Copy link
Contributor

Choose a reason for hiding this comment

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

Should throw InternalError instead of using res.status().json() pattern per CLAUDE.md error handling guidelines

Suggested change
return res.status(503).json({
message: "Mock org not initialised yet — server may still be starting up",
code: "mock_org_not_ready",
});
throw new InternalError({
message: "Mock org not initialised yet — server may still be starting up",
code: "mock_org_not_ready",
});

Context Used: Context from dashboard - CLAUDE.md (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: server/src/middleware/mockAuthMiddleware.ts
Line: 34-37

Comment:
Should throw `InternalError` instead of using `res.status().json()` pattern per CLAUDE.md error handling guidelines

```suggestion
		throw new InternalError({
			message: "Mock org not initialised yet — server may still be starting up",
			code: "mock_org_not_ready",
		});
```

**Context Used:** Context from `dashboard` - CLAUDE.md ([source](https://app.greptile.com/review/custom-context?memory=7dd29fca-a6f0-4168-be5b-a3ea3d587c1c))

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6c84d47b17

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +102 to 103
if (process.env.QUEUE_URL) {
console.log(`[Worker ${process.pid}] Using BullMQ queue implementation`);

Choose a reason for hiding this comment

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

P1 Badge Unify queue precedence between worker and producer paths

This change makes workers prefer QUEUE_URL over SQS_QUEUE_URL, but addTaskToQueue still prefers SQS_QUEUE_URL first in server/src/queue/queueUtils.ts (checked initializeQueue, lines 67-73), so when both env vars are set the app will enqueue jobs to SQS while workers consume BullMQ; in that configuration queued jobs are never processed.

Useful? React with 👍 / 👎.


// Prefer cached context; fall back to a fresh DB lookup if the cache
// was not populated yet (e.g. first request before startup hook ran)
let mockData = getMockOrgContext();

Choose a reason for hiding this comment

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

P2 Badge Respect requested app_env when serving cached mock org data

The middleware grabs getMockOrgContext() before reading app_env, but initMockOrg caches only sandbox data (AppEnv.Sandbox), so requests with app_env=live will still receive sandbox feature data while ctx.env is set to live; this mixes environment-specific state and can produce incorrect behavior when testing production-mode flows in mock mode.

Useful? React with 👍 / 👎.

Comment on lines +38 to +42
return c.json(
{
message:
"Mock org not initialised yet — server may still be starting up",
code: "mock_org_not_ready",

Choose a reason for hiding this comment

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

P1 Badge Throw RecaseError for mock auth startup failures

Per /workspace/autumn/AGENTS.md (Error Handling in API Routes), expected Hono route failures should throw RecaseError, but this middleware returns a manual c.json response; that bypasses the shared onError pipeline and creates a non-standard error shape/logging path when the mock org is not ready, which can break centralized client error handling.

Useful? React with 👍 / 👎.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

4 issues found across 18 files

Confidence score: 3/5

  • vite/src/lib/mockSession.ts doesn’t return refetch/error from useQuery, which can crash consumers like UserDetails that call refetch()
  • server/src/middleware/mockAuthMiddleware.ts has uncaught async exceptions that can hang requests and trigger unhandled promise rejections, creating user-visible failures
  • Given the above user-impacting behaviors and a few medium-severity configuration/logic issues, this carries some regression risk
  • Pay close attention to vite/src/lib/mockSession.ts, server/src/middleware/mockAuthMiddleware.ts, docker-compose.sandbox.yml, server/src/honoMiddlewares/mockAuthMiddleware.ts - missing session API pieces, async error handling, duplicate env var override, and sandbox fallback consistency.
Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="server/src/middleware/mockAuthMiddleware.ts">

<violation number="1" location="server/src/middleware/mockAuthMiddleware.ts:16">
P1: Uncaught exceptions in async Express middleware will hang the request and cause unhandled promise rejections.</violation>
</file>

<file name="docker-compose.sandbox.yml">

<violation number="1" location="docker-compose.sandbox.yml:109">
P2: Duplicate `SQS_QUEUE_URL` definition overrides the explicit empty value intended to disable SQS.</violation>
</file>

<file name="server/src/honoMiddlewares/mockAuthMiddleware.ts">

<violation number="1" location="server/src/honoMiddlewares/mockAuthMiddleware.ts:28">
P2: Nondeterministic fallback environment logic. The cache fallback query uses `appEnv` which may return Live features, whereas the cache itself always returns Sandbox features. Use `AppEnv.Sandbox` in the fallback to match the cache's behavior and avoid duplicate header extraction.</violation>
</file>

<file name="vite/src/lib/mockSession.ts">

<violation number="1" location="vite/src/lib/mockSession.ts:22">
P1: `useMockSession` must return the `refetch` and `error` properties from `useQuery` to fully mock better-auth's `useSession` signature, otherwise it will crash components like `UserDetails` that call `refetch()`.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

@@ -0,0 +1,50 @@
import { AppEnv, AuthType } from "@autumn/shared";
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Feb 21, 2026

Choose a reason for hiding this comment

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

P1: Uncaught exceptions in async Express middleware will hang the request and cause unhandled promise rejections.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At server/src/middleware/mockAuthMiddleware.ts, line 16:

<comment>Uncaught exceptions in async Express middleware will hang the request and cause unhandled promise rejections.</comment>

<file context>
@@ -0,0 +1,50 @@
+ * from the DB (populated on startup by initMockOrg) and injects it into
+ * req so all downstream handlers work normally against a real DB / Stripe sandbox.
+ */
+export const mockAuthMiddleware = async (
+	req: any,
+	res: any,
</file context>
Fix with Cubic

* Returns a stable mock user + session so the frontend skips all auth flows.
*/
export const useMockSession = () => {
const { data, isPending } = useQuery({
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Feb 21, 2026

Choose a reason for hiding this comment

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

P1: useMockSession must return the refetch and error properties from useQuery to fully mock better-auth's useSession signature, otherwise it will crash components like UserDetails that call refetch().

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At vite/src/lib/mockSession.ts, line 22:

<comment>`useMockSession` must return the `refetch` and `error` properties from `useQuery` to fully mock better-auth's `useSession` signature, otherwise it will crash components like `UserDetails` that call `refetch()`.</comment>

<file context>
@@ -0,0 +1,30 @@
+ * Returns a stable mock user + session so the frontend skips all auth flows.
+ */
+export const useMockSession = () => {
+	const { data, isPending } = useQuery({
+		queryKey: ["mock-session"],
+		queryFn: fetchMockSession,
</file context>
Fix with Cubic

- AWS_REGION=${AWS_REGION:-us-east-1}
- AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID:-}
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY:-}
- SQS_QUEUE_URL=${SQS_QUEUE_URL:-}
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Feb 21, 2026

Choose a reason for hiding this comment

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

P2: Duplicate SQS_QUEUE_URL definition overrides the explicit empty value intended to disable SQS.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docker-compose.sandbox.yml, line 109:

<comment>Duplicate `SQS_QUEUE_URL` definition overrides the explicit empty value intended to disable SQS.</comment>

<file context>
@@ -0,0 +1,116 @@
+      - AWS_REGION=${AWS_REGION:-us-east-1}
+      - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID:-}
+      - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY:-}
+      - SQS_QUEUE_URL=${SQS_QUEUE_URL:-}
+      - HATCHET_CLIENT_TOKEN=${HATCHET_CLIENT_TOKEN:-}
+      - STRIPE_SANDBOX_SECRET_KEY=${STRIPE_SANDBOX_SECRET_KEY:-}
</file context>
Fix with Cubic

let mockData = getMockOrgContext();

if (!mockData) {
const appEnv = (c.req.header("app_env") as AppEnv) ?? AppEnv.Sandbox;
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Feb 21, 2026

Choose a reason for hiding this comment

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

P2: Nondeterministic fallback environment logic. The cache fallback query uses appEnv which may return Live features, whereas the cache itself always returns Sandbox features. Use AppEnv.Sandbox in the fallback to match the cache's behavior and avoid duplicate header extraction.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At server/src/honoMiddlewares/mockAuthMiddleware.ts, line 28:

<comment>Nondeterministic fallback environment logic. The cache fallback query uses `appEnv` which may return Live features, whereas the cache itself always returns Sandbox features. Use `AppEnv.Sandbox` in the fallback to match the cache's behavior and avoid duplicate header extraction.</comment>

<file context>
@@ -0,0 +1,57 @@
+	let mockData = getMockOrgContext();
+
+	if (!mockData) {
+		const appEnv = (c.req.header("app_env") as AppEnv) ?? AppEnv.Sandbox;
+		mockData = await OrgService.getWithFeatures({
+			db: ctx.db,
</file context>
Fix with Cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant