diff --git a/.gitignore b/.gitignore
index bb1de54..bd9765e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,4 +11,5 @@ artifacts/
*.sln.ide
build/docker-compose.yml
build/mongodb/mongodata/
-src/Guestbooky/.vs/
\ No newline at end of file
+src/Guestbooky/.vs/
+/build/.env
diff --git a/README.md b/README.md
index 0675eb5..25b0bdc 100644
--- a/README.md
+++ b/README.md
@@ -34,6 +34,7 @@
- [🚀 Deployment ](#-deployment-)
- [Backend](#backend-1)
- [Admin Panel](#admin-panel-1)
+ - [Backup](#backup)
- [⛏️ Built Using ](#️-built-using-)
- [✍️ Authors ](#️-authors-)
@@ -65,20 +66,7 @@ For running it locally:
- A Cloudflare turnstile secret key for the captcha
- Not forgetting to set up environment variables
-You will be able to see in `build/docker-compose.public.yml` that the application makes heavy usage of them.
-```
- - ASPNETCORE_ENVIRONMENT=Production
- - CORS_ORIGINS=https://guestbook.example.com,http://localhost:5008,http://localhost:8080
- - ACCESS_USERNAME=user
- - ACCESS_PASSWORD=pass
- - ACCESS_TOKENKEY=pleaseinsertafairlylargetokenkeyherewillyou
- - ACCESS_ISSUER=https://guestbook.example.com/api
- - ACCESS_AUDIENCE=https://guestbook.example.com
- - CLOUDFLARE_SECRET=0x000000000000000000000000000000000
- - MONGODB_CONNECTIONSTRING=mongodb://mongouser:mongopass@mongo:27017/Guestbooky
- - MONGODB_DATABASENAME=Guestbooky
- - LOG_LEVEL=Debug
-```
+There's a `.env.template` file with all environment variables used throughout the compose file.
> [!IMPORTANT]
You will need to set them up either by hand or by using your IDE's capabilities. On Visual Studio, that can be done via the Debug Properties of Guestbooky.API.
@@ -89,10 +77,10 @@ You will be able to see in `build/docker-compose.public.yml` that the applicatio
|**CLOUDFLARE_SECRET**|The turnstile secret, used in the server portion of the captcha check.|
|**MONGODB_\***|Related to the connection to MongoDB. Yeah.|
|**LOG_\***|Logging.|
-
+|**GUESTBOOKY_**|Related to accessing the main document collection, which uses its own user.|
> [!TIP]
-> For local usage of the backend, you can use `docker-compose.local.yml` and edit the fields you need.
+> For local usage of the backend, you can use `docker-compose.local.yml` which provides just what you need to run the backend yourself.
### Admin panel
@@ -112,12 +100,16 @@ For development, it should be enough to run `vite` in Guestbooky-admin's `src` f
### Backend
-Use `docker-compose.public.yml` as a basis. it should create the image for you and start running.
+Use `docker-compose.public.yml` as a basis, and remember to have a `.env` file ready. it should create the image for you and start running.
### Admin Panel
In order to create a live version, adjust the **API_URL** path in `Guestbooky-admin/src/environment/constants.js`, and execute `vite build`. The application will be prepared and sent to `src/Guestbooky-admin/dist`. Send to your hosting solution and you should be good.
+### Backup
+
+Mongodump is run as a cron job daily. The behavior is customizable in `docker-compose.yml`
+
## ⛏️ Built Using
- [MongoDB](https://www.mongodb.com/) - Database
diff --git a/build/docker-compose.local.yml b/build/docker-compose.local.yml
index 63520fd..c5545d6 100644
--- a/build/docker-compose.local.yml
+++ b/build/docker-compose.local.yml
@@ -5,8 +5,8 @@ services:
container_name: mongo
restart: always
environment:
- MONGO_INITDB_ROOT_USERNAME: root
- MONGO_INITDB_ROOT_PASSWORD: mongo
+ MONGO_INITDB_ROOT_USERNAME: ${MONGO_INITDB_ROOT_USERNAME}
+ MONGO_INITDB_ROOT_PASSWORD: ${MONGO_INITDB_ROOT_PASSWORD}
volumes:
- ./mongodb/mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro
- ./mongodb/mongod.conf:/etc/mongod.conf:ro
@@ -19,15 +19,15 @@ services:
image: mongo-express
container_name: mongo-express
restart: always
- ports:
- - 8082:8081
environment:
- ME_CONFIG_MONGODB_ADMINUSERNAME: root
- ME_CONFIG_MONGODB_ADMINPASSWORD: mongo
- ME_CONFIG_MONGODB_URL: mongodb://root:mongo@mongo:27017/
- ME_CONFIG_BASICAUTH: false
+ ME_CONFIG_MONGODB_ADMINUSERNAME: ${MONGO_INITDB_ROOT_USERNAME}
+ ME_CONFIG_MONGODB_ADMINPASSWORD: ${MONGO_INITDB_ROOT_PASSWORD}
+ ME_CONFIG_MONGODB_URL: mongodb://${MONGO_INITDB_ROOT_USERNAME}:${MONGO_INITDB_ROOT_PASSWORD}@mongo:27017/
+ ME_CONFIG_BASICAUTH: "true"
depends_on:
- mongo
+ ports:
+ - "8082:8081"
volumes:
mongodata:
\ No newline at end of file
diff --git a/build/docker-compose.public.yml b/build/docker-compose.public.yml
index b2a1c8c..e189d3b 100644
--- a/build/docker-compose.public.yml
+++ b/build/docker-compose.public.yml
@@ -6,17 +6,17 @@ services:
ports:
- "8080:8080"
environment:
- - ASPNETCORE_ENVIRONMENT=Production
- - CORS_ORIGINS=https://guestbooky.example.com
- - ACCESS_USERNAME=user
- - ACCESS_PASSWORD=pass
- - ACCESS_TOKENKEY=youbetterbesureyouareusingatokenkey
- - ACCESS_ISSUER=https://guestbooky.example.com/api
- - ACCESS_AUDIENCE=https://guestbooky.example.com
- - CLOUDFLARE_SECRET=0x000000000000000000000000000000000
- - MONGODB_CONNECTIONSTRING=mongodb://mongouser:mongopass@mongo:27017/Guestbooky
- - MONGODB_DATABASENAME=Guestbooky
- - LOG_LEVEL=Debug
+ ASPNETCORE_ENVIRONMENT: Production
+ CORS_ORIGINS: ${CORS_ORIGINS}
+ ACCESS_USERNAME: ${ACCESS_USERNAME}
+ ACCESS_PASSWORD: ${ACCESS_PASSWORD}
+ ACCESS_TOKENKEY: ${ACCESS_TOKENKEY}
+ ACCESS_ISSUER: ${ACCESS_ISSUER}
+ ACCESS_AUDIENCE: ${ACCESS_AUDIENCE}
+ CLOUDFLARE_SECRET: ${CLOUDFLARE_SECRET}
+ MONGODB_CONNECTIONSTRING: mongodb://${GUESTBOOKY_USER}:${GUESTBOOKY_PASSWORD}@mongo:27017/${GUESTBOOKY_DB_NAME}
+ MONGODB_DATABASENAME: ${GUESTBOOKY_DB_NAME}
+ LOG_LEVEL: Debug
depends_on:
- mongo
restart: unless-stopped
@@ -28,8 +28,11 @@ services:
container_name: mongo
restart: always
environment:
- MONGO_INITDB_ROOT_USERNAME: root
- MONGO_INITDB_ROOT_PASSWORD: mongo
+ MONGO_INITDB_ROOT_USERNAME: ${MONGO_INITDB_ROOT_USERNAME}
+ MONGO_INITDB_ROOT_PASSWORD: ${MONGO_INITDB_ROOT_PASSWORD}
+ GUESTBOOKY_DB_NAME: ${GUESTBOOKY_DB_NAME}
+ GUESTBOOKY_USER: ${GUESTBOOKY_USER}
+ GUESTBOOKY_PASSWORD: ${GUESTBOOKY_PASSWORD}
volumes:
- ./mongodb/mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro
- ./mongodb/mongod.conf:/etc/mongod.conf:ro
@@ -38,6 +41,37 @@ services:
networks:
- guestbooky
+ cron:
+ image: mcuadros/ofelia:latest
+ container_name: ofelia-cron
+ command: daemon --docker
+ volumes:
+ - /var/run/docker.sock:/var/run/docker.sock:ro
+ - ./docker-compose.yml:/etc/docker-compose.yml:ro
+ labels:
+ ofelia.job-run.backup: "0 0 * * * docker-compose -f /etc/docker-compose.yml run --rm backup-job"
+ networks:
+ - guestbooky
+ env_file:
+ - .env
+
+ backup-job:
+ container_name: mongo-backup-job
+ image: mongo
+ command: >
+ bash -c "mongodump
+ --host mongo
+ --db ${GUESTBOOKY_DB_NAME}
+ --username ${GUESTBOOKY_USER}
+ --password ${GUESTBOOKY_USER}
+ --authenticationDatabase ${GUESTBOOKY_DB_NAME}
+ --out /backups/guestbooky_$(date +\%Y-\%m-\%d)"
+ volumes:
+ - ./backups:/backups
+ depends_on:
+ - mongo
+ networks:
+ - guestbooky
volumes:
mongodata:
diff --git a/build/mongodb/mongo-init.js b/build/mongodb/mongo-init.js
index 276b0a1..399290c 100644
--- a/build/mongodb/mongo-init.js
+++ b/build/mongodb/mongo-init.js
@@ -1,13 +1,13 @@
-db = db.getSiblingDB('Guestbooky');
+db = db.getSiblingDB(process.env.GUESTBOOKY_DB_NAME);
db.createUser(
{
- user: "guestbookyuser",
- pwd: "guestbookypassword",
+ user: process.env.GUESTBOOKY_USER,
+ pwd: process.env.GUESTBOOKY_PASSWORD,
roles: [
{
role: "readWrite",
- db: "Guestbooky"
+ db: process.env.GUESTBOOKY_DB_NAME
}
]
}
diff --git a/docs/comments.md b/docs/comments.md
index 0c358bd..bbafe3d 100644
--- a/docs/comments.md
+++ b/docs/comments.md
@@ -43,4 +43,6 @@ ___
- There isn't much exception handling, except in the API layer. This is on purpose. Another thing that this project could really use, but is left as an exercise, is using a `Maybe/Result/ErrorOr` type.
- Since there is so little that can go wrong with *low-stakes CRUDding*, it is a reasonable trade-off to let the API layer catch and send an internal server error.
-- By default, you need to choose between good Cookie-based authentication defaults or REST-friendly authentication via the `Authorization` header. Luckily you can support both with a few small additions - it made more sense to keep *RESTy* as the main method and stick Cookie support to its tail.
\ No newline at end of file
+- By default, you need to choose between good Cookie-based authentication defaults or REST-friendly authentication via the `Authorization` header. Luckily you can support both with a few small additions - it made more sense to keep *RESTy* as the main method and stick Cookie support to its tail
+
+- I really, REALLY should have done a daily backup mechanism right from the start. And I should have done the `.env`-based variable configuration from the get-go, too.
\ No newline at end of file