From a275197ce46896a338840de63a7ade16df97a753 Mon Sep 17 00:00:00 2001 From: Gerhard Scheikl Date: Fri, 8 May 2026 11:01:08 +0200 Subject: [PATCH] make app production-ready --- .dockerignore | 13 +++++++++++++ app/shopify.server.ts | 2 +- deploy/Caddyfile.snippet | 8 ++++++++ docker-compose.yml | 28 ++++++++++++++++++++++++++++ prisma/schema.prisma | 2 +- shopify.app.toml | 8 ++++++-- 6 files changed, 57 insertions(+), 4 deletions(-) create mode 100644 deploy/Caddyfile.snippet create mode 100644 docker-compose.yml diff --git a/.dockerignore b/.dockerignore index 78e1a23..840bb3a 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,3 +1,16 @@ .cache build node_modules + +# Local-only files that must NOT be baked into the production image. +.env +.env.* +!.env.production.example +prisma/dev.sqlite +prisma/dev.sqlite-journal +.shopify +.git +.github +*.log +extensions/*/dist + diff --git a/app/shopify.server.ts b/app/shopify.server.ts index 691d476..20d8a42 100644 --- a/app/shopify.server.ts +++ b/app/shopify.server.ts @@ -15,7 +15,7 @@ const shopify = shopifyApp({ appUrl: process.env.SHOPIFY_APP_URL || "", authPathPrefix: "/auth", sessionStorage: new PrismaSessionStorage(prisma), - distribution: AppDistribution.AppStore, + distribution: AppDistribution.SingleMerchant, future: { expiringOfflineAccessTokens: true, }, diff --git a/deploy/Caddyfile.snippet b/deploy/Caddyfile.snippet new file mode 100644 index 0000000..6ac9afb --- /dev/null +++ b/deploy/Caddyfile.snippet @@ -0,0 +1,8 @@ +# Append to your existing Caddyfile (or include via `import`). +# DNS A/AAAA record for invoice-app.linumiq.com must point to this server first, +# otherwise Caddy will fail to obtain a Let's Encrypt certificate. + +invoice-app.linumiq.com { + encode zstd gzip + reverse_proxy 127.0.0.1:3000 +} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..cf8765f --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,28 @@ +services: + app: + build: + context: . + dockerfile: Dockerfile + image: linumiq-invoice:latest + container_name: linumiq-invoice + restart: unless-stopped + env_file: + - .env.production + environment: + # SQLite file lives on a named volume so it survives image rebuilds. + DATABASE_URL: "file:/data/prod.sqlite" + NODE_ENV: production + PORT: "3000" + volumes: + - invoice-data:/data + # Bind to loopback only — Caddy on the host terminates TLS and reverse-proxies. + ports: + - "127.0.0.1:3000:3000" + healthcheck: + test: ["CMD", "wget", "-qO-", "http://127.0.0.1:3000/healthz", "||", "exit", "0"] + interval: 30s + timeout: 5s + retries: 3 + +volumes: + invoice-data: diff --git a/prisma/schema.prisma b/prisma/schema.prisma index be85b17..9f7d720 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -10,7 +10,7 @@ generator client { // See https://www.prisma.io/docs/orm/reference/prisma-schema-reference#string for more information datasource db { provider = "sqlite" - url = "file:dev.sqlite" + url = env("DATABASE_URL") } model Session { diff --git a/shopify.app.toml b/shopify.app.toml index 89db265..0dbcaf0 100644 --- a/shopify.app.toml +++ b/shopify.app.toml @@ -1,7 +1,7 @@ # Learn more about configuring your app at https://shopify.dev/docs/apps/tools/cli/configuration client_id = "fbc263e6cc28e8de031878d2a0f17444" -application_url = "https://example.com" +application_url = "https://invoice-app.linumiq.com" embedded = true name = "linumiq-invoice" @@ -32,7 +32,11 @@ api_version = "2026-07" topics = [ "orders/updated" ] [auth] -redirect_urls = [ "https://example.com/api/auth" ] +redirect_urls = [ + "https://invoice-app.linumiq.com/auth/callback", + "https://invoice-app.linumiq.com/auth/shopify/callback", + "https://invoice-app.linumiq.com/api/auth/callback", +] [build] include_config_on_deploy = true