Updates
This commit is contained in:
@@ -38,13 +38,13 @@ steps:
|
||||
depends_on:
|
||||
- lint
|
||||
|
||||
# build:
|
||||
# image: node:22-bookworm-slim
|
||||
# commands:
|
||||
# - corepack enable && corepack prepare pnpm@latest --activate
|
||||
# - pnpm run build
|
||||
# depends_on:
|
||||
# - test
|
||||
build:
|
||||
image: node:22-bookworm-slim
|
||||
commands:
|
||||
- corepack enable && corepack prepare pnpm@latest --activate
|
||||
- pnpm run build
|
||||
depends_on:
|
||||
- test
|
||||
|
||||
# build-full:
|
||||
# image: node:22-bookworm-slim
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Deploy: build image, push to registry, trigger Portainer stack redeploy.
|
||||
# Runs on push/tag/manual to main only, after ci workflow succeeds.
|
||||
# Deploy: build qr-api and qr-web (multi-arch amd64 + arm64), push to registry, trigger Portainer stack redeploy.
|
||||
# Runs on push/tag/manual to main only, after CI workflow succeeds.
|
||||
when:
|
||||
- branch: main
|
||||
event: [push, tag, manual]
|
||||
@@ -10,47 +10,15 @@ depends_on:
|
||||
- ci
|
||||
|
||||
steps:
|
||||
- name: Docker image build
|
||||
- name: Docker image build (qr-api + qr-web, multi-arch)
|
||||
image: docker:latest
|
||||
environment:
|
||||
REGISTRY_REPO: git.mifi.dev/mifi-holdings/shorty
|
||||
DOCKER_API_VERSION: '1.43'
|
||||
DOCKER_BUILDKIT: '1'
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
commands:
|
||||
- set -e
|
||||
- echo "=== Building Docker image (BuildKit) ==="
|
||||
- 'echo "Commit SHA: ${CI_COMMIT_SHA:0:8}"'
|
||||
- 'echo "Registry repo: $REGISTRY_REPO"'
|
||||
- |
|
||||
build() {
|
||||
docker build \
|
||||
--progress=plain \
|
||||
--tag $REGISTRY_REPO:${CI_COMMIT_SHA} \
|
||||
--tag $REGISTRY_REPO:latest \
|
||||
--label "git.commit=${CI_COMMIT_SHA}" \
|
||||
--label "git.branch=${CI_COMMIT_BRANCH}" \
|
||||
.
|
||||
}
|
||||
for attempt in 1 2 3; do
|
||||
echo "Build attempt $attempt/3"
|
||||
if build; then
|
||||
echo "✓ Docker image built successfully"
|
||||
exit 0
|
||||
fi
|
||||
echo "Build attempt $attempt failed, retrying in 30s..."
|
||||
sleep 30
|
||||
done
|
||||
echo "All build attempts failed"
|
||||
exit 1
|
||||
|
||||
- name: Push to registry
|
||||
image: docker:latest
|
||||
environment:
|
||||
DOCKER_API_VERSION: '1.43'
|
||||
DOCKER_API_VERSION: "1.43"
|
||||
DOCKER_BUILDKIT: "1"
|
||||
BUILDKIT_PROGRESS: "plain"
|
||||
REGISTRY_URL: git.mifi.dev
|
||||
REGISTRY_REPO: git.mifi.dev/mifi-holdings/shorty
|
||||
REGISTRY_REPO_API: git.mifi.dev/mifi-holdings/shorty-qr-api
|
||||
REGISTRY_REPO_WEB: git.mifi.dev/mifi-holdings/shorty-qr-web
|
||||
REGISTRY_USERNAME:
|
||||
from_secret: gitea_registry_username
|
||||
REGISTRY_PASSWORD:
|
||||
@@ -59,18 +27,30 @@ steps:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
commands:
|
||||
- set -e
|
||||
- echo "=== Pushing to registry ==="
|
||||
- 'echo "Registry: $REGISTRY_URL"'
|
||||
- 'echo "Repository: $REGISTRY_REPO"'
|
||||
- echo "=== Multi-arch Docker build (amd64 + arm64) ==="
|
||||
- 'echo "Commit SHA: ${CI_COMMIT_SHA:0:8}"'
|
||||
- |
|
||||
echo "$REGISTRY_PASSWORD" | docker login "$REGISTRY_URL" \
|
||||
-u "$REGISTRY_USERNAME" \
|
||||
--password-stdin
|
||||
- docker push $REGISTRY_REPO:${CI_COMMIT_SHA}
|
||||
- docker push $REGISTRY_REPO:latest
|
||||
- echo "✓ Images pushed successfully"
|
||||
depends_on:
|
||||
- Docker image build
|
||||
apk add --no-cache git
|
||||
docker buildx version || true
|
||||
docker buildx create --name shorty-builder --use --driver docker-container 2>/dev/null || docker buildx use shorty-builder
|
||||
echo "$REGISTRY_PASSWORD" | docker login "$REGISTRY_URL" -u "$REGISTRY_USERNAME" --password-stdin
|
||||
- |
|
||||
build_push() {
|
||||
local ctx=$1
|
||||
local repo=$2
|
||||
docker buildx build \
|
||||
--platform linux/amd64,linux/arm64 \
|
||||
--progress=plain \
|
||||
--tag $repo:${CI_COMMIT_SHA} \
|
||||
--tag $repo:latest \
|
||||
--label "git.commit=${CI_COMMIT_SHA}" \
|
||||
--label "git.branch=${CI_COMMIT_BRANCH}" \
|
||||
--push \
|
||||
"$ctx"
|
||||
}
|
||||
build_push ./qr-api $REGISTRY_REPO_API
|
||||
build_push ./qr-web $REGISTRY_REPO_WEB
|
||||
echo "✓ Images built and pushed (multi-arch)"
|
||||
|
||||
- name: Trigger Portainer stack redeploy
|
||||
image: curlimages/curl:latest
|
||||
@@ -90,4 +70,4 @@ steps:
|
||||
fi
|
||||
echo "✓ Portainer redeploy triggered (HTTP $code)"
|
||||
depends_on:
|
||||
- Push to registry
|
||||
- Docker image build (qr-api + qr-web, multi-arch)
|
||||
|
||||
90
AGENTS.md
Normal file
90
AGENTS.md
Normal file
@@ -0,0 +1,90 @@
|
||||
# Shorty — Agent-oriented project guide
|
||||
|
||||
This file describes the repository layout, conventions, and workflows so LLM agents and humans can work in it accurately and efficiently.
|
||||
|
||||
## What this repo is
|
||||
|
||||
- **Shorty** is a self-hosted stack: **Kutt** (URL shortener) + **QR Designer** (qr-api + qr-web).
|
||||
- **Kutt**: short links at `mifi.me`, admin at `link.mifi.me` (Postgres + Redis).
|
||||
- **QR Designer**: Next.js app at `qr.mifi.dev` (BasicAuth); backend **qr-api** (Express, SQLite, uploads, shorten proxy to Kutt). qr-api is internal-only (backend network).
|
||||
|
||||
## Repo layout (monorepo, pnpm workspace)
|
||||
|
||||
```
|
||||
shorty/
|
||||
├── package.json # Root: scripts lint, format, format:check, test, build (all delegate to workspaces)
|
||||
├── pnpm-workspace.yaml # packages: qr-api, qr-web
|
||||
├── docker-compose.yml # Full stack with build (Kutt + qr-api + qr-web from Dockerfiles)
|
||||
├── docker-compose.portainer.yml # Same stack using registry images; for Portainer + webhook redeploy
|
||||
├── .woodpecker/
|
||||
│ ├── ci.yml # CI: install → format → lint → test → build
|
||||
│ └── deploy.yml # Deploy: buildx qr-api + qr-web (multi-arch), push, Portainer webhook
|
||||
├── qr-api/ # Express API (TS), SQLite, multer uploads, Kutt proxy
|
||||
│ ├── Dockerfile
|
||||
│ ├── .dockerignore
|
||||
│ ├── src/
|
||||
│ └── package.json
|
||||
└── qr-web/ # Next.js 15 (App Router), Mantine, qr-code-styling
|
||||
├── Dockerfile
|
||||
├── .dockerignore
|
||||
├── next.config.ts # output: 'standalone'
|
||||
├── src/
|
||||
└── package.json
|
||||
```
|
||||
|
||||
- **No root Dockerfile.** Images are built from `qr-api/` and `qr-web/` only.
|
||||
- **Lockfile:** `pnpm-lock.yaml` is committed; CI uses `pnpm install --frozen-lockfile`.
|
||||
|
||||
## Key scripts (from repo root)
|
||||
|
||||
| Command | Effect |
|
||||
|-------------------|--------|
|
||||
| `pnpm install` | Install deps for all workspaces |
|
||||
| `pnpm run lint` | ESLint in qr-api and qr-web |
|
||||
| `pnpm run format:check` | Prettier check (no write) |
|
||||
| `pnpm run format` | Prettier write |
|
||||
| `pnpm run test` | Vitest in qr-api and qr-web |
|
||||
| `pnpm run build` | Build qr-api (tsc) and qr-web (next build) |
|
||||
|
||||
Per-package: `pnpm --filter qr-api dev`, `pnpm --filter qr-web dev` (dev servers).
|
||||
|
||||
## Environment and config
|
||||
|
||||
- **Root:** `.env.example` documents vars; copy to `.env` for Docker Compose. `.env` is gitignored.
|
||||
- **Devcontainer:** `.devcontainer/devcontainer.json` sets `DB_PATH`, `UPLOADS_PATH`, `KUTT_API_KEY`, `QR_API_URL` for in-container dev; no `.env` required for qr-api/qr-web dev.
|
||||
- **Compose:** Kutt needs `DB_PASSWORD`, `JWT_SECRET`; qr-api optionally `KUTT_API_KEY`. Portainer stack can set `REGISTRY`, `IMAGE_TAG` for registry-based compose.
|
||||
|
||||
## CI/CD (Woodpecker)
|
||||
|
||||
- **CI** (runs on PR, push to main, tag, manual): Node 22, pnpm, then `format:check` → `lint` → `test` → `build`. No Docker in CI.
|
||||
- **Deploy** (runs on main push/tag/manual after CI): Uses `docker buildx` to build **two** images from `./qr-api` and `./qr-web` with `--platform linux/amd64,linux/arm64`, tags `:latest` and `:${CI_COMMIT_SHA}`, pushes to `git.mifi.dev/mifi-holdings/shorty-qr-api` and `shorty-qr-web`, then POSTs `portainer_webhook_url` to trigger Portainer stack redeploy.
|
||||
- **Secrets:** `gitea_registry_username`, `gitea_package_token`, `portainer_webhook_url`.
|
||||
|
||||
## Portainer (production)
|
||||
|
||||
- **Registry-based stack:** Use `docker-compose.portainer.yml`. Images: `${REGISTRY}/mifi-holdings/shorty-qr-api:${IMAGE_TAG}`, same for `shorty-qr-web`. Add stack webhook in Portainer and set that URL as `portainer_webhook_url` in Woodpecker.
|
||||
- **Build-from-source:** Use `docker-compose.yml`; no registry, no webhook.
|
||||
|
||||
## Code style and tooling
|
||||
|
||||
- **TypeScript** only (qr-api and qr-web).
|
||||
- **Prettier:** 4 spaces, single quotes, trailing comma all, semicolons (see `.prettierrc`). Check with `pnpm run format:check`.
|
||||
- **ESLint:** Root `.eslintrc.cjs` for qr-api; qr-web has its own `.eslintrc.cjs` (Next + Prettier). No TSLint.
|
||||
- **Ignores:** `.gitignore` (e.g. node_modules, .pnpm-store, .next, dist, .env, *.tsbuildinfo); `.prettierignore` and ESLint `ignorePatterns` aligned (coverage, build dirs, .pnpm-store). Each app has `.dockerignore` to keep build context small.
|
||||
|
||||
## Where to change what
|
||||
|
||||
- **API routes (qr-api):** `qr-api/src/routes/`, `qr-api/src/index.ts`.
|
||||
- **Web app (qr-web):** `qr-web/src/app/` (App Router), `qr-web/src/components/`, `qr-web/src/contexts/`.
|
||||
- **Shared types:** Defined in each package; no shared package.
|
||||
- **Compose:** Kutt + qr services in `docker-compose.yml`; registry-only variant in `docker-compose.portainer.yml`.
|
||||
- **Pipelines:** `.woodpecker/ci.yml`, `.woodpecker/deploy.yml`. Image names and registry are in `deploy.yml` env.
|
||||
|
||||
## Testing and building locally
|
||||
|
||||
- **Unit tests:** `pnpm run test` (Vitest in both packages).
|
||||
- **Dev:** `pnpm --filter qr-api dev` and `pnpm --filter qr-web dev` (ports 8080 and 3000); devcontainer forwards them.
|
||||
- **Full stack (Docker):** `docker compose up -d` (uses `docker-compose.yml`; needs `.env` with `DB_PASSWORD`, `JWT_SECRET`).
|
||||
- **Multi-arch build (local):** Use `docker buildx build --platform linux/amd64,linux/arm64 -t <repo>:<tag> --push ./qr-api` (and same for `./qr-web`) after logging into the registry.
|
||||
|
||||
This layout and these scripts are the source of truth for automation and agent-driven edits.
|
||||
42
README.md
42
README.md
@@ -27,13 +27,21 @@ Designed for Docker/Portainer with Traefik. Uses **pnpm** everywhere; no Tailwin
|
||||
|
||||
## Deploy (Portainer)
|
||||
|
||||
1. In Portainer: **Stacks → Add stack**.
|
||||
2. Use the repo root `docker-compose.yml` (clone repo or paste content).
|
||||
3. Set required env vars (at least):
|
||||
- `DB_PASSWORD` — Postgres password for Kutt
|
||||
- `JWT_SECRET` — Kutt JWT secret (generate a random string)
|
||||
- `KUTT_API_KEY` — Kutt API key for qr-api (after creating it in Kutt UI)
|
||||
4. Deploy. No ports are exposed; Traefik handles ingress.
|
||||
**Option A — Registry + webhook (recommended for CI/CD)**
|
||||
Use prebuilt images and redeploy on push via webhook:
|
||||
|
||||
1. In Portainer: **Stacks → Add stack**. Use **docker-compose.portainer.yml** (paste or pull from repo).
|
||||
2. Set env vars:
|
||||
- **Required:** `DB_PASSWORD`, `JWT_SECRET`
|
||||
- **Optional:** `REGISTRY` (default `git.mifi.dev`), `IMAGE_TAG` (default `latest`), `KUTT_API_KEY`
|
||||
3. Deploy. Then in the stack: **Webhooks** → add webhook. Copy the URL and add it as secret `portainer_webhook_url` in Woodpecker (repo secrets). On each push to `main`, the pipeline builds multi-arch images, pushes to the registry, and triggers this webhook to redeploy the stack.
|
||||
|
||||
**Option B — Build from source**
|
||||
For one-off or local deploys without CI:
|
||||
|
||||
1. In Portainer: **Stacks → Add stack**. Use **docker-compose.yml** (builds qr-api and qr-web from Dockerfiles).
|
||||
2. Set required env vars: `DB_PASSWORD`, `JWT_SECRET`, and optionally `KUTT_API_KEY`.
|
||||
3. Deploy. No ports are exposed; Traefik handles ingress.
|
||||
|
||||
## Env vars and .env.example
|
||||
|
||||
@@ -71,10 +79,12 @@ Ports 3000 and 8080 are forwarded by the devcontainer.
|
||||
|
||||
## Repo structure
|
||||
|
||||
- `docker-compose.yml` — Root compose for Portainer (Kutt + qr-api + qr-web, Traefik labels).
|
||||
- `docker-compose.yml` — Compose that builds qr-api and qr-web from source (local or one-off Portainer).
|
||||
- `docker-compose.portainer.yml` — Compose that uses registry images; for Portainer + CI/CD webhook redeploys.
|
||||
- `qr-api/` — Node/TS Express API: SQLite projects, uploads, shorten proxy to Kutt. Not exposed via Traefik.
|
||||
- `qr-web/` — Next.js (App Router) + Mantine QR designer; proxies all API calls to qr-api server-side.
|
||||
- `.woodpecker.yml` — CI: lint-and-test on PR/push to main; manual deploy with `depends_on` lint-and-test.
|
||||
- `.woodpecker/ci.yml` — CI: install, format check, lint, test, build on PR/push/tag.
|
||||
- `.woodpecker/deploy.yml` — Deploy: build qr-api and qr-web (multi-arch amd64/arm64), push to registry, trigger Portainer webhook. Runs on push/tag to `main` after CI.
|
||||
- `.devcontainer/` — Devcontainer for local dev.
|
||||
|
||||
## Security
|
||||
@@ -87,18 +97,20 @@ Ports 3000 and 8080 are forwarded by the devcontainer.
|
||||
|
||||
The QR designer uses **qr-code-styling** for dots, corners, colors, and error correction. The optional **qr-border-plugin** (from [lefe.dev marketplace](https://lefe.dev/marketplace/qr-border-plugin)) adds border styling but depends on `@lefe-dev/lefe-verify-license`, which may involve licensing/watermark behavior. This stack uses qr-code-styling only by default; you can add qr-border-plugin from npm or GitHub if desired and document any license terms.
|
||||
|
||||
## Switching to prebuilt images (CI/CD)
|
||||
## CI/CD (Woodpecker)
|
||||
|
||||
In `.woodpecker.yml`, the deploy pipeline has placeholder steps. To use prebuilt images:
|
||||
- **CI** (`.woodpecker/ci.yml`): on every PR/push to `main`/tag — `pnpm install --frozen-lockfile`, format check, lint, test, build. Requires `pnpm-lock.yaml` committed.
|
||||
- **Deploy** (`.woodpecker/deploy.yml`): on push/tag to `main` after CI — builds `shorty-qr-api` and `shorty-qr-web` as multi-arch (linux/amd64, linux/arm64), pushes to `git.mifi.dev/mifi-holdings/shorty-qr-api` and `shorty-qr-web`, then POSTs the Portainer webhook to redeploy the stack.
|
||||
|
||||
1. Build `qr-api` and `qr-web` in CI (e.g. `docker build -t $REGISTRY/shorty/qr-api:$CI_COMMIT_SHA ./qr-api`).
|
||||
2. Push to your registry; set `REGISTRY` and `IMAGE_PREFIX` (or equivalent) as secrets.
|
||||
3. In `docker-compose.yml`, replace `build: context: ./qr-api` with `image: $REGISTRY/shorty/qr-api:$TAG` (use env or a compose override for TAG).
|
||||
**Secrets** (repo or org): `gitea_registry_username`, `gitea_package_token`, `portainer_webhook_url`.
|
||||
|
||||
**Local build/push test (before committing):**
|
||||
From repo root: build with buildx and push to your registry, or run `docker compose -f docker-compose.yml build` to verify builds.
|
||||
|
||||
## Code style and tooling
|
||||
|
||||
- **TypeScript** everywhere.
|
||||
- **Prettier:** tabWidth 4, spaces (no tabs), singleQuote, trailingComma all, semi.
|
||||
- **ESLint** for TS/React/Next in qr-web; shared root config for qr-api.
|
||||
- **pnpm** only; `pnpm-lock.yaml` is the single lockfile (no package-lock.json or yarn.lock).
|
||||
- **pnpm** only; `pnpm-lock.yaml` is committed and is the single lockfile (no package-lock.json or yarn.lock).
|
||||
- **Tests:** Vitest (qr-api and qr-web).
|
||||
|
||||
112
docker-compose.portainer.yml
Normal file
112
docker-compose.portainer.yml
Normal file
@@ -0,0 +1,112 @@
|
||||
# Portainer stack: registry-based images (no build). Use with CI/CD webhook redeploy.
|
||||
# Set in Portainer stack env (or .env): REGISTRY, IMAGE_TAG (defaults below).
|
||||
# Images: ${REGISTRY}/mifi-holdings/shorty-qr-api:${IMAGE_TAG}, shorty-qr-web:${IMAGE_TAG}
|
||||
|
||||
services:
|
||||
kutt_db:
|
||||
image: postgres:16-alpine
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
volumes:
|
||||
- /mnt/config/docker/kutt/postgres:/var/lib/postgresql/data
|
||||
environment:
|
||||
POSTGRES_USER: ${DB_USER:-kutt}
|
||||
POSTGRES_PASSWORD: ${DB_PASSWORD:?Set DB_PASSWORD}
|
||||
POSTGRES_DB: ${DB_NAME:-kutt}
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-kutt} -d ${DB_NAME:-kutt}"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
kutt_redis:
|
||||
image: redis:7-alpine
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
volumes:
|
||||
- /mnt/config/docker/kutt/redis:/data
|
||||
command: redis-server --appendonly yes
|
||||
|
||||
kutt:
|
||||
image: kutt/kutt:latest
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- marina-net
|
||||
- backend
|
||||
depends_on:
|
||||
kutt_db:
|
||||
condition: service_healthy
|
||||
kutt_redis:
|
||||
condition: service_started
|
||||
environment:
|
||||
DB_CLIENT: pg
|
||||
DB_HOST: kutt_db
|
||||
DB_PORT: "5432"
|
||||
DB_USER: ${DB_USER:-kutt}
|
||||
DB_PASSWORD: ${DB_PASSWORD:?Set DB_PASSWORD}
|
||||
DB_NAME: ${DB_NAME:-kutt}
|
||||
REDIS_ENABLED: "true"
|
||||
REDIS_HOST: kutt_redis
|
||||
REDIS_PORT: "6379"
|
||||
DEFAULT_DOMAIN: mifi.me
|
||||
NODE_ENV: production
|
||||
JWT_SECRET: ${JWT_SECRET:?Set JWT_SECRET}
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "docker.network=marina-net"
|
||||
- "traefik.http.routers.kutt-mifi.rule=Host(`mifi.me`)"
|
||||
- "traefik.http.routers.kutt-mifi.entrypoints=websecure"
|
||||
- "traefik.http.routers.kutt-mifi.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.kutt-mifi.service=kutt-short"
|
||||
- "traefik.http.services.kutt-short.loadbalancer.server.port=3000"
|
||||
- "traefik.http.routers.kutt-link.rule=Host(`link.mifi.me`)"
|
||||
- "traefik.http.routers.kutt-link.entrypoints=websecure"
|
||||
- "traefik.http.routers.kutt-link.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.kutt-link.service=kutt"
|
||||
- "traefik.http.services.kutt.loadbalancer.server.port=3000"
|
||||
|
||||
qr_api:
|
||||
image: ${REGISTRY:-git.mifi.dev}/mifi-holdings/shorty-qr-api:${IMAGE_TAG:-latest}
|
||||
container_name: qr_api
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
volumes:
|
||||
- /mnt/config/docker/qr/db:/data
|
||||
- /mnt/config/docker/qr/uploads:/uploads
|
||||
environment:
|
||||
PORT: "8080"
|
||||
DB_PATH: /data/db.sqlite
|
||||
UPLOADS_PATH: /uploads
|
||||
KUTT_API_KEY: ${KUTT_API_KEY:-}
|
||||
KUTT_BASE_URL: http://kutt:3000
|
||||
SHORT_DOMAIN: https://mifi.me
|
||||
|
||||
qr_web:
|
||||
image: ${REGISTRY:-git.mifi.dev}/mifi-holdings/shorty-qr-web:${IMAGE_TAG:-latest}
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- marina-net
|
||||
- backend
|
||||
depends_on:
|
||||
- qr_api
|
||||
environment:
|
||||
QR_API_URL: http://qr_api:8080
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "docker.network=marina-net"
|
||||
- "traefik.http.routers.qr-web.rule=Host(`qr.mifi.dev`)"
|
||||
- "traefik.http.routers.qr-web.entrypoints=websecure"
|
||||
- "traefik.http.routers.qr-web.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.qr-web.service=qr-web"
|
||||
- "traefik.http.routers.qr-web.middlewares=qr-web-basicauth"
|
||||
- "traefik.http.middlewares.qr-web-basicauth.basicauth.users=mifi:$$2y$$05$$TS20fkfrmJ3MLc.cgfM6OcuowOstcy/2DTOq0YfirUDU3b0vtNz."
|
||||
- "traefik.http.services.qr-web.loadbalancer.server.port=3000"
|
||||
|
||||
networks:
|
||||
marina-net:
|
||||
external: true
|
||||
backend:
|
||||
driver: bridge
|
||||
@@ -7,7 +7,8 @@
|
||||
"lint": "pnpm -r run lint",
|
||||
"format": "prettier --write .",
|
||||
"format:check": "prettier --check .",
|
||||
"test": "pnpm -r run test"
|
||||
"test": "pnpm -r run test",
|
||||
"build": "pnpm -r run build"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "^3.4.2"
|
||||
|
||||
Reference in New Issue
Block a user