diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..eeb55c4 --- /dev/null +++ b/.env.example @@ -0,0 +1,11 @@ +# Docker Compose runtime environment +# Copy to .env.prod and fill in values for production deployment + +# Registry hostname (used to pull images) +REGISTRY_HOST=booskie-box.coin-aldebaran.ts.net + +# ClickHouse connection (indexer) +CLICKHOUSE_URL=https://your-clickhouse-host:8443 +CLICKHOUSE_DATABASE=weaver +CLICKHOUSE_USER=default +CLICKHOUSE_PASSWORD=your-password-here diff --git a/.gitignore b/.gitignore index 92f76c1..7f13b9a 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ /alloy .direnv .env +.env.prod .devenv CLAUDE.md AGENTS.md diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 10a5a5f..0000000 --- a/Dockerfile +++ /dev/null @@ -1,36 +0,0 @@ -FROM rust:1 AS chef -RUN cargo install cargo-chef -WORKDIR /app - -FROM chef AS planner -COPY . . -RUN cargo chef prepare --recipe-path recipe.json - - -FROM chef AS builder -COPY --from=planner /app/recipe.json recipe.json -RUN cargo chef cook --release --recipe-path recipe.json -COPY . . - -# Install `dx` -RUN curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash -RUN cargo binstall dioxus-cli --root /.cargo -y --force -ENV PATH="/.cargo/bin:$PATH" - -# Create the final bundle folder. Bundle always executes in release mode with optimizations enabled -RUN cd crates/weaver-server && dx bundle --release - -FROM chef AS runtime - - -COPY --from=builder /app/target/dx/weaver-server/release/web/ /usr/local/app - -# set our port and make sure to listen for all connections -ENV PORT=8080 -ENV IP=0.0.0.0 - -# expose the port 8080 -EXPOSE 8080 - -WORKDIR /usr/local/app -ENTRYPOINT [ "/usr/local/app/weaver-server" ] diff --git a/crates/weaver-app/Dockerfile b/crates/weaver-app/Dockerfile new file mode 100644 index 0000000..dd47f40 --- /dev/null +++ b/crates/weaver-app/Dockerfile @@ -0,0 +1,74 @@ +# Build stage with cargo-chef for dependency caching +FROM rust:1-trixie AS chef +# Pin nightly version for reproducibility +RUN rustup default nightly-2025-12-04 && rustup component add rust-src --toolchain nightly-2025-12-04 +RUN cargo install cargo-chef +WORKDIR /app + +FROM chef AS planner +COPY . . +RUN cargo chef prepare --recipe-path recipe.json + +FROM chef AS builder + +# Install build dependencies +RUN apt-get update && apt-get install -y \ + pkg-config \ + libssl-dev \ + && rm -rf /var/lib/apt/lists/* + +# Install wasm target and tools +RUN rustup target add wasm32-unknown-unknown +RUN cargo install wasm-bindgen-cli + +# Install dioxus-cli +RUN curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash +RUN cargo binstall dioxus-cli --root /usr/local -y --force + +# Cook dependencies first (cached layer) +COPY --from=planner /app/recipe.json recipe.json +RUN cargo chef cook --release --recipe-path recipe.json + +# Copy source code +COPY . . + +# Use production env for build-time constants +RUN cp crates/weaver-app/.env-prod crates/weaver-app/.env + +# Build wasm workers +RUN RUSTFLAGS='--cfg getrandom_backend="wasm_js"' cargo build -p weaver-app --bin editor_worker --bin embed_worker \ + --target wasm32-unknown-unknown --release \ + --no-default-features --features "web" + +# Run wasm-bindgen on workers +RUN wasm-bindgen target/wasm32-unknown-unknown/release/editor_worker.wasm \ + --out-dir crates/weaver-app/public \ + --target no-modules \ + --no-typescript +RUN wasm-bindgen target/wasm32-unknown-unknown/release/embed_worker.wasm \ + --out-dir crates/weaver-app/public \ + --target no-modules \ + --no-typescript + +# Bundle the app +RUN dx bundle --release --debug-symbols false -p weaver-app + +# Runtime stage +FROM debian:bookworm-slim + +RUN apt-get update && apt-get install -y \ + ca-certificates \ + libssl3 \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /app + +# Copy the bundled app +COPY --from=builder /app/target/dx/weaver-app/release/web/ /app/ + +ENV PORT=8080 +ENV IP=0.0.0.0 + +EXPOSE 8080 + +ENTRYPOINT ["/app/weaver-app"] diff --git a/docker-compose.yml b/docker-compose.yml index 26c358b..936c65b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,15 @@ services: + # Docker registry for local image hosting + registry: + image: registry:2 + container_name: weaver-registry + ports: + - "5000:5000" + volumes: + - registry_data:/var/lib/registry + restart: unless-stopped + # Tap - AT Protocol sync utility - # Build from local indigo checkout, or use pre-built image tap: container_name: weaver-tap image: ghcr.io/bluesky-social/indigo/tap:latest @@ -13,8 +22,6 @@ services: TAP_BIND: ":2480" TAP_DISABLE_ACKS: "false" TAP_LOG_LEVEL: info - # Filter to weaver collections only - #TAP_SIGNAL_COLLECTION: sh.weaver.edit.root TAP_SIGNAL_COLLECTION: sh.tangled.actor.profile TAP_COLLECTION_FILTERS: "sh.weaver.*,app.bsky.actor.profile,sh.tangled.*,pub.leaflet.*" healthcheck: @@ -22,40 +29,55 @@ services: interval: 20s timeout: 5s retries: 3 + restart: unless-stopped - # Weaver indexer - consumes from tap or direct firehose + # Weaver indexer - consumes from tap indexer: container_name: weaver-indexer - build: - context: . - dockerfile: crates/weaver-index/Dockerfile - command: ["run"] + image: ${REGISTRY_HOST:-localhost}:5000/weaver-index:latest ports: - "3000:3000" environment: - RUST_LOG: debug,weaver_index=debug,hyper_util::client::legacy::pool=info - # ClickHouse connection (set these for your cloud/homelab instance) + RUST_LOG: info,weaver_index=debug,hyper_util::client::legacy::pool=info CLICKHOUSE_URL: ${CLICKHOUSE_URL} CLICKHOUSE_DATABASE: ${CLICKHOUSE_DATABASE:-weaver} CLICKHOUSE_USER: ${CLICKHOUSE_USER} CLICKHOUSE_PASSWORD: ${CLICKHOUSE_PASSWORD} - # Source mode: "firehose" or "tap" INDEXER_SOURCE: tap - # Tap connection (when INDEXER_SOURCE=tap) TAP_URL: ws://tap:2480/channel TAP_SEND_ACKS: "true" - # Firehose connection (when INDEXER_SOURCE=firehose) FIREHOSE_RELAY_URL: wss://bsky.network - # Collection filters INDEXER_COLLECTIONS: "sh.weaver.*,app.bsky.actor.profile,sh.tangled.*,pub.leaflet.*" depends_on: tap: condition: service_healthy healthcheck: - test: ["CMD", "wget", "-q", "--spider", "http://localhost:2480/xrpc/_health"] + test: ["CMD", "wget", "-q", "--spider", "http://localhost:3000/xrpc/_health"] + interval: 20s + timeout: 5s + retries: 3 + restart: unless-stopped + + # Weaver app - web frontend + weaver-app: + container_name: weaver-app + image: ${REGISTRY_HOST:-localhost}:5000/weaver-app:latest + ports: + - "8080:8080" + environment: + PORT: 8080 + IP: 0.0.0.0 + RUST_LOG: info + depends_on: + indexer: + condition: service_healthy + healthcheck: + test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080/"] interval: 20s timeout: 5s retries: 3 + restart: unless-stopped volumes: + registry_data: tap_data: