monacousa-portal/deploy
Matt dc0198dcad
Build and Push Docker Image / build (push) Successful in 1m54s Details
Add comprehensive table grants for authenticated role
RLS policies define WHAT rows can be accessed, but GRANT statements
control WHETHER a table can be accessed at all. This was causing 403
errors when authenticated users tried to access tables.

Added grants for:
- Core tables: members, membership_statuses, membership_types
- Dues: dues_payments (SELECT)
- Events: events, event_types, event_rsvps (full CRUD), event_rsvps_public
- Documents: documents, document_categories, document_folders
- Settings: app_settings (SELECT for public settings)
- Email: email_logs (SELECT for own logs)
- Preferences: user_notification_preferences (SELECT, INSERT, UPDATE)
- Views: members_with_dues, events_with_counts

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 15:40:47 +01:00
..
.env.example Fix domain configuration for separate portal and API domains 2026-01-26 11:34:25 +01:00
README.md Remove Traefik from deploy package (use existing nginx) 2026-01-26 11:18:55 +01:00
docker-compose.yml Add password setup script for Supabase roles 2026-01-26 13:57:35 +01:00
init.sql Add comprehensive table grants for authenticated role 2026-01-26 15:40:47 +01:00
kong.yml.template Add standalone production deployment package 2026-01-26 11:15:56 +01:00
setup.sh Fix domain configuration for separate portal and API domains 2026-01-26 11:34:25 +01:00
zz-set-passwords.sh Add password setup script for Supabase roles 2026-01-26 13:57:35 +01:00

README.md

Monaco USA Portal - Standalone Production Deployment

This is a standalone deployment package for the Monaco USA Portal. No source code cloning required.

Prerequisites

  • Linux server (Ubuntu 22.04+ recommended)
  • Docker Engine 24.0+
  • Docker Compose v2.20+
  • Nginx installed and configured for SSL
  • Domain name with DNS pointing to your server

Quick Start

1. Download the deployment files

Create a directory and download the deployment files:

mkdir -p /opt/monacousa
cd /opt/monacousa

# Download files from your deployment source
# Example: copy from Gitea, scp, etc.

You need these files:

  • docker-compose.yml
  • .env.example
  • init.sql
  • kong.yml.template
  • setup.sh

2. Configure environment

# Copy the example environment file
cp .env.example .env

# Edit with your settings
nano .env

At minimum, configure:

  • DOMAIN - Your domain name (e.g., portal.monacousa.org)
  • SMTP settings (optional but recommended for emails)

3. Run setup script

# Make setup script executable
chmod +x setup.sh

# Run setup - this generates secrets and kong.yml
./setup.sh

The setup script will:

  • Generate secure random passwords and JWT tokens
  • Create kong.yml from the template with your API keys
  • Validate your configuration

4. Start the services

docker compose up -d

5. Configure Nginx

Add proxy configuration for your domain. Example:

# Portal - main site
server {
    listen 443 ssl http2;
    server_name portal.monacousa.org;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
    }
}

# API - Supabase services
server {
    listen 443 ssl http2;
    server_name api.portal.monacousa.org;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
    }
}

# Studio - Supabase dashboard (optional)
server {
    listen 443 ssl http2;
    server_name studio.portal.monacousa.org;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    # Add basic auth for security
    auth_basic "Supabase Studio";
    auth_basic_user_file /etc/nginx/.htpasswd;

    location / {
        proxy_pass http://127.0.0.1:3001;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
    }
}

Reload nginx:

nginx -t && systemctl reload nginx

6. Verify deployment

# Check all containers are running
docker compose ps

# Check database initialization
docker compose logs db

# Check for any errors
docker compose logs -f

7. Access the portal

Open https://portal.monacousa.org in your browser. On first visit, you'll be redirected to /setup to create the initial admin account.

Architecture

Internet
    │
    └─► Nginx (SSL/Reverse Proxy)
            │
            ├─► portal.domain.com:443 ──► localhost:3000 ──► Portal (SvelteKit)
            ├─► api.domain.com:443 ──► localhost:8000 ──► Kong ──► Auth/REST/Storage
            └─► studio.domain.com:443 ──► localhost:3001 ──► Studio (Dashboard)

Internal Docker Network
    │
    ├─► Kong API Gateway (port 8000)
    │       ├─► Auth (GoTrue)
    │       ├─► REST (PostgREST)
    │       ├─► Storage API
    │       └─► Realtime
    │
    └─► PostgreSQL Database

Exposed Ports

Service Port Purpose
Portal 127.0.0.1:3000 Main web application
Kong 127.0.0.1:8000 Supabase API gateway
Studio 127.0.0.1:3001 Supabase dashboard (optional)

All ports are bound to localhost only for security. Use nginx to expose them.

Files Description

File Purpose
docker-compose.yml All service definitions
.env Your configuration (from .env.example)
init.sql Database schema and migrations
kong.yml.template API gateway config template
kong.yml Generated API gateway config (created by setup.sh)
setup.sh Setup script for secrets and validation

Management Commands

# Start all services
docker compose up -d

# Stop all services
docker compose down

# View logs
docker compose logs -f

# View specific service logs
docker compose logs -f portal
docker compose logs -f db

# Restart a specific service
docker compose restart portal

# Check resource usage
docker stats

# Enter database shell
docker compose exec db psql -U postgres

Updating

To update the portal to a new version:

# Pull the latest image
docker compose pull portal

# Restart the portal service
docker compose up -d portal

Backup

Database backup

# Create backup
docker compose exec db pg_dump -U postgres postgres > backup_$(date +%Y%m%d).sql

# Restore backup
docker compose exec -T db psql -U postgres postgres < backup_YYYYMMDD.sql

Full backup (including storage)

# Stop services first for consistent backup
docker compose stop

# Backup volumes
docker run --rm -v monacousa_db-data:/data -v $(pwd):/backup alpine \
    tar czf /backup/db-data-backup.tar.gz -C /data .

docker run --rm -v monacousa_storage-data:/data -v $(pwd):/backup alpine \
    tar czf /backup/storage-data-backup.tar.gz -C /data .

# Start services
docker compose up -d

Troubleshooting

Containers not starting

# Check logs for errors
docker compose logs

# Check if ports are in use
netstat -tlnp | grep -E ':(3000|3001|8000)'

Database connection errors

# Check database is healthy
docker compose ps db

# Check database logs
docker compose logs db

# Verify database is accepting connections
docker compose exec db pg_isready -U postgres

API 401 Unauthorized errors

This usually means the API keys don't match. Run setup again:

./setup.sh
docker compose restart kong

Portal not loading

# Check portal logs
docker compose logs portal

# Verify kong is routing correctly
docker compose exec portal wget -qO- http://kong:8000/rest/v1/ || echo "Kong not reachable"

Nginx 502 Bad Gateway

Check if the Docker containers are running:

docker compose ps
curl http://127.0.0.1:3000  # Should return HTML
curl http://127.0.0.1:8000  # Should return JSON

Security Recommendations

  1. Secure your .env file

    chmod 600 .env
    
  2. Protect Supabase Studio with auth

    # Generate password file for nginx
    htpasswd -c /etc/nginx/.htpasswd admin
    
  3. Regular updates

    • Keep Docker and host OS updated
    • Regularly pull latest portal images
  4. Monitor logs

    • Set up log rotation (configured in docker-compose.yml)
    • Consider centralized logging

Support

For issues and questions: