Youth Serving Christ (YCS) at St. Dominic Catholic Church — a full‑stack web application with a responsive website. The web app is built with React (Vite + Material UI) and the backend is Node.js + Express with PostgreSQL.
This document covers project structure, local setup (web and backend), PostgreSQL, deployment to Render (free tier), and recent feature updates (gallery albums/lightbox, admin thumbnails).
- Frontend (Web): React (Vite), React Router, Material UI, Framer Motion, Swiper, React Hook Form
- Backend: Node.js, Express, CORS, Static uploads
- Database: PostgreSQL
- Auth: JWT (localStorage)
- Deployment: Render (free tier), render.yaml blueprint
ibl_project/
├─ backend/
│ ├─ index.js # Express server entry
│ ├─ routes/
│ │ ├─ auth.js # /api/auth (login/register)
│ │ ├─ profile.js # /api/profile (now returns is_admin, email)
│ │ ├─ users.js # /api/users (admin)
│ │ ├─ blog.js # /api/blog
│ │ ├─ events.js # /api/events
│ │ ├─ leaders.js # /api/leaders
│ │ ├─ gallery.js # /api/gallery
│ │ └─ albums.js # /api/albums
│ ├─ uploads/ # uploaded files (served at /uploads)
│ └─ .env # backend environment (you create this)
│
├─ frontend/
│ ├─ public/
│ │ └─ images/ # static images, available at /images/*
│ ├─ src/
│ │ ├─ App.jsx # routes
│ │ ├─ main.jsx # ThemeProvider, CssBaseline
│ │ ├─ theme.js # MUI theme (colors, typography)
│ │ ├─ index.css # global CSS (self-host fonts, footer)
│ │ ├─ context/AuthContext.jsx
│ │ ├─ components/
│ │ │ ├─ Navbar.jsx # re-exports modular Navbar
│ │ │ ├─ Navbar/ # SRP refactor (logic + presentational)
│ │ │ │ ├─ index.jsx # orchestrator
│ │ │ │ ├─ useNavItems.js # role-aware items + isActive
│ │ │ │ ├─ NavbarBrand.jsx # logo/title/admin chip
│ │ │ │ ├─ NavbarLinks.jsx # desktop links
│ │ │ │ └─ NavbarDrawer.jsx # mobile drawer
│ │ │ ├─ Footer.jsx
│ │ │ ├─ Home.jsx, Blog.jsx, Events.jsx, Gallery.jsx
│ │ │ ├─ GalleryAlbums.jsx, GalleryAlbum.jsx # Albums list + album lightbox with keyboard nav and x-of-y
│ │ │ ├─ Register.jsx, Login.jsx, Profile.jsx, Members.jsx, Leaders.jsx
│ │ │ ├─ AdminDashboard.jsx
│ │ │ └─ Admin/* (management UIs)
│ └─ package.json # Vite scripts
│
└─ README.md # This file
- The previous
frontend/src/components/Navbar.jsxmixed navigation composition, active-route detection, drawer state, and UI. - Refactor split responsibilities:
- Logic:
frontend/src/components/Navbar/useNavItems.jsprovides role-aware items andisActive. - Presentational:
NavbarBrand.jsx,NavbarLinks.jsx,NavbarDrawer.jsx. - Orchestrator:
Navbar/index.jsxwires media query and handlers.
- Logic:
Navbar.jsxnow simply re-exports the modular Navbar to avoid changing import paths throughout the app.
Benefits: clearer structure, easier testing (logic vs UI), reusable nav items, simpler future changes to routes/active rules.
- Node.js 18+ and npm
- PostgreSQL 14+ (local or hosted)
- Git (optional)
-
Create a PostgreSQL database and user
-- from psql or any SQL client CREATE DATABASE ycs_st_dominic; CREATE USER ycs_user WITH ENCRYPTED PASSWORD 'strong_password_here'; GRANT ALL PRIVILEGES ON DATABASE ycs_st_dominic TO ycs_user;
-
Create required tables (suggested schema)
You can adapt these tables to match your exact needs. These align with API endpoints used by the frontend.
-- users CREATE TABLE IF NOT EXISTS users ( id SERIAL PRIMARY KEY, username VARCHAR(100) UNIQUE NOT NULL, email VARCHAR(255) UNIQUE NOT NULL, password_hash TEXT NOT NULL, is_admin BOOLEAN DEFAULT FALSE, created_at TIMESTAMP DEFAULT NOW() ); -- profiles (1:1 with users) CREATE TABLE IF NOT EXISTS profiles ( id SERIAL PRIMARY KEY, user_id INT REFERENCES users(id) ON DELETE CASCADE, name VARCHAR(150), bio TEXT, picture_url TEXT ); -- leaders CREATE TABLE IF NOT EXISTS leaders ( id SERIAL PRIMARY KEY, name VARCHAR(150) NOT NULL, position VARCHAR(150), bio TEXT, picture_url TEXT ); -- blog posts CREATE TABLE IF NOT EXISTS blog ( id SERIAL PRIMARY KEY, title VARCHAR(255) NOT NULL, content TEXT NOT NULL, picture_url TEXT, date TIMESTAMP DEFAULT NOW() ); -- events CREATE TABLE IF NOT EXISTS events ( id SERIAL PRIMARY KEY, title VARCHAR(255) NOT NULL, description TEXT, date DATE NOT NULL, picture_url TEXT ); -- gallery images (optional album_id) CREATE TABLE IF NOT EXISTS albums ( id SERIAL PRIMARY KEY, title VARCHAR(255) NOT NULL, date DATE, cover_url TEXT ); CREATE TABLE IF NOT EXISTS gallery ( id SERIAL PRIMARY KEY, album_id INT REFERENCES albums(id) ON DELETE SET NULL, caption TEXT, picture_url TEXT NOT NULL, created_at TIMESTAMP DEFAULT NOW() );
Note: The frontend determines “upcoming” by checking if an event date is in the future, or your backend can expose
is_futurein its API response. -
Backend environment variables (
backend/.env)Create a
.envfile inbackend/:PORT=5000 DATABASE_URL=postgres://ycs_user:strong_password_here@localhost:5432/ycs_st_dominic JWT_SECRET=replace_with_a_long_random_string CORS_ORIGIN=http://localhost:5173 UPLOAD_DIR=uploads
-
Install backend dependencies & run (from
backend/)npm install npm run start # or: node index.jsThe server will start on
http://localhost:5000.
Admin profile parity:
profile.jsnow includesis_adminandSELECTandRETURNING, so both web and mobile can render an Admin Dashboard link/tab when appropriate.
Note: Backend routes include auth, profile, users, blog, events, leaders, gallery, and albums per the repository structure above. Ensure CORS is configured for both your dev web origin and your mobile app usage during local dev.
-
Configure fonts & images
- Self‑hosted font is already configured in
frontend/src/index.cssvia@font-face(Ubuntu Mono). No external calls needed. - Put static images into
frontend/public/images/. They are served at/images/....
- Self‑hosted font is already configured in
-
Install frontend dependencies & run (from
frontend/)npm install npm run dev
Vite will print a local dev URL like
http://localhost:5173. -
Environment variables (Frontend)
- By default, frontend makes relative calls (e.g.,
/api/...). If your backend runs on another port, use a Vite proxy or setVITE_API_BASE_URLin an.envand read it in your axios config.
- By default, frontend makes relative calls (e.g.,
-
Build for production
npm run build npm run preview # serves the production build locally
-
Start Vite listening on all interfaces:
npm run dev -- --host 0.0.0.0 --port 5173
-
On another device (same network), open:
http://YOUR_COMPUTER_IP:5173 -
Windows firewall may need to allow Node.js (or the terminal) on Private networks.
-
Optional scripts to add in
frontend/package.json:{ "scripts": { "dev:lan": "vite --host 0.0.0.0 --port 5173", "preview:lan": "vite preview --host 0.0.0.0 --port 4173" } }
- Hero section on
Home.jsxwith background image, call‑to‑action buttons. - Blog carousel using Swiper (Autoplay, Navigation, Pagination) and linking to
/blog/:id. - Gallery albums and lightbox
- Albums grid (
GalleryAlbums.jsx) and per‑album grid (GalleryAlbum.jsx). - Lightbox with previous/next, image preloading, zoom/pan, and keyboard navigation (Left/Right/Escape).
- Footer shows “x of y” indicator and caption.
- Albums grid (
- Upcoming events showing soonest 3 events.
- Responsive UI with Material UI’s theme (
frontend/src/theme.js), responsive typography, and Drawer navigation for small screens. - Self‑hosted fonts (
Ubuntu Mono).
Admin UX
- Navbar shows an “Admin Dashboard” link and an Admin chip when
user.is_adminis true.
The frontend calls:
GET /api/blog→[ { id, title, content, picture_url, date } ]GET /api/events→[ { id, title, description, date, picture_url } ]GET /api/gallery→[ { id, album_id, caption, picture_url, created_at } ]GET /api/albums→[ { id, title, date, cover_url } ]GET /api/leaders→[ { id, name, position, bio, picture_url } ]GET /api/users(admin) → users listPOST /api/auth/login→{ token, user }POST /api/auth/register→{ token, user }GET/PUT /api/profile→ current user profile
If your current backend is missing some of these routes, add them to match the UI. The provided SQL schemas above are a good starting point.
- Backend serves files from
backend/uploads/at/uploads/*. - You can store user‑uploaded images (e.g., profile photos, gallery) there and save their URLs in PostgreSQL.
- Theme is defined in
frontend/src/theme.js(brown + beige palette) and applied infrontend/src/main.jsxviaThemeProviderandCssBaseline. - Global CSS lives in
frontend/src/index.css(footer behavior, self‑hosted fonts, variables).
- Hot reload: Vite will hot‑reload when you edit frontend files.
- Error boundaries: Consider adding an error boundary around major routes (React 18+ error handling guidance).
- Network errors: If API calls fail, ensure backend CORS allows the frontend origin and both servers are running.
- Placeholders: Replace placeholder images in
frontend/public/images/with real assets.
You can deploy the frontend (static build) to any static host (Netlify, Vercel, S3 + CloudFront). The backend can be deployed to a VPS or PaaS (Railway, Render, Fly.io, Heroku successor platforms). Render free‑tier is supported via render.yaml in this repo. Make sure to:
- Set backend
.envwith productionDATABASE_URLandJWT_SECRET. - Serve uploads from a durable storage (S3, local volume, or shared disk), and point picture URLs accordingly.
- Configure CORS for your production frontend domain.
The mobile app mirrors the website with UI/feature parity and adds native UX.
Key features
- Admin tab (visible only when
is_adminis true). - Gallery albums and pinch‑to‑zoom viewer (
react-native-image-viewing) with “x of y” indicator. - Admin lists show thumbnails (Blogs, Events, Leaders).
- Events use native
@react-native-community/datetimepicker. - Consistent typography/spacing with React Native Paper theme.
Install & run (from mobile/)
npm install
npm start
# Press "a" to open Android emulatorLocal API configuration
mobile/app.jsondefinesexpo.extra.apiBaseUrl.- When using Android emulator to access your dev backend on the same machine, use
http://10.0.2.2:5000as the base URL.
Auth & profile
- JWT is stored in
SecureStore. - After startup/login, the app calls
/api/profileto fetch authoritativeis_adminand user fields (fallback tojwt-decodeif needed).
Packages of note
react-native-image-viewing,@react-native-community/datetimepicker,@react-navigation/*,react-native-paper,expo-secure-store,@expo/vector-icons.
This repo includes render.yaml for the free tier.
Web service
- plan:
free. - buildCommand: install backend, then frontend with dev dependencies to ensure Vite is available, e.g.
cd backend && npm install && cd ../frontend && npm install --include=dev && npm run build
- startCommand: run DB migrations at boot (free tier has no persistent disk for cron jobs), then start server, e.g.
cd backend && npm run migrate && node server.js
Database
- PostgreSQL plan:
free.
Notes
- Ensure CORS is configured for your production frontend.
- Store uploads on durable storage for production (S3 or persistent volume). Free tier ephemeral storage may be wiped on redeploy.
Security/Repo hygiene
.gitignoreincludes environment files (.env, variants), keys/certs, caches, and build artifacts.- The entire
mobile/workspace is ignored for this repository to prevent committing large platform-specific build directories or secrets from mobile tooling.
- Vite can’t resolve Swiper: run
npm installinfrontend/and restart dev server. - Port conflicts: change Vite port
--port 5174or backendPORT. - CORS errors: set
CORS_ORIGINto your frontend URL. - LAN access fails: check Windows firewall and that devices share the same network.
- Android emulator can’t reach backend: use
http://10.0.2.2:5000inmobile/app.json. - Expo datetime picker peer dependency: pinned
@react-native-community/datetimepicker@^7.6.3for Expo SDK 51. - Render build fails: vite not found: ensure
npm install --include=devruns beforenpm run buildfor the frontend.
Private/internal. All rights reserved.