Nikola Derežić 419d91e292
All checks were successful
Build and Push Docker Image / build_web_app__check_image_version (push) Successful in 13s
Build and Push Docker Image / build_web_app (push) Successful in 5m49s
Merge branch 'hotfix/2.21.3'
2026-01-09 19:42:14 +01:00
2026-01-09 19:42:06 +01:00

ToDo

  • Public page with instructions

Authentication

Authentication consists of the following parts:

  • next-auth boilerplate
    • middleware.ts = hooks-up next-auth into the page processing pipeline - user session is checked before any page is rendered
    • auth.ts = defines how the authentication is done, and how session is checked (used by middleware)
    • /app/api/[...nextauth]/route.ts = defines route which shows an authentication form

Source:

Multi-User Support

Each location record is marked with a user ID.

All the actions user withUser to fetch user ID, which is then used in all the DB operations.

Repository Structure

This repository contains multiple independent projects:

  • web-app/: Next.js application for tracking utility bills
  • docker-stack/: Docker Compose configurations and deployment scripts
  • housekeeping/: Database backup and maintenance scripts

Each project is self-contained with its own dependencies and configuration.

Working with Projects

# Web app
cd web-app
npm install
npm run dev

# Deploy with Docker
cd docker-stack
./deploy-standalone.sh 2.20.0

# Housekeeping scripts
cd housekeeping
./db-backup--standalone.sh

Database Backup & Restore

The project includes multiple backup strategies for different deployment scenarios and requirements. All backup scripts are located in the housekeeping/ workspace.

Backup Scripts Overview

Standalone Docker Deployments

Online Backups (No Downtime):

  • housekeeping/db-dump--standalone.sh - Creates online backup of the 'utility-bills' database using mongodump

    • Database stays running during backup
    • Only backs up the database content, not the full volume
    • Output: ./mongo-backup/utility-bills-dump-YYYY-MM-DD_HH-MM.tar.gz
    • Default retention: 7 backups (configurable via KEEP env var)
    • Usage: cd housekeeping && ./db-dump--standalone.sh or KEEP=10 ./db-dump--standalone.sh
  • housekeeping/db-restore-from-dump--standalone.sh - Restores from mongodump archives

    • Database stays running during restore
    • WARNING: Drops existing collections before restore
    • Usage: cd housekeeping && ./db-restore-from-dump--standalone.sh utility-bills-dump-2025-11-26_14-30.tar.gz

Offline Backups (With Downtime):

  • housekeeping/db-backup--standalone.sh - Creates offline backup of the complete mongo-volume directory
    • Database container is stopped during backup for consistency
    • Backs up the entire MongoDB data directory
    • Output: ./mongo-backup/mongo-volume-backup-YYYY-MM-DD-HH-MM.tar.gz
    • Default retention: 7 backups (configurable via KEEP env var)
    • Usage: cd housekeeping && ./db-backup--standalone.sh or KEEP=2 ./db-backup--standalone.sh

Docker Swarm Deployments

  • housekeeping/db-backup--swarm.sh - Creates offline backup by scaling down the MongoDB service

    • Service is scaled to 0 during backup
    • Output: ./mongo-backup/mongo-volume-backup-YYYY-MM-DD-HH-MM.tar.gz
    • Usage: cd housekeeping && ./db-backup--swarm.sh
  • housekeeping/db-restore-from-backup--swarm.sh - Restores volume backup by scaling down the service

    • Service is scaled to 0 during restore
    • Optional --pre-backup flag for safety backup before restore
    • Usage: cd housekeeping && ./db-restore-from-backup--swarm.sh mongo-volume-backup-2025-11-26-14-30.tar.gz

Automated Backup Schedule

Backups run automatically via cron at 04:00 every day:

# Sunday: Full volume backup (offline), keep 2 backups
0 4 * * 0 cd /home/knee-cola/web-pro/evidencija-rezija/housekeeping && KEEP=2 ./db-backup--standalone.sh

# Monday-Saturday: Database dump (online), keep 6 backups
0 4 * * 1-6 cd /home/knee-cola/web-pro/evidencija-rezija/housekeeping && KEEP=6 ./db-dump--standalone.sh

Backup Strategy:

  • Sundays: Full volume backup with brief downtime (keeps 2 full backups)
  • Monday-Saturday: Online database dumps without downtime (keeps 6 daily backups)
  • Safety net: The retention policy ensures that at any point you have 2 full backups plus the 6 daily dumps created between them. This provides up to 2 weeks to detect and recover from a corrupted or inconsistent full backup before losing the previous full backup and its associated daily dumps.

All backup operations are logged with timestamps:

  • Volume backups: ./mongo-backup/db-backup-standalone.log
  • Database dumps: ./mongo-backup/db-dump-db-standalone.log
  • Restore operations: ./mongo-backup/db-restore-from-dump.log

Backup Directory

All backups are stored in ./mongo-backup/:

  • Volume backups: mongo-volume-backup-YYYY-MM-DD-HH-MM.tar.gz (full mongo-volume directory)
  • Database dumps: utility-bills-dump-YYYY-MM-DD_HH-MM.tar.gz (utility-bills database only)

This directory is excluded from git via .gitignore.

Deploying

The deployment is done via Docker.

Building Docker Image

From the web-app/ directory:

cd web-app
./build.sh 2.20.0

The image will be stored in the local Docker instance.

Deploying Docker Service

From the docker-stack/ directory:

cd docker-stack

# Standalone deployment
./deploy-standalone.sh 2.20.0

# Or Swarm deployment
./deploy-swarm.sh 2.20.0

Implementation details

Issues with HOSTNAME

When deplyed via docker and published via Cloudflare there's an issue with HOSTNAME env variable:

  • if left unset, the server will use IP address assigned to container by Docker (i.e. 10.0.20.3) and will not accept connections from outside
▲ Next.js 14.0.2
- Local:        http://68db6c9ebafe:80
- Network:      http://10.0.20.3:80
  • if set to "0.0.0.0" the server will serve static pages, but will reject API calls when submitting form
▲ Next.js 14.0.2
- Local:        http://localhost:80
- Network:      http://0.0.0.0:80

utility-bills-tracker_web-app.1.Error: Invalid Server Actions request.

`x-forwarded-host` header with value `0.0.0.0:80` does not match `origin` header with value `rezije.app` from a forwarded Server Actions request. Aborting the action.
  • if set to "rezije.app" the server will not start since the IP address it resolves with the given FQDN does not match any of the IP addresses assigned to the container
▲ Next.js 14.0.2
- Local:        http://localhost:80
- Network:      http://0.0.0.0:80

utility-bills-tracker_web-app.1.Error: Invalid Server Actions request.

`x-forwarded-host` header with value `rezije.app:80` does not match `origin` header with value `rezije.app` from a forwarded Server Actions request. Aborting the action.

So there are the following issues:

  • server will not accept external request - can be fixed by setting HOSTNAME to 0.0.0.0
  • server rejects API requests - can be fixed by adding serverActions.allowedOrigins option to nextjs.config.js file

So these are the fixes which were implemented in order to be able to run server in production.

This is a hack indicating that I don't understand how the damn thing should be configured!

Even when this hack is emplyed the server still logs the followig error:

failed to get redirect response TypeError: fetch failed
    at Object.fetch (node:internal/deps/undici/undici:11730:11)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
  cause: Error: connect ECONNREFUSED 0.0.0.0:443
      at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1555:16)
      at TCPConnectWrap.callbackTrampoline (node:internal/async_hooks:128:17) {
    errno: -111,
    code: 'ECONNREFUSED',
    syscall: 'connect',
    address: '0.0.0.0',
    port: 443
  }
}

Mongo DB & AVX Instructions

The MongoDB server v > 5.0 will not run on and old machine such as Acer Revo due to it's CPU.

This issue was solved by using an older Mongo DB Version 4.4.27

Decoding Barcode

Barcode decoding is slow and can lead to locking of the main thread. This heavy lifting could be moved to background thread.

The new solution could be based on the following code: https://github.com/pocesar/react-use-qrcode That solution uses video to decode the QR code. This could be modified so that it uses data stored in canvas.

OAuth verification video transcript

This is Rezije app demonstration for Google OAuth login process for the users of our app. The video shows that our usage of OAuth scopes complies with Google API services user data policy.

Our app does not use any of the sensitive and restricted scopes.

User's can access Privacy policy and Terms of service by clicking links in footer of the page.

Let's first click on the "Privacy policy" link. Here we can see our Privacy policy.

Now let's click on the "Terms of service" link. Here We can see our Terms of service.

Links to these pages are assigned in the apropriate fields in the Google's Cloud Console and are listed in the Google's OAuth window.

From our homepage you can login by clicking on the "Sign in with Google" button.

Here in the address bar you can see that the client ID is present in the URL.

Select the account with which you would like to sign-in with and you will be logged in into the app.

We are using two scopes:

  1. OAuth ID, which is used to assign ownership to the application specific data when it's is stored and retrieved from our database.
  2. user's e-mail address, which is stored in our database so that we can contact our users in case such action is needed.

For any questions regarding the use of the Google API service please feel free to reach out at support@rezije.app

Localization

Localization was done by following video: https://www.youtube.com/watch?v=uZQ5d2bRMO4

Description
No description provided
Readme 9.4 MiB
Languages
JavaScript 74.7%
TypeScript 24.3%
Shell 0.9%