Production deploy: stream API field mapping, Caddy domain config, systemd service, Docker bridge binding
This commit is contained in:
parent
c6b8fb752a
commit
8f4e5dea40
@ -43,6 +43,15 @@ export default async function DonatePage() {
|
||||
</p>
|
||||
</header>
|
||||
|
||||
{/* Coming soon notice */}
|
||||
<div className="bg-amber-500/10 border border-amber-500/30 rounded-2xl p-6 flex items-center gap-4">
|
||||
<span className="text-2xl">🚧</span>
|
||||
<div>
|
||||
<h3 className="font-bold text-amber-400 text-lg">Online Donations Coming Soon</h3>
|
||||
<p className="text-stone-400 text-sm">We're setting up secure payment processing. In the meantime, please visit <a href="https://ccfriendsofwildlife.org" className="text-teal underline" target="_blank" rel="noopener">ccfriendsofwildlife.org</a> to donate directly.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Impact banner */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-px bg-white/5 rounded-2xl overflow-hidden">
|
||||
{[
|
||||
|
||||
5
backend/src/lib/prisma.ts
Normal file
5
backend/src/lib/prisma.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
export default prisma;
|
||||
@ -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(),
|
||||
|
||||
@ -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) => {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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) => {
|
||||
|
||||
@ -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) => {
|
||||
|
||||
@ -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) => {
|
||||
|
||||
@ -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); }
|
||||
});
|
||||
|
||||
|
||||
@ -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 ─────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@ -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:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user