# GymFlow Deployment Guide (NAS / Existing Container)

This guide explains how to deploy GymFlow to your Ugreen NAS by integrating it into your existing `nodejs-apps` container.

## 1. Preparation (Build)

You need to build the application on your local machine before transferring it to the NAS.

### Build Frontend
Run the following in the project root:
```bash
npm install
npm install
npm run build
```
> [!IMPORTANT]
> If you encounter a `TypeError: Missing parameter name` in your logs, ensure you have rebuilt the app with the latest changes (`app.get('*all', ...)`).
This creates a `dist` folder with the compiled frontend.

### Build Backend
1. Update your `server/package.json` to have these scripts for production:
```json
"scripts": {
    "start": "node dist/index.js",
    "start:prod": "node dist/index.js",
    ...
}
```
2. Run the following locally:
```bash
cd server
npm install
npm run build
cd ..
```

## 2. Transfer Files

Copy the entire `gymflow` folder to your NAS.
Destination: `nodejs_data/gymflow` (inside the folder mounted to `/usr/src/app`).

Ensure the following files/folders are present on the NAS:
- `gymflow/dist/` (Frontend assets)
- `gymflow/server/dist/` (Backend code)
- `gymflow/server/package.json`
- `gymflow/server/prisma/` (Schema for database)
- `gymflow/ecosystem.config.cjs` (PM2 config)

*Note: You do not need to copy `node_modules`. We will install production dependencies on the NAS to ensure compatibility.*

Update your `docker-compose.yml` to use a custom Dockerfile (to support building native modules like `better-sqlite3`) and map the new port.

### 2a. Use Custom Dockerfile
The standard `node:lts-slim` image lacks Python and build tools. Use the provided [Dockerfile.node-apps](file:///d:/Coding/gymflow/Dockerfile.node-apps):

1. Copy `Dockerfile.node-apps` to your NAS alongside `docker-compose.yml`.
2. Modify `docker-compose.yml`:
```yaml
services:
  nodejs-apps:
    build:
      context: .
      dockerfile: Dockerfile.node-apps
    container_name: node-apps
    # image: node:lts-slim  <-- Comment this out
    ...
```

### 3. Integration

### Update `command`
Add the following to your existing command string. We added `npx prisma generate` explicitly to ensure the Linux client is built correctly, and we ensure `DATABASE_URL` is consistent:

```bash
... && cd ../gymflow/server && npm install --omit=dev && APP_MODE=prod DATABASE_URL=file:./prod.db npx prisma generate && APP_MODE=prod DATABASE_URL=file:./prod.db npx prisma db push && cd .. && pm2 start ecosystem.config.cjs && ...
```
*Note: We assume `gymflow` is a sibling of `ag-beats` etc.*

**Full Command Example:**
```yaml
command: /bin/sh -c "npm install -g pm2 && cd ag-beats && npm install && cd ../ball-shooting && npm install && cd ../gymflow/server && npm install --omit=dev && APP_MODE=prod DATABASE_URL=file:./prod.db npx prisma generate && APP_MODE=prod DATABASE_URL=file:./prod.db npx prisma db push && cd .. && pm2 start ecosystem.config.cjs && cd ../ag-beats && pm2 start ecosystem.config.js && cd ../ball-shooting && pm2 start npm --name ag-ball -- start && pm2 logs --raw"
```

> [!IMPORTANT]
> Since we updated the `Dockerfile.node-apps` to include `openssl` (required by Prisma), you **must** rebuild the image:
> `docker-compose up -d --build nodejs-apps`

### Update `ports`
Add the GymFlow port (3003 inside container, mapped to your choice, e.g., 3033):
```yaml
ports:
 - "3030:3000"
 - "3031:3001"
 - "3032:3002"
 - "3033:3003" # GymFlow
```

## 4. Unified Ecosystem Config
Your common `ecosystem.config.js` should look like this to ensure GymFlow has the correct production environment:

```javascript
module.exports = {
  apps: [
    {
      name: "ag-home",
      script: "server.js",
      cwd: "/usr/src/app",
      exec_mode: "fork",
    },
    {
      name: "ag-beats",
      script: "npm",
      args: "start",
      cwd: "/usr/src/app/ag-beats",
    },
    {
      name: "ag-ball",
      script: "npm",
      args: "start",
      cwd: "/usr/src/app/ball-shooting",
    },
    {
      name: "gymflow",
      script: "dist/index.js",
      cwd: "/usr/src/app/gymflow/server",
      env: {
        NODE_ENV: "production",
        APP_MODE: "prod",
        PORT: 3003,
        DATABASE_URL: "file:./prod.db",
        DATABASE_URL_PROD: "file:./prod.db"
      }
    }
  ]
};
```

## 5. Nginx Proxy Manager

Point your domain (e.g., `gym.yourdomain.com`) to the NAS IP and the mapped port (`3033`).
- Scheme: `http`
- Forward Hostname / IP: `[NAS_IP]`
- Forward Port: `3033`
- Websockets Support: Enable (if needed for future features).

## 6. Troubleshooting

### "Readonly Database" Error
If you see an error like `Invalid prisma.userProfile.upsert() invocation: attempt to write a readonly database`:

1. **Verify Permissions:** Run the diagnostic script inside your container:
   ```bash
   docker exec -it node-apps node /usr/src/app/gymflow/server/check_db_perms.js
   ```
2. **Fix Permissions:** If the checks fail, run these commands on your NAS inside the `gymflow/server` directory:
   ```bash
   sudo chmod 777 .
   sudo chmod 666 prod.db
   ```
   *Note: SQLite needs write access to the directory itself to create temporary journaling files (`-wal`, `-shm`).*

3. **Check Docker User:** Alternatively, ensure your Docker container is running as a user who owns these files (e.g., set `user: "1000:1000"` in `docker-compose.yml` if your NAS user has that ID).

### "Invalid ELF Header" Error
If you see an error like `invalid ELF header` for `better-sqlite3.node`:
This happens because the `node_modules` contains Windows binaries (from your local machine) instead of Linux binaries.

1. **Fix Inside Container:** Run the following command to force a rebuild of native modules for Linux:
   ```bash
   docker exec -it node-apps /bin/sh -c "cd /usr/src/app/gymflow/server && npm rebuild better-sqlite3"
   ```
2. **Restart Container:** After rebuilding, restart the container:
   ```bash
   docker-compose restart nodejs-apps
   ```
