feat(infra): add tools service with document scanner, image & PDF tools
Implement self-hosted document scanner and media processing tools as an alternative to CamScanner/ilovepdf without third-party uploads. Backend: Rust Axum gateway + worker pool with NATS JetStream queue Frontend: Next.js 16 + shadcn/ui + Tailwind v4 + Framer Motion Pipeline: Canny edge detection -> DLT homography warp -> Sauvola binarization -> Hough deskew -> Tesseract OCR -> searchable PDF Phase 1 (MVP) delivers: - Document scanner with perspective correction and OCR - Image compress/resize/convert tools - PDF merge/split/compress tools - Real-time WebSocket progress updates - Rate limiting, auto-cleanup, Prometheus metrics - Full CI/CD pipeline with Docker multi-stage build Co-Authored-By: Kilo <kilo@kilo.ai>
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
services:
|
||||
tools:
|
||||
container_name: tools
|
||||
image: ghcr.io/asepharyana/asepharyana-hub/tools:sha-xxxxxxx
|
||||
restart: always
|
||||
networks:
|
||||
app-shared-net:
|
||||
aliases:
|
||||
- tools
|
||||
env_file:
|
||||
- ../../.env
|
||||
environment:
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- NATS_URL=nats://nats:4222
|
||||
- STORAGE_PATH=/data/tools
|
||||
- GATEWAY_PORT=3001
|
||||
- TOOLS_WORKER_CONCURRENCY=4
|
||||
- RUST_LOG=info
|
||||
volumes:
|
||||
- tools_data:/data/tools
|
||||
ports:
|
||||
- "3001:3001"
|
||||
depends_on:
|
||||
redis:
|
||||
condition: service_started
|
||||
nats:
|
||||
condition: service_started
|
||||
labels:
|
||||
- 'prometheus.io/scrape=true'
|
||||
- 'prometheus.io/port=3001'
|
||||
- 'prometheus.io/path=/metrics'
|
||||
healthcheck:
|
||||
test: ['CMD-SHELL', 'curl -so /dev/null --connect-timeout 5 http://localhost:3001/health || test $? -eq 22']
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
|
||||
volumes:
|
||||
tools_data:
|
||||
|
||||
networks:
|
||||
app-shared-net:
|
||||
name: app-shared-net
|
||||
external: true
|
||||
@@ -0,0 +1,73 @@
|
||||
# ============================================================
|
||||
# Stage 1: Build Rust Backend
|
||||
# ============================================================
|
||||
FROM rust:1.85-slim-bookworm AS chef
|
||||
RUN cargo install cargo-chef
|
||||
WORKDIR /app
|
||||
|
||||
FROM chef AS planner
|
||||
COPY backend/ .
|
||||
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 backend/ .
|
||||
RUN cargo build --release --bin tools-gateway --bin tools-workers
|
||||
|
||||
# ============================================================
|
||||
# Stage 2: Build Next.js Frontend
|
||||
# ============================================================
|
||||
FROM oven/bun:1.3 AS frontend-builder
|
||||
WORKDIR /app
|
||||
COPY frontend/package.json frontend/bun.lock ./
|
||||
RUN bun install --frozen-lockfile || bun install
|
||||
COPY frontend/ .
|
||||
RUN bun run build
|
||||
|
||||
# ============================================================
|
||||
# Stage 3: Production Runtime
|
||||
# ============================================================
|
||||
FROM debian:bookworm-slim AS runtime
|
||||
|
||||
# Install runtime dependencies
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
tesseract-ocr \
|
||||
tesseract-ocr-eng \
|
||||
tesseract-ocr-ind \
|
||||
ca-certificates \
|
||||
fonts-dejavu-core \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy Rust binaries
|
||||
COPY --from=builder /app/target/release/tools-gateway /app/gateway
|
||||
COPY --from=builder /app/target/release/tools-workers /app/workers
|
||||
|
||||
# Copy Next.js build
|
||||
COPY --from=frontend-builder /app/.next /app/.next
|
||||
COPY --from=frontend-builder /app/public /app/public
|
||||
COPY --from=frontend-builder /app/package.json /app/package.json
|
||||
COPY --from=frontend-builder /app/node_modules /app/node_modules
|
||||
COPY --from=frontend-builder /app/next.config.ts /app/next.config.ts
|
||||
|
||||
# Create temp storage directory
|
||||
RUN mkdir -p /data/tools && chmod 1777 /data/tools
|
||||
|
||||
# Environment
|
||||
ENV TESSDATA_PREFIX=/usr/share/tesseract-ocr/5/tessdata
|
||||
ENV STORAGE_PATH=/data/tools
|
||||
ENV GATEWAY_PORT=3001
|
||||
ENV TOOLS_WORKER_CONCURRENCY=4
|
||||
ENV RUST_LOG=info
|
||||
|
||||
# Expose port
|
||||
EXPOSE 3001
|
||||
|
||||
# Copy entrypoint
|
||||
COPY scripts/entrypoint.sh /app/entrypoint.sh
|
||||
RUN chmod +x /app/entrypoint.sh
|
||||
|
||||
CMD ["/app/entrypoint.sh"]
|
||||
@@ -20,6 +20,16 @@ http:
|
||||
- common-chain@file
|
||||
service: scraper-service
|
||||
|
||||
# ── Tools (Document Scanner & Media Processing) ──
|
||||
tools:
|
||||
rule: 'Host(`tools.asepharyana.my.id`) || Host(`tools.asepharyana.web.id`)'
|
||||
entryPoints:
|
||||
- websecure
|
||||
tls: {}
|
||||
middlewares:
|
||||
- common-chain@file
|
||||
service: tools-service
|
||||
|
||||
# ── Jaeger UI ──
|
||||
jaeger:
|
||||
rule: 'Host(`jaeger.asepharyana.my.id`) || Host(`jaeger.asepharyana.web.id`)'
|
||||
@@ -41,6 +51,11 @@ http:
|
||||
servers:
|
||||
- url: 'http://scraper-api:4091'
|
||||
|
||||
tools-service:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: 'http://tools:3001'
|
||||
|
||||
jaeger-service:
|
||||
loadBalancer:
|
||||
servers:
|
||||
|
||||
Reference in New Issue
Block a user