diff --git a/README.md b/README.md index 0f74419..727ab68 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,24 @@ npm run dev The frontend is available at `http://127.0.0.1:3000`. The backend health endpoint is available at `http://127.0.0.1:8080/health`. +## Running with Docker Compose + +Create the root `.env` file as described in the configuration section, then build and start both services: + +```powershell +docker compose up --build +``` + +Open `http://localhost:3000` in your browser. The API is exposed at `http://localhost:8080`, and SQLite data is kept in the named `card_to_iban_data` volume. + +Stop the services with: + +```powershell +docker compose down +``` + +The database volume is preserved by default. To remove it intentionally, run `docker compose down --volumes`. + ## API Contract ### Convert a card number to an IBAN diff --git a/backend/.dockerignore b/backend/.dockerignore new file mode 100644 index 0000000..c4430df --- /dev/null +++ b/backend/.dockerignore @@ -0,0 +1,7 @@ +.env +*.db +*.sqlite +*.sqlite3 +bin +coverage.out +*.test diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 0000000..06e2505 --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,36 @@ +FROM golang:1.27.1-alpine AS build + +WORKDIR /src + +ARG GOPROXY=https://package-mirror.liara.ir/repository/go/ +ENV GOPROXY=$GOPROXY + +COPY go.mod go.sum ./ +RUN go mod download + +COPY cmd ./cmd +COPY internal ./internal + +RUN CGO_ENABLED=0 GOOS=linux go build \ + -trimpath \ + -ldflags="-s -w" \ + -o /out/api \ + ./cmd/api + +FROM alpine:3.22 + +RUN apk add --no-cache ca-certificates \ + && addgroup -S app \ + && adduser -S -G app app \ + && mkdir /data \ + && chown app:app /data + +WORKDIR /app + +COPY --from=build /out/api ./api + +USER app + +EXPOSE 8080 + +CMD ["./api"] diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..481e91b --- /dev/null +++ b/compose.yaml @@ -0,0 +1,36 @@ +name: card-to-iban + +services: + backend: + build: + context: ./backend + env_file: + - ./.env + environment: + SERVER_ADDR: 0.0.0.0:8080 + DATABASE_PATH: /data/card-to-iban.db + FRONTEND_ORIGIN: ${FRONTEND_ORIGIN:-http://localhost:3000} + ports: + - "8080:8080" + volumes: + - card_to_iban_data:/data + healthcheck: + test: ["CMD", "wget", "--quiet", "--spider", "http://127.0.0.1:8080/health"] + interval: 10s + timeout: 3s + retries: 5 + start_period: 5s + + frontend: + build: + context: ./frontend + environment: + NUXT_PUBLIC_API_BASE_URL: ${NUXT_PUBLIC_API_BASE_URL:-http://localhost:8080} + ports: + - "3000:3000" + depends_on: + backend: + condition: service_healthy + +volumes: + card_to_iban_data: diff --git a/frontend/.dockerignore b/frontend/.dockerignore new file mode 100644 index 0000000..1567fcd --- /dev/null +++ b/frontend/.dockerignore @@ -0,0 +1,7 @@ +.env +.env.* +node_modules +.nuxt +.output +dist +npm-debug.log* diff --git a/frontend/.env.sample b/frontend/.env.sample new file mode 100644 index 0000000..feed355 --- /dev/null +++ b/frontend/.env.sample @@ -0,0 +1 @@ +NUXT_PUBLIC_API_BASE_URL=http://127.0.0.1:8080 diff --git a/frontend/Dockerfile b/frontend/Dockerfile new file mode 100644 index 0000000..633ada8 --- /dev/null +++ b/frontend/Dockerfile @@ -0,0 +1,25 @@ +FROM node:22-alpine AS build + +WORKDIR /app + +COPY package.json package-lock.json ./ +RUN npm ci + +COPY . . +RUN npm run build + +FROM node:22-alpine + +ENV NODE_ENV=production \ + NITRO_HOST=0.0.0.0 \ + NITRO_PORT=3000 + +WORKDIR /app + +COPY --from=build --chown=node:node /app/.output ./.output + +USER node + +EXPOSE 3000 + +CMD ["node", ".output/server/index.mjs"]