diff --git a/app/donate/page.tsx b/app/donate/page.tsx index ff35666..033b92b 100644 --- a/app/donate/page.tsx +++ b/app/donate/page.tsx @@ -43,6 +43,15 @@ export default async function DonatePage() {

+ {/* Coming soon notice */} +
+ 🚧 +
+

Online Donations Coming Soon

+

We're setting up secure payment processing. In the meantime, please visit ccfriendsofwildlife.org to donate directly.

+
+
+ {/* Impact banner */}
{[ diff --git a/backend/src/lib/prisma.ts b/backend/src/lib/prisma.ts new file mode 100644 index 0000000..4e54f7a --- /dev/null +++ b/backend/src/lib/prisma.ts @@ -0,0 +1,5 @@ +import { PrismaClient } from '@prisma/client'; + +const prisma = new PrismaClient(); + +export default prisma; diff --git a/backend/src/routes/auth.ts b/backend/src/routes/auth.ts index d7c37d9..332b60c 100644 --- a/backend/src/routes/auth.ts +++ b/backend/src/routes/auth.ts @@ -1,12 +1,11 @@ import { Router, Request, Response, NextFunction } from 'express'; import { body, validationResult } from 'express-validator'; -import { PrismaClient } from '@prisma/client'; +import prisma from '../lib/prisma'; import { hashPassword, verifyPassword } from '../utils/password'; import { signToken } from '../utils/jwt'; import { authenticate, AuthRequest } from '../middleware/auth'; const router = Router(); -const prisma = new PrismaClient(); const validateRegister = [ body('email').isEmail().normalizeEmail(), diff --git a/backend/src/routes/burrows.ts b/backend/src/routes/burrows.ts index 3380bff..a6363ef 100644 --- a/backend/src/routes/burrows.ts +++ b/backend/src/routes/burrows.ts @@ -1,10 +1,9 @@ import { Router, Response, NextFunction } from 'express'; import { body, validationResult } from 'express-validator'; -import { PrismaClient } from '@prisma/client'; +import prisma from '../lib/prisma'; import { authenticate, requireRole, optionalAuth, AuthRequest } from '../middleware/auth'; const router = Router(); -const prisma = new PrismaClient(); // GET /api/burrows — public router.get('/', optionalAuth, async (_req: AuthRequest, res: Response, next: NextFunction) => { diff --git a/backend/src/routes/donations.ts b/backend/src/routes/donations.ts index 1354a17..08947a0 100644 --- a/backend/src/routes/donations.ts +++ b/backend/src/routes/donations.ts @@ -1,10 +1,9 @@ import { Router, Response, NextFunction } from 'express'; import { body, validationResult } from 'express-validator'; -import { PrismaClient } from '@prisma/client'; +import prisma from '../lib/prisma'; import { optionalAuth, authenticate, requireRole, AuthRequest } from '../middleware/auth'; const router = Router(); -const prisma = new PrismaClient(); // POST /api/donations — public (guest) or authenticated // Stripe integration stub: stores intent, returns client_secret placeholder diff --git a/backend/src/routes/events.ts b/backend/src/routes/events.ts index 5fae125..35bca93 100644 --- a/backend/src/routes/events.ts +++ b/backend/src/routes/events.ts @@ -1,10 +1,9 @@ import { Router, Response, NextFunction } from 'express'; import { body, validationResult } from 'express-validator'; -import { PrismaClient } from '@prisma/client'; +import prisma from '../lib/prisma'; import { authenticate, requireRole, optionalAuth, AuthRequest } from '../middleware/auth'; const router = Router(); -const prisma = new PrismaClient(); // GET /api/events — public router.get('/', optionalAuth, async (_req: AuthRequest, res: Response, next: NextFunction) => { diff --git a/backend/src/routes/sightings.ts b/backend/src/routes/sightings.ts index 8eac2bf..617c30e 100644 --- a/backend/src/routes/sightings.ts +++ b/backend/src/routes/sightings.ts @@ -1,10 +1,9 @@ import { Router, Response, NextFunction } from 'express'; import { body, validationResult } from 'express-validator'; -import { PrismaClient } from '@prisma/client'; +import prisma from '../lib/prisma'; import { authenticate, requireRole, optionalAuth, AuthRequest } from '../middleware/auth'; const router = Router(); -const prisma = new PrismaClient(); // GET /api/sightings — public router.get('/', optionalAuth, async (_req: AuthRequest, res: Response, next: NextFunction) => { diff --git a/backend/src/routes/stats.ts b/backend/src/routes/stats.ts index 3643502..6200a75 100644 --- a/backend/src/routes/stats.ts +++ b/backend/src/routes/stats.ts @@ -1,9 +1,8 @@ import { Router, Response, NextFunction } from 'express'; -import { PrismaClient } from '@prisma/client'; +import prisma from '../lib/prisma'; import { AuthRequest } from '../middleware/auth'; const router = Router(); -const prisma = new PrismaClient(); // GET /api/stats — public dashboard stats router.get('/', async (_req: AuthRequest, res: Response, next: NextFunction) => { diff --git a/backend/src/routes/streams.ts b/backend/src/routes/streams.ts index 2a22db2..095c046 100644 --- a/backend/src/routes/streams.ts +++ b/backend/src/routes/streams.ts @@ -1,16 +1,28 @@ import { Router, Response, NextFunction } from 'express'; import { body, validationResult } from 'express-validator'; -import { PrismaClient } from '@prisma/client'; +import prisma from '../lib/prisma'; import { authenticate, requireRole, AuthRequest } from '../middleware/auth'; const router = Router(); -const prisma = new PrismaClient(); // GET /api/streams — public +function mapStream(s: any) { + return { + id: s.id, + name: s.name, + location: s.camera_location, + status: s.status, + viewerCount: 0, + hlsUrl: s.stream_url, + thumbnailUrl: s.thumbnail_url, + createdAt: s.created_at, + }; +} + router.get('/', async (_req: AuthRequest, res: Response, next: NextFunction) => { try { const streams = await prisma.livestreamSource.findMany({ orderBy: { status: 'asc' } }); - res.json(streams); + res.json(streams.map(mapStream)); } catch (err) { next(err); } }); @@ -19,7 +31,7 @@ router.get('/:id', async (req: AuthRequest, res: Response, next: NextFunction) = try { const stream = await prisma.livestreamSource.findUnique({ where: { id: req.params.id } }); if (!stream) { res.status(404).json({ error: 'Stream not found' }); return; } - res.json(stream); + res.json(mapStream(stream)); } catch (err) { next(err); } }); diff --git a/backend/src/routes/volunteer.ts b/backend/src/routes/volunteer.ts index af9caac..9b0d910 100644 --- a/backend/src/routes/volunteer.ts +++ b/backend/src/routes/volunteer.ts @@ -1,10 +1,9 @@ import { Router, Response, NextFunction } from 'express'; import { body, validationResult } from 'express-validator'; -import { PrismaClient } from '@prisma/client'; +import prisma from '../lib/prisma'; import { authenticate, requireRole, AuthRequest } from '../middleware/auth'; const router = Router(); -const prisma = new PrismaClient(); // ─── VOLUNTEER HOURS ───────────────────────────────────────────────────────── diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 17d3b31..3be4588 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -8,7 +8,7 @@ services: environment: POSTGRES_DB: owl_stream POSTGRES_USER: owl_user - POSTGRES_PASSWORD: ${DB_PASSWORD:-owl_secure_password} + POSTGRES_PASSWORD: ${DB_PASSWORD:?DB_PASSWORD must be set in .env} volumes: - owl_pg_data:/var/lib/postgresql/data networks: @@ -23,6 +23,10 @@ services: options: max-size: "10m" max-file: "3" + deploy: + resources: + limits: + memory: 256M owl-backend: build: @@ -34,11 +38,11 @@ services: owl-db: condition: service_healthy environment: - DATABASE_URL: postgresql://owl_user:${DB_PASSWORD:-owl_secure_password}@owl-db:5432/owl_stream - JWT_SECRET: ${JWT_SECRET:-owl_jwt_secret_change_me} + DATABASE_URL: postgresql://owl_user:${DB_PASSWORD:?DB_PASSWORD required}@owl-db:5432/owl_stream + JWT_SECRET: ${JWT_SECRET:?JWT_SECRET required} PORT: 3020 HOST: 0.0.0.0 - ALLOWED_ORIGINS: ${ALLOWED_ORIGINS:-http://localhost:8089} + ALLOWED_ORIGINS: ${ALLOWED_ORIGINS:-https://owls.bizzle.cloud,http://localhost:8089} ports: - "127.0.0.1:3020:3020" networks: @@ -71,6 +75,7 @@ services: - NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL:-http://127.0.0.1:3020} ports: - "127.0.0.1:8110:8089" + - "172.18.0.1:8110:8089" networks: - owl-network healthcheck: