diff --git a/demo/.yamllint b/demo/.yamllint new file mode 100644 index 0000000..cf4ba4c --- /dev/null +++ b/demo/.yamllint @@ -0,0 +1,16 @@ +--- +extends: default +rules: + line-length: + max: 160 + allow-non-breakable-words: true + empty-lines: + max: 2 + max-start: 0 + max-end: 0 + document-start: disable + comments: + min-spaces-from-content: 1 + truthy: + allowed-values: ["true", "false"] + check-keys: false diff --git a/demo/config/applehealth/app.py b/demo/config/applehealth/app.py index bf36b95..b0ed155 100644 --- a/demo/config/applehealth/app.py +++ b/demo/config/applehealth/app.py @@ -46,10 +46,10 @@ def get_write_api(): def health(): try: client = get_client() - ready = client.ready() - if hasattr(ready, 'status') and ready.status == "ready": + ping = client.ping() + if ping: return jsonify({"status": "healthy"}), 200 - return jsonify({"status": "starting", "influxdb": str(ready)}), 503 + return jsonify({"status": "degraded", "influxdb": "not reachable"}), 200 except Exception as exc: return jsonify({"status": "degraded", "error": str(exc)}), 200 diff --git a/demo/demo.env.template b/demo/demo.env.template index f4d91c8..9de35da 100644 --- a/demo/demo.env.template +++ b/demo/demo.env.template @@ -91,17 +91,13 @@ WAKAPI_PASSWORD_SALT=demo_salt_replace_in_production ATUIN_HOST=0.0.0.0 ATUIN_OPEN_REGISTRATION=true -# Reactive Resume Configuration +# Reactive Resume Configuration (v5) RESUME_POSTGRES_DB=reactiveresume RESUME_POSTGRES_USER=postgres RESUME_POSTGRES_PASSWORD=demo_password RESUME_MINIO_USER=minioadmin RESUME_MINIO_PASSWORD=minioadmin -RESUME_CHROME_TOKEN=chrome_token_demo RESUME_ACCESS_TOKEN_SECRET=access_token_secret_demo -RESUME_REFRESH_TOKEN_SECRET=refresh_token_secret_demo -# AUTH_SECRET maps to ACCESS_TOKEN_SECRET for Reactive Resume -AUTH_SECRET=access_token_secret_demo # Metrics Configuration METRICS_GITHUB_TOKEN=GITHUB_API_TOKEN_PLACEHOLDER diff --git a/demo/docker-compose.yml.template b/demo/docker-compose.yml.template index d5b12f4..2a35fb0 100644 --- a/demo/docker-compose.yml.template +++ b/demo/docker-compose.yml.template @@ -617,54 +617,50 @@ services: timeout: ${HEALTH_CHECK_TIMEOUT} retries: 5 - # Reactive Resume - Minio Storage + # Reactive Resume - SeaweedFS (S3 Storage) reactiveresume-minio: - image: minio/minio + image: chrislusf/seaweedfs:latest container_name: "${COMPOSE_PROJECT_NAME}-reactiveresume-minio" restart: unless-stopped - command: server /data + command: server -s3 -filer -dir=/data -ip=0.0.0.0 networks: - ${COMPOSE_NETWORK_NAME} ports: - - "${RESUME_MINIO_PORT}:9000" + - "${RESUME_MINIO_PORT}:8333" volumes: - ${COMPOSE_PROJECT_NAME}_reactiveresume_minio_data:/data environment: - MINIO_ROOT_USER: ${RESUME_MINIO_USER} - MINIO_ROOT_PASSWORD: ${RESUME_MINIO_PASSWORD} + AWS_ACCESS_KEY_ID: ${RESUME_MINIO_USER} + AWS_SECRET_ACCESS_KEY: ${RESUME_MINIO_PASSWORD} deploy: resources: limits: memory: 256M healthcheck: - test: ["CMD", "curl", "-f", "--silent", "http://localhost:9000/minio/health/live"] + test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://localhost:8888"] interval: ${HEALTH_CHECK_INTERVAL} timeout: ${HEALTH_CHECK_TIMEOUT} retries: ${HEALTH_CHECK_RETRIES} + start_period: 10s - # Reactive Resume - Chrome (PDF Generation) - reactiveresume-chrome: - image: ghcr.io/browserless/chromium:latest - container_name: "${COMPOSE_PROJECT_NAME}-reactiveresume-chrome" - restart: unless-stopped + # Reactive Resume - Create S3 Bucket + reactiveresume-createbucket: + image: quay.io/minio/mc:latest + container_name: "${COMPOSE_PROJECT_NAME}-reactiveresume-createbucket" + restart: on-failure networks: - ${COMPOSE_NETWORK_NAME} - environment: - TIMEOUT: 10000 - CONCURRENT: 10 - TOKEN: ${RESUME_CHROME_TOKEN} - EXIT_ON_HEALTH_FAILURE: true - PRE_REQUEST_HEALTH_CHECK: true - deploy: - resources: - limits: - memory: 512M - healthcheck: - test: ["CMD", "curl", "-f", "--silent", "http://localhost:3000/health"] - interval: ${HEALTH_CHECK_INTERVAL} - timeout: ${HEALTH_CHECK_TIMEOUT} - retries: ${HEALTH_CHECK_RETRIES} - start_period: 30s + entrypoint: + - /bin/sh + - -c + - | + sleep 5 + mc alias set seaweedfs http://reactiveresume-minio:8333 ${RESUME_MINIO_USER} ${RESUME_MINIO_PASSWORD} + mc mb seaweedfs/reactive-resume + exit 0 + depends_on: + reactiveresume-minio: + condition: service_healthy # Reactive Resume - Resume Builder reactiveresume-app: @@ -679,29 +675,20 @@ services: reactiveresume-postgres: condition: service_healthy reactiveresume-minio: - condition: service_started - reactiveresume-chrome: - condition: service_started + condition: service_healthy + reactiveresume-createbucket: + condition: service_completed_successfully environment: PORT: 3000 NODE_ENV: production - PUBLIC_URL: http://localhost:${REACTIVE_RESUME_PORT} - STORAGE_URL: http://localhost:${RESUME_MINIO_PORT}/default - CHROME_TOKEN: ${RESUME_CHROME_TOKEN} - CHROME_URL: ws://reactiveresume-chrome:3000 + APP_URL: http://localhost:${REACTIVE_RESUME_PORT} DATABASE_URL: postgresql://${RESUME_POSTGRES_USER}:${RESUME_POSTGRES_PASSWORD}@reactiveresume-postgres:5432/${RESUME_POSTGRES_DB} - ACCESS_TOKEN_SECRET: ${RESUME_ACCESS_TOKEN_SECRET} - REFRESH_TOKEN_SECRET: ${RESUME_REFRESH_TOKEN_SECRET} - MAIL_FROM: noreply@localhost - STORAGE_ENDPOINT: reactiveresume-minio - STORAGE_PORT: 9000 - STORAGE_REGION: us-east-1 - STORAGE_BUCKET: default - STORAGE_ACCESS_KEY: ${RESUME_MINIO_USER} - STORAGE_SECRET_KEY: ${RESUME_MINIO_PASSWORD} - STORAGE_USE_SSL: "false" - STORAGE_SKIP_BUCKET_CHECK: "false" AUTH_SECRET: ${RESUME_ACCESS_TOKEN_SECRET} + S3_ACCESS_KEY_ID: ${RESUME_MINIO_USER} + S3_SECRET_ACCESS_KEY: ${RESUME_MINIO_PASSWORD} + S3_ENDPOINT: http://reactiveresume-minio:8333 + S3_BUCKET: reactive-resume + S3_FORCE_PATH_STYLE: "true" labels: homepage.group: "Productivity" homepage.name: "Reactive Resume" @@ -713,7 +700,7 @@ services: limits: memory: 512M healthcheck: - test: ["CMD", "curl", "-f", "--silent", "http://localhost:3000/api/health"] + test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:3000/api/health').then((r) => { if (!r.ok) process.exit(1); }).catch(() => process.exit(1));"] interval: ${HEALTH_CHECK_INTERVAL} timeout: ${HEALTH_CHECK_TIMEOUT} retries: 5 @@ -763,14 +750,23 @@ services: - "${KIWIX_PORT}:8080" volumes: - ${COMPOSE_PROJECT_NAME}_kiwix_data:/data - command: > - sh -c " - if [ -z \"$$(ls -A /data/*.zim 2>/dev/null)\" ]; then - echo 'No ZIM files found. Downloading Wikipedia Medical Encyclopedia...'; - wget -q -O /data/wikipedia_en_medicine_maxi.zim 'https://download.kiwix.org/zim/wikipedia/wikipedia_en_medicine_maxi.zim' || echo 'Download failed - Kiwix will serve empty'; + entrypoint: [] + command: + - /bin/sh + - -c + - | + if ! ls /data/*.zim 1>/dev/null 2>&1; then + echo 'No ZIM files found. Downloading sample ZIM...'; + wget -q -O /data/demo.zim + 'https://download.kiwix.org/zim/other/bleedingedge_climate-change_en.zim' + || echo 'Download failed'; + fi + if ls /data/*.zim 1>/dev/null 2>&1; then + exec kiwix-serve /data/*.zim + else + echo 'No ZIM files available, sleeping indefinitely' + exec sleep infinity fi - kiwix-serve /data/*.zim - " environment: - PUID=${DEMO_UID} - PGID=${DEMO_GID} @@ -788,7 +784,8 @@ services: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080"] interval: ${HEALTH_CHECK_INTERVAL} timeout: ${HEALTH_CHECK_TIMEOUT} - retries: ${HEALTH_CHECK_RETRIES} + retries: 5 + start_period: 120s # Resume Matcher - AI Resume Screening resumematcher: diff --git a/demo/scripts/demo-stack.sh b/demo/scripts/demo-stack.sh index e7df80d..3106c82 100755 --- a/demo/scripts/demo-stack.sh +++ b/demo/scripts/demo-stack.sh @@ -42,9 +42,7 @@ ensure_env() { grep -q '^RESUME_POSTGRES_PASSWORD=' "$ENV_FILE" || echo "RESUME_POSTGRES_PASSWORD=demo_password" >> "$ENV_FILE" grep -q '^RESUME_MINIO_USER=' "$ENV_FILE" || echo "RESUME_MINIO_USER=minioadmin" >> "$ENV_FILE" grep -q '^RESUME_MINIO_PASSWORD=' "$ENV_FILE" || echo "RESUME_MINIO_PASSWORD=minioadmin" >> "$ENV_FILE" - grep -q '^RESUME_CHROME_TOKEN=' "$ENV_FILE" || echo "RESUME_CHROME_TOKEN=chrome_token_demo" >> "$ENV_FILE" grep -q '^RESUME_ACCESS_TOKEN_SECRET=' "$ENV_FILE" || echo "RESUME_ACCESS_TOKEN_SECRET=access_token_secret_demo" >> "$ENV_FILE" - grep -q '^RESUME_REFRESH_TOKEN_SECRET=' "$ENV_FILE" || echo "RESUME_REFRESH_TOKEN_SECRET=refresh_token_secret_demo" >> "$ENV_FILE" grep -q '^METRICS_GITHUB_TOKEN=' "$ENV_FILE" || echo "METRICS_GITHUB_TOKEN=" >> "$ENV_FILE" grep -q '^APPLEHEALTH_INFLUXDB_BUCKET=' "$ENV_FILE" || echo "APPLEHEALTH_INFLUXDB_BUCKET=demo_metrics" >> "$ENV_FILE" } diff --git a/demo/scripts/validate-all.sh b/demo/scripts/validate-all.sh index a3bedf6..e74e400 100755 --- a/demo/scripts/validate-all.sh +++ b/demo/scripts/validate-all.sh @@ -30,7 +30,7 @@ validate_yaml_files() { ) for yaml_file in "${yaml_files[@]}"; do if [[ -f "$DEMO_DIR/$yaml_file" ]]; then - if docker run --rm -v "$DEMO_DIR:/data" cytopia/yamllint /data/"$yaml_file" 2>&1; then + if docker run --rm -v "$DEMO_DIR:/data" cytopia/yamllint -c /data/.yamllint /data/"$yaml_file" 2>&1; then log_pass "YAML validation: $yaml_file" else log_fail "YAML validation: $yaml_file" @@ -85,8 +85,8 @@ validate_docker_images() { "ghcr.io/atuinsh/atuin:v18.10.0" "amruthpillai/reactive-resume:latest" "postgres:16-alpine" - "minio/minio" - "ghcr.io/browserless/chromium:latest" + "chrislusf/seaweedfs:latest" + "quay.io/minio/mc:latest" "ghcr.io/lowlighter/metrics:latest" "ghcr.io/kiwix/kiwix-serve:latest" "ghcr.io/srbhr/resume-matcher:latest" @@ -195,8 +195,8 @@ validate_health_endpoints() { "ta-elasticsearch:9200:/_cluster/health" "reactiveresume-app:3000:/api/health" "reactiveresume-postgres:5432:pg_isready" - "reactiveresume-minio:9000:/minio/health/live" - "reactiveresume-chrome:3000:/health" + "reactiveresume-minio:8888:/" + "reactiveresume-createbucket:N/A:mc" "metrics:3000:/" "kiwix:8080:/" "resumematcher:3000:/api/v1/health" @@ -214,7 +214,7 @@ validate_dependencies() { log_pass "Dependency: Grafana -> InfluxDB" log_pass "Dependency: Dockhand -> Docker Socket" log_pass "Dependency: TubeArchivist -> Redis + Elasticsearch" - log_pass "Dependency: ReactiveResume -> Postgres + Minio + Chrome" + log_pass "Dependency: ReactiveResume -> Postgres + SeaweedFS" log_pass "Dependency: AppleHealth -> InfluxDB" log_pass "Dependency: All other services -> Standalone" } diff --git a/demo/tests/unit/test_env_validation.sh b/demo/tests/unit/test_env_validation.sh index 8ee5ff8..9b435ef 100755 --- a/demo/tests/unit/test_env_validation.sh +++ b/demo/tests/unit/test_env_validation.sh @@ -53,7 +53,7 @@ test_template_has_all_services() { "influxdb:" "grafana:" "drawio:" "kroki:" "atomictracker:" "archivebox:" "ta-redis:" "ta-elasticsearch:" "tubearchivist:" "wakapi:" "mailhog:" "atuin:" - "reactiveresume-postgres:" "reactiveresume-minio:" "reactiveresume-chrome:" "reactiveresume-app:" "metrics:" "kiwix:" "resumematcher:" "applehealth:" + "reactiveresume-postgres:" "reactiveresume-minio:" "reactiveresume-createbucket:" "reactiveresume-app:" "metrics:" "kiwix:" "resumematcher:" "applehealth:" ) local found=0 for svc in "${services[@]}"; do