265 lines
11 KiB
Markdown
265 lines
11 KiB
Markdown
# Flyer URL Configuration
|
|
|
|
## Overview
|
|
|
|
Flyer image and icon URLs are environment-specific to ensure they point to the correct server for each deployment. Images are served as static files by NGINX from the `/flyer-images/` path with 7-day browser caching enabled.
|
|
|
|
## Environment-Specific URLs
|
|
|
|
| Environment | Base URL | Example |
|
|
| ------------- | ------------------------------------------- | -------------------------------------------------------------------------- |
|
|
| Dev Container | `https://127.0.0.1` | `https://127.0.0.1/flyer-images/safeway-flyer.jpg` |
|
|
| Test | `https://flyer-crawler-test.projectium.com` | `https://flyer-crawler-test.projectium.com/flyer-images/safeway-flyer.jpg` |
|
|
| Production | `https://flyer-crawler.projectium.com` | `https://flyer-crawler.projectium.com/flyer-images/safeway-flyer.jpg` |
|
|
|
|
**Note:** The dev container accepts connections to **both** `https://localhost/` and `https://127.0.0.1/` thanks to the SSL certificate and NGINX configuration. See [SSL Certificate Configuration](#ssl-certificate-configuration-dev-container) below.
|
|
|
|
## SSL Certificate Configuration (Dev Container)
|
|
|
|
The dev container uses self-signed certificates generated by [mkcert](https://github.com/FiloSottile/mkcert) to enable HTTPS locally. This configuration solves a common mixed-origin SSL issue.
|
|
|
|
### The Problem
|
|
|
|
When users access the site via `https://localhost/` but image URLs in the database use `https://127.0.0.1/...`, browsers treat these as different origins. This causes `ERR_CERT_AUTHORITY_INVALID` errors when loading images, even though both hostnames point to the same server.
|
|
|
|
### The Solution
|
|
|
|
1. **Certificate Generation** (`Dockerfile.dev`):
|
|
|
|
```bash
|
|
mkcert localhost 127.0.0.1 ::1
|
|
```
|
|
|
|
This creates a certificate with Subject Alternative Names (SANs) for all three hostnames.
|
|
|
|
2. **NGINX Configuration** (`docker/nginx/dev.conf`):
|
|
|
|
```nginx
|
|
server_name localhost 127.0.0.1;
|
|
```
|
|
|
|
NGINX accepts requests to both hostnames using the same SSL certificate.
|
|
|
|
### How It Works
|
|
|
|
| Component | Configuration |
|
|
| -------------------- | ---------------------------------------------------- |
|
|
| SSL Certificate SANs | `localhost`, `127.0.0.1`, `::1` |
|
|
| NGINX `server_name` | `localhost 127.0.0.1` |
|
|
| Seed Script URLs | Uses `https://127.0.0.1` (works with DB constraints) |
|
|
| User Access | Either `https://localhost/` or `https://127.0.0.1/` |
|
|
|
|
### Why This Matters
|
|
|
|
- **Database Constraints**: The `flyers` table has CHECK constraints requiring URLs to start with `http://` or `https://`. Relative URLs are not allowed.
|
|
- **Consistent Behavior**: Users can access the site using either hostname without SSL warnings.
|
|
- **Same Certificate**: Both hostnames use the same self-signed certificate, eliminating mixed-content errors.
|
|
|
|
### Verifying the Configuration
|
|
|
|
```bash
|
|
# Check certificate SANs
|
|
podman exec flyer-crawler-dev openssl x509 -in /app/certs/localhost.crt -text -noout | grep -A1 "Subject Alternative Name"
|
|
|
|
# Expected output:
|
|
# X509v3 Subject Alternative Name:
|
|
# DNS:localhost, IP Address:127.0.0.1, IP Address:0:0:0:0:0:0:0:1
|
|
|
|
# Test both hostnames respond
|
|
curl -k https://localhost/health
|
|
curl -k https://127.0.0.1/health
|
|
```
|
|
|
|
### Troubleshooting SSL Issues
|
|
|
|
If you encounter `ERR_CERT_AUTHORITY_INVALID`:
|
|
|
|
1. **Check NGINX is running**: `podman exec flyer-crawler-dev nginx -t`
|
|
2. **Verify certificate exists**: `podman exec flyer-crawler-dev ls -la /app/certs/`
|
|
3. **Ensure both hostnames are in server_name**: Check `/etc/nginx/sites-available/default`
|
|
4. **Rebuild container if needed**: The certificate is generated at build time
|
|
|
|
### Permanent Fix: Install CA Certificate (Recommended)
|
|
|
|
To permanently eliminate SSL certificate warnings, install the mkcert CA certificate on your system. This is optional but provides a better development experience.
|
|
|
|
The CA certificate is located at `certs/mkcert-ca.crt` in the project root. See [`certs/README.md`](../certs/README.md) for platform-specific installation instructions (Windows, macOS, Linux, Firefox).
|
|
|
|
After installation:
|
|
|
|
- Your browser will trust all mkcert certificates without warnings
|
|
- Both `https://localhost/` and `https://127.0.0.1/` will work without SSL errors
|
|
- Flyer images will load without `ERR_CERT_AUTHORITY_INVALID` errors
|
|
|
|
See also: [Debugging Guide - SSL Issues](development/DEBUGGING.md#ssl-certificate-issues)
|
|
|
|
## NGINX Static File Serving
|
|
|
|
All environments serve flyer images as static files with browser caching:
|
|
|
|
```nginx
|
|
# Serve flyer images from static storage (7-day cache)
|
|
location /flyer-images/ {
|
|
alias /path/to/flyer-images/;
|
|
expires 7d;
|
|
add_header Cache-Control "public, immutable";
|
|
}
|
|
```
|
|
|
|
### Directory Paths by Environment
|
|
|
|
| Environment | NGINX Alias Path |
|
|
| ------------- | ---------------------------------------------------------- |
|
|
| Dev Container | `/app/public/flyer-images/` |
|
|
| Test | `/var/www/flyer-crawler-test.projectium.com/flyer-images/` |
|
|
| Production | `/var/www/flyer-crawler.projectium.com/flyer-images/` |
|
|
|
|
## Configuration
|
|
|
|
### Environment Variable
|
|
|
|
Set `FLYER_BASE_URL` in your environment configuration:
|
|
|
|
```bash
|
|
# Dev container (.env)
|
|
FLYER_BASE_URL=https://localhost
|
|
|
|
# Test environment
|
|
FLYER_BASE_URL=https://flyer-crawler-test.projectium.com
|
|
|
|
# Production
|
|
FLYER_BASE_URL=https://flyer-crawler.projectium.com
|
|
```
|
|
|
|
### Seed Script
|
|
|
|
The seed script ([src/db/seed.ts](../src/db/seed.ts)) automatically uses the correct base URL based on:
|
|
|
|
1. `FLYER_BASE_URL` environment variable (if set)
|
|
2. `NODE_ENV` value:
|
|
- `production` → `https://flyer-crawler.projectium.com`
|
|
- `test` → `https://flyer-crawler-test.projectium.com`
|
|
- Default → `https://localhost`
|
|
|
|
The seed script also copies test images from `src/tests/assets/` to `public/flyer-images/`:
|
|
|
|
- `test-flyer-image.jpg` - Sample flyer image
|
|
- `test-flyer-icon.png` - Sample 64x64 icon
|
|
|
|
## Updating Existing Data
|
|
|
|
If you need to update existing flyer URLs in the database, use the provided SQL script:
|
|
|
|
### Dev Container
|
|
|
|
```bash
|
|
# Connect to dev database
|
|
podman exec -it flyer-crawler-postgres psql -U postgres -d flyer_crawler_dev
|
|
|
|
# Run the update (dev container uses HTTPS with self-signed certs)
|
|
UPDATE flyers
|
|
SET
|
|
image_url = REPLACE(image_url, 'example.com', 'localhost'),
|
|
icon_url = REPLACE(icon_url, 'example.com', 'localhost')
|
|
WHERE
|
|
image_url LIKE '%example.com%'
|
|
OR icon_url LIKE '%example.com%';
|
|
|
|
# Verify
|
|
SELECT flyer_id, image_url, icon_url FROM flyers;
|
|
```
|
|
|
|
### Test Environment
|
|
|
|
```bash
|
|
# Via SSH
|
|
ssh root@projectium.com "psql -U flyer_crawler_test -d flyer-crawler-test -c \"
|
|
UPDATE flyers
|
|
SET
|
|
image_url = REPLACE(image_url, 'example.com', 'flyer-crawler-test.projectium.com'),
|
|
icon_url = REPLACE(icon_url, 'example.com', 'flyer-crawler-test.projectium.com')
|
|
WHERE
|
|
image_url LIKE '%example.com%'
|
|
OR icon_url LIKE '%example.com%';
|
|
\""
|
|
```
|
|
|
|
### Production
|
|
|
|
```bash
|
|
# Via SSH
|
|
ssh root@projectium.com "psql -U flyer_crawler_prod -d flyer-crawler-prod -c \"
|
|
UPDATE flyers
|
|
SET
|
|
image_url = REPLACE(image_url, 'example.com', 'flyer-crawler.projectium.com'),
|
|
icon_url = REPLACE(icon_url, 'example.com', 'flyer-crawler.projectium.com')
|
|
WHERE
|
|
image_url LIKE '%example.com%'
|
|
OR icon_url LIKE '%example.com%';
|
|
\""
|
|
```
|
|
|
|
## Test Data Updates
|
|
|
|
### Test Helper Function
|
|
|
|
A helper function `getFlyerBaseUrl()` is available in [src/tests/utils/testHelpers.ts](../src/tests/utils/testHelpers.ts) that automatically detects the correct base URL for tests:
|
|
|
|
```typescript
|
|
export const getFlyerBaseUrl = (): string => {
|
|
if (process.env.FLYER_BASE_URL) {
|
|
return process.env.FLYER_BASE_URL;
|
|
}
|
|
|
|
// Check if we're in dev container (DB_HOST=postgres is typical indicator)
|
|
// Use 'localhost' instead of '127.0.0.1' to match the hostname users access
|
|
// This avoids SSL certificate mixed-origin issues in browsers
|
|
if (process.env.DB_HOST === 'postgres' || process.env.DB_HOST === '127.0.0.1') {
|
|
return 'https://localhost';
|
|
}
|
|
|
|
if (process.env.NODE_ENV === 'production') {
|
|
return 'https://flyer-crawler.projectium.com';
|
|
}
|
|
|
|
if (process.env.NODE_ENV === 'test') {
|
|
return 'https://flyer-crawler-test.projectium.com';
|
|
}
|
|
|
|
// Default for unit tests
|
|
return 'https://example.com';
|
|
};
|
|
```
|
|
|
|
### Updated Test Files
|
|
|
|
The following test files now use `getFlyerBaseUrl()` for environment-aware URL generation:
|
|
|
|
- [src/db/seed.ts](../src/db/seed.ts) - Main seed script (uses `FLYER_BASE_URL`)
|
|
- [src/tests/utils/testHelpers.ts](../src/tests/utils/testHelpers.ts) - `getFlyerBaseUrl()` helper function
|
|
- [src/hooks/useDataExtraction.test.ts](../src/hooks/useDataExtraction.test.ts) - Mock flyer factory
|
|
- [src/schemas/flyer.schemas.test.ts](../src/schemas/flyer.schemas.test.ts) - Schema validation tests
|
|
- [src/services/flyerProcessingService.server.test.ts](../src/services/flyerProcessingService.server.test.ts) - Processing service tests
|
|
- [src/tests/integration/flyer-processing.integration.test.ts](../src/tests/integration/flyer-processing.integration.test.ts) - Integration tests
|
|
|
|
This approach ensures tests work correctly in all environments (dev container, CI/CD, local development, test, production).
|
|
|
|
## Files Changed
|
|
|
|
| File | Change |
|
|
| --------------------------- | ------------------------------------------------------------------------------------------------- |
|
|
| `src/db/seed.ts` | Added `FLYER_BASE_URL` environment variable support, copies test images to `public/flyer-images/` |
|
|
| `docker/nginx/dev.conf` | Added `/flyer-images/` location block for static file serving |
|
|
| `.env.example` | Added `FLYER_BASE_URL` variable |
|
|
| `sql/update_flyer_urls.sql` | SQL script for updating existing data |
|
|
| Test files | Updated mock data to use `https://localhost` |
|
|
|
|
## Summary
|
|
|
|
- Seed script now uses environment-specific HTTPS URLs
|
|
- Seed script copies test images from `src/tests/assets/` to `public/flyer-images/`
|
|
- NGINX serves `/flyer-images/` as static files with 7-day cache
|
|
- Test files updated with `https://localhost` (not `127.0.0.1` to avoid SSL mixed-origin issues)
|
|
- SQL script provided for updating existing data
|
|
- Documentation updated for each environment
|