# Fortnox React + Flask Application

This repository contains a full-stack web application with:

- Frontend: React (Create React App)
- Backend: Flask (served via Gunicorn)
- Web server: Apache (reverse proxy + SSL)
- Deployment: Git-based with automated provisioning and deploy script
- OS target: Debian / Ubuntu servers

---

## Repository Structure

```
.
├── backend/                 # Flask API
│   ├── api.py
│   ├── wsgi.py
│   ├── requirements.txt
│   ├── .env.example
│   └── venv/                # Created on server (not committed)
│
├── frontend/                # React app
│   ├── src/
│   ├── public/
│   ├── package.json
│   └── build/               # Production build (generated)
│
├── deploy/
│   ├── apache/              # Apache vhost configs
│   │   ├── fortnox.synktek.com.conf
│   │   └── fortnox.synktek.com-le-ssl.conf
│   │
│   ├── systemd/             # systemd service units
│   │   └── fortnox-gunicorn.service
│   │
│   └── scripts/
│       ├── install.sh       # One-time server provisioning script
│       └── deploy.sh        # Main deployment script
│
└── README.md
```

---

## Architecture Overview

```
Browser
   ↓ HTTPS
Apache (SSL + Proxy)
   ↓
Gunicorn (127.0.0.1:8000)
   ↓
Flask API
```

- Apache serves the React `build/` directory
- API requests are proxied to Gunicorn
- Gunicorn runs as `www-data`
- Deployments are done by user `deploy`

---

## Initial Server Setup (One-Time)

On a fresh Debian/Ubuntu server:

### 1) Clone the repository

```bash
git clone git@github.com:synktek-holger/fortnox.git
cd fortnox
```

### 2) Run provisioning script (as root)

```bash
sudo bash deploy/scripts/install.sh
```

This will:

- Install system packages
- Create `deploy` user
- Configure Apache (from `deploy/apache/`)
- Install systemd service (from `deploy/systemd/`)
- Configure sudo rules
- Install Node via nvm
- Initialize `backend/.env` from `backend/.env.example`

---

## Environment Configuration

Backend secrets are stored in:

```
backend/.env
```

Template:

```
backend/.env.example
```

After provisioning, edit:

```bash
sudo nano backend/.env
```

Example:

```env
FLASK_ENV=production
SECRET_KEY=change-me
SESSION_FILE_DIR=/run/fortnox/flask_session
```

Do NOT commit `.env` to Git.

---

## Deployment Workflow

All deployments are handled by:

```
deploy/scripts/deploy.sh
```

### Deploy (as deploy user)

```bash
sudo -u deploy bash -lc 'cd /var/www/fortnox.synktek.com && bash deploy/scripts/deploy.sh'
```

This will:

- Pull latest Git changes
- Install backend dependencies
- Build frontend
- Restart Gunicorn
- Reload Apache

No passwords should be required (deploy has limited NOPASSWD sudo).

---

## Local Development

### Backend

```bash
cd backend
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
flask run
```

### Frontend

```bash
cd frontend
npm install
npm start
```

---

## Service Management

### Gunicorn

```bash
sudo systemctl status fortnox-gunicorn
sudo systemctl restart fortnox-gunicorn
```

### Apache

```bash
sudo systemctl status apache2
sudo systemctl reload apache2
```

Logs:

```bash
journalctl -u fortnox-gunicorn -f
tail -f /var/log/apache2/error.log
```

---

## Session Storage

Flask sessions are stored in:

```
/run/fortnox/flask_session
```

Note:

- Cleared on reboot (ephemeral)
- Users will be logged out after reboot/restart that clears `/run`

If persistent sessions are needed, change to `/var/lib/fortnox/`.

---

## Permissions Model

| Component | Owner    | Purpose            |
|----------|----------|--------------------|
| Code     | deploy   | Deployments        |
| Runtime  | www-data | Gunicorn execution |
| Services | root     | systemd / Apache   |

Deploy user has passwordless access to:

- `systemctl restart fortnox-gunicorn`
- `systemctl reload apache2`

---

## Troubleshooting

### Gunicorn not starting

```bash
journalctl -u fortnox-gunicorn --no-pager
```

Common causes:

- Missing venv
- Wrong paths in service file
- Bad .env config
- Permission issues

### Frontend build fails

```bash
cd frontend
nvm use 20
npm ci
npm run build
```

Check Node version:

```bash
node -v
```

Should be v20.x.

### Apache not proxying

```bash
sudo apachectl configtest
sudo systemctl reload apache2
```

Verify proxy modules:

```bash
apachectl -M | grep proxy
```

---

## Security Notes

- `.env` is not committed
- Gunicorn bound to localhost only
- SSL enforced (HTTP redirects to HTTPS)
- sudo limited to specific commands
- Sessions isolated per app

---

