Scheer Enterprise Translation Tool
Node HTTP server that proxies the DeepL API and serves a single-page UI, plus per-domain glossary management for the four Scheer entities. Runs on Node's built-ins only; no dependencies. Containerized for Dokploy: the domain -> glossary_id map is written to DOMAINS_FILE (default /app/data/domains.json) so it can live on a mounted volume and survive redeploys. See DEPLOY.md. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
94
DEPLOY.md
Normal file
94
DEPLOY.md
Normal file
@@ -0,0 +1,94 @@
|
||||
# Deploying to Dokploy
|
||||
|
||||
The app is a single Node process with no dependencies. Dokploy builds it from
|
||||
the `Dockerfile` in this repo and puts Traefik in front of it.
|
||||
|
||||
## 1. Push the repo to a Git host
|
||||
|
||||
Dokploy pulls from GitHub/GitLab/Gitea (or a raw Git URL over SSH).
|
||||
|
||||
**Before the first push:** `.env` and `.env.testcopy` contain a real DeepL API
|
||||
key. They are untracked from now on via `.gitignore`, but if they were already
|
||||
committed they still exist in history — remove them from tracking and rotate
|
||||
the key rather than relying on the file being gone from the working tree.
|
||||
|
||||
## 2. Create the application in Dokploy
|
||||
|
||||
Project → **Create Service** → **Application**.
|
||||
|
||||
| Field | Value |
|
||||
| ------------- | ------------------------------ |
|
||||
| Source | Git provider + this repo/branch |
|
||||
| Build Type | **Dockerfile** |
|
||||
| Dockerfile | `Dockerfile` |
|
||||
|
||||
## 3. Environment variables
|
||||
|
||||
**Environment** tab:
|
||||
|
||||
```
|
||||
DEEPL_API_KEY=<your DeepL Growth API key>
|
||||
```
|
||||
|
||||
`PORT` and `DOMAINS_FILE` are already set in the Dockerfile — do not override
|
||||
them unless you also change the volume mount path to match.
|
||||
|
||||
The key is server-side only; it is never sent to the browser.
|
||||
|
||||
## 4. Volume (required)
|
||||
|
||||
Without this, every redeploy resets all glossary mappings.
|
||||
|
||||
**Advanced → Volumes → Add** :
|
||||
|
||||
| Field | Value |
|
||||
| ----------- | -------------- |
|
||||
| Type | Volume Mount |
|
||||
| Volume Name | `deepl-data` |
|
||||
| Mount Path | `/app/data` |
|
||||
|
||||
`DOMAINS_FILE=/app/data/domains.json` writes into that volume. The path is a
|
||||
subdirectory of `/app` on purpose — mounting `/app` itself would hide
|
||||
`server.js` and `index.html`.
|
||||
|
||||
## 5. Domain
|
||||
|
||||
**Domains** tab → Add:
|
||||
|
||||
| Field | Value |
|
||||
| ------------- | ------------------------ |
|
||||
| Host | your hostname |
|
||||
| Container Port| `3000` |
|
||||
| HTTPS | on, Let's Encrypt |
|
||||
|
||||
## 6. Deploy
|
||||
|
||||
Hit **Deploy**. Verify with:
|
||||
|
||||
```
|
||||
curl https://<your-host>/health
|
||||
# {"status":"ok","apiKeyConfigured":true}
|
||||
```
|
||||
|
||||
`apiKeyConfigured: false` means `DEEPL_API_KEY` did not reach the container.
|
||||
|
||||
## Seeding existing glossary mappings
|
||||
|
||||
A fresh volume starts empty and the app writes a default `domains.json` with
|
||||
all four domains and no glossaries. The `domains.json` in this repo is **not**
|
||||
copied into the image (it is in `.dockerignore`), so any glossary IDs recorded
|
||||
there are not carried over. Either re-save the glossaries through the UI after
|
||||
the first deploy, or copy the file in once:
|
||||
|
||||
```
|
||||
docker cp domains.json <container>:/app/data/domains.json
|
||||
docker restart <container>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The app has **no authentication**. Anything on the public domain can use your
|
||||
DeepL quota and edit the shared glossaries. Put Traefik basic auth or an
|
||||
IP allowlist in front of it if it is internet-facing.
|
||||
- Docker `HEALTHCHECK` hits `/health` every 30s. It does not call DeepL, so a
|
||||
DeepL outage will not restart the container.
|
||||
Reference in New Issue
Block a user