A modern, full-stack web platform for the Guild of Physics, built with Next.js, Payload CMS, and PostgreSQL.
This project is designed for extensibility, internationalization, and rich content management.
- Node.js: v18.20.2 or >=20.9.0
- pnpm: v10+
- Docker (optional, for containerized development/production)
- PostgreSQL: (if not using Docker Compose's built-in service)
git clone <repo-url>
cd fk-webpnpm installCreate a .env file in the root directory.
Required variables (see codebase for more, depending on features used):
# Server and site
NEXT_NEXT_PUBLIC_SERVER_URL=http://localhost:3000
# Database
DATABASE_URI=postgres://user:password@localhost:5432/dbname
# Payload CMS
PAYLOAD_SECRET=your-secret
# Email (SMTP)
EMAIL_FROM_NAME=Fyysikkokilta
EMAIL_FROM_ADDRESS=your@email.com
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=your-smtp-user
SMTP_PASSWORD=your-smtp-password
# Google APIs
GOOGLE_API_KEY=your-google-api-key
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
GOOGLE_SITE_VERIFICATION=your-google-site-verification
# OAuth
ALLOW_NON_EXISTING_USERS=false
# S3
S3_BUCKET=...
S3_ACCESS_KEY_ID=...
S3_SECRET=...
S3_ENDPOINT=...
NEXT_PUBLIC_S3_PUBLIC_URL=...
# Form builder
FORM_BUILDER_DEFAULT_TO_EMAIL=...
# Job Queue
JOB_QUEUE_SECRET=your-job-queue-secret
# Analyze bundle (optional)
ANALYZE=true- By default, the project expects a PostgreSQL database.
- You can use Docker Compose to spin up the app and (optionally) a database.
Uncomment the postgres service in docker-compose.yml if you want to use the built-in database.
docker-compose up --build- Create a PostgreSQL database and user.
- Set
DATABASE_URIaccordingly in your.env.
pnpm devpnpm build
pnpm startOr use Docker:
docker build -t fk-web .
docker run -p 3000:3000 --env-file .env fk-websrc/
app/ # Next.js app directory (frontend routes, layouts, API)
(frontend)/ # Main frontend, locale-based routing
(payload)/ # Payload CMS admin interface
blocks/ # Reusable content blocks (Calendar, TwoColumns, etc.)
collections/ # Payload CMS collections (Pages, Newsletters, Media, etc.)
components/ # Shared React components (RichText, Navigation, etc.)
emails/ # Email templates
fields/ # Custom Payload field configs
globals/ # Global site settings (Footer, Navigation, etc.)
hooks/ # Custom hooks for Payload/Next.js
lib/ # Utility libraries (calendar, etc.)
utils/ # Utility functions
payload.config.ts # Payload CMS configuration
payload-types.ts # Auto-generated Payload types
- Next.js (App Router, SSR, i18n)
- Payload CMS (headless CMS, admin UI, API)
- PostgreSQL (database)
- Tailwind CSS (utility-first styling)
- date-fns (date utilities)
- lucide-react (icon set)
- next-intl (internationalization)
- S3 (Cloudflare) (cloud storage, optional)
- Plaiceholder (image placeholders)
- React Hook Form (forms)
- Nodemailer (email via Payload plugin)
- Payload Plugins: SEO, Redirects, Form Builder, Import/Export, Storage, etc.
- Calendar: Google Calendar integration, color-coded events
- TwoColumns: Responsive two-column layout
- Align: Horizontally align and set width for rich text content
- Newsletter: Newsletter content and settings
- PDFViewer: Embed PDFs
- BoardMemberGrid: Display board members
- Collapsible: Expand/collapse content
- EmbedVideo: YouTube/Vimeo embeds
- ...and more
- Uses pnpm for package management.
- Uses ESLint and Prettier for code style.
- Uses Docker for production and local development.
- All media and document uploads are stored in
/public/mediaand/public/documents(volumes in Docker). - Rich text editing is powered by Payload's Lexical editor.
The project uses Payload CMS's built-in job queue system for handling background tasks like newsletter sending and scheduled publishing.
Jobs are configured in src/payload.config.ts and can be triggered via API endpoints.
Jobs can be executed using the /api/payload-jobs/run endpoint:
# Trigger a job via API
curl -X POST http://localhost:3000/api/payload-jobs/run \
-H "Content-Type: application/json" \
-H "x-job-queue-secret: your-job-queue-secret" \
-d '{"task": "sendNewsletter", "data": {"newsletterId": 123}}'- schedulePublish: Handles scheduled content publishing
- sendNewsletter: Sends newsletters to subscribers
JOB_QUEUE_SECRET: Secret key for API authentication (required for job execution)
For more information, see the Payload CMS Jobs Queue documentation.
pnpm dev– Start development serverpnpm build– Build for productionpnpm start– Start production serverpnpm lint– Lint codepnpm generate:types– Generate Payload typespnpm generate:importmap– Generate import map for Payload
MIT