Backend API for the Project Application and Funding Service (PAFS) - RESTful APIs for managing flood and coastal erosion risk management projects.
Purpose: RESTful API for user authentication, authorization, and data management
Tech Stack:
- Node.js 22 + Hapi.js 21
- PostgreSQL 16 (Aurora Serverless V2) + Prisma ORM
- Liquibase 4.25 for schema migrations
- JWT authentication + bcrypt
- Vitest + Docker + CDP deployment
Key Features:
- User authentication and authorization
- Account provisioning workflow
- Role-based access control
- Database schema versioning
- Health check endpoints
- Requirements
- Quick Start
- VS Code Setup
- Database Migrations
- Development
- Schema Changes
- Docker
- Environment Variables
- Deployment
- Related Links
- Licence
Node.js: >= 22
npm: >= 11
PostgreSQL: >= 16
Liquibase: 4.25 (via Docker or standalone)
Install Node.js:
# Using nvm (recommended)
nvm install 22
nvm use 22Install PostgreSQL:
# Mac
brew install postgresql@16
# Linux
sudo apt-get install postgresql-16
# Windows: Download from postgresql.org# Clone repository
git clone https://github.com/DEFRA/pafs-backend-api.git
cd pafs-backend-api
# Install dependencies
nvm use # Use Node version from .nvmrc
npm install
# Setup database
psql -U postgres
CREATE DATABASE pafs_backend_local;
CREATE USER pafs_user WITH PASSWORD 'pafs_password';
GRANT ALL PRIVILEGES ON DATABASE pafs_backend_local TO pafs_user;
\q
# Configure Liquibase
cp liquibase.properties.template liquibase.properties
# Edit liquibase.properties with your credentials
# Run migrations
npm run db:migrate
# Start development server
npm run devApplication runs at http://localhost:3001
Recommended for debugging and development.
Create .vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Dev Server",
"runtimeExecutable": "npm",
"runtimeArgs": ["run", "dev"],
"skipFiles": ["<node_internals>/**"],
"console": "integratedTerminal",
"env": {
"NODE_ENV": "development",
"PORT": "3001"
}
}
]
}Run: Press F5 or use Run and Debug panel
Location: prisma/schema.prisma
Purpose: Type-safe database access with auto-generated client
- Pull schema from database (via VS Code) → Generates
schema.prismafrom existing database - Generate Prisma Client (via npm) → Creates type-safe client for database access
Use VS Code launch configuration to pull schema:
Add to .vscode/launch.json:
{
"type": "node",
"request": "launch",
"name": "PAFS Backend API - Prisma Pull",
"skipFiles": ["<node_internals>/**"],
"runtimeExecutable": "npm",
"runtimeArgs": ["run", "prisma:db:pull"],
"console": "integratedTerminal",
"env": {
"DB_HOST": "127.0.0.1",
"DB_PORT": "5432",
"DB_DATABASE": "pafs_backend_api",
"DB_USERNAME": "postgres",
"DB_PASSWORD": "pgadmin",
"DB_USE_IAM_AUTHENTICATION": "false"
}
}Run: Press F5 and select "PAFS Backend API - Prisma Pull"
This pulls the database schema and generates/updates prisma/schema.prisma file.
After pulling schema, generate the Prisma Client:
npm run prisma:generateThis generates the type-safe Prisma Client based on your schema.
Note: This runs automatically on npm install (postinstall hook)
Important:
- Run
prisma:db:pullvia VS Code to generate schema from database - Run
prisma:generatevia npm to create Prisma Client - Prisma works alongside Liquibase (Liquibase manages migrations, Prisma provides type-safe access)
Tool: Liquibase 4.25
Location: changelog/ directory
Format: XML changesets
Setup:
# Copy template
cp liquibase.properties.template liquibase.properties
# Edit liquibase.properties with your database credentialsRun Migrations:
Option 1: Using Docker
# Interactive shell (recommended for multiple commands)
docker run -it --rm --network host \
-v "$(pwd):/liquibase/workspace" \
-w /liquibase/workspace \
liquibase/liquibase:4.25 sh
# Then inside container:
liquibase --defaults-file=liquibase.properties validate
liquibase --defaults-file=liquibase.properties status
liquibase --defaults-file=liquibase.properties update
exit
# Or single command:
docker run --rm --network host \
-v "$(pwd):/liquibase/workspace" \
-w /liquibase/workspace \
liquibase/liquibase:4.25 \
--defaults-file=liquibase.properties updateOption 2: Using Podman
# Interactive shell
podman run -it --rm --network host \
-v "$(pwd):/liquibase/workspace:Z" \
-w /liquibase/workspace \
liquibase/liquibase:4.25 sh
# Then inside container:
liquibase --defaults-file=liquibase.properties validate
liquibase --defaults-file=liquibase.properties status
liquibase --defaults-file=liquibase.properties update
exit
# Or single command:
podman run --rm --network host \
-v "$(pwd):/liquibase/workspace:Z" \
-w /liquibase/workspace \
liquibase/liquibase:4.25 \
--defaults-file=liquibase.properties updateOption 3: Using standalone Liquibase
liquibase --defaults-file=liquibase.properties updateImportant Notes:
- For Docker/Podman on Windows/Mac: Use
host.docker.internalinliquibase.propertiesinstead oflocalhost - For Podman: The
:Zflag is required for SELinux contexts - For standalone Liquibase: Download from liquibase.org
Run Development Server:
npm run dev # Nodemon with hot reloadRun Tests:
npm test # Run tests with coverage
npm run test:watch # Watch modeAvailable Scripts:
npm run dev # Development server
npm start # Production server
npm test # Run tests
npm run lint # Lint code
npm run format # Format codeCreate New Changeset:
- Add XML file to
changelog/ - Follow naming:
{version}-{sequence}-{description}.xml - Test locally with
npm run db:migrate - Create PR (automatic validation runs)
- After merge, publish via GitHub Actions
Automatic Validation:
- PR checks validate changelog syntax
- Runs migration on test database
- Ensures no broken migrations
Build:
# Development
docker build --target development -t pafs-backend-api:dev .
# Production
docker build -t pafs-backend-api .Run:
docker run -p 3001:3001 pafs-backend-api| Variable | Description | Default |
|---|---|---|
NODE_ENV |
Environment | development |
PORT |
Server port | 3001 |
LOG_LEVEL |
Log level | info |
DATABASE_URL |
PostgreSQL connection | - |
JWT_SECRET |
JWT signing secret | - |
CDP Environments: Manage secrets via CDP Portal
Automated (GitHub Actions):
- Push to
main→ Build & test - Tests pass → Docker image built
- Image published to CDP
- Deploy via CDP Portal
Manual:
- CDP Portal → Select service → Choose environment → Deploy
THIS INFORMATION IS LICENSED UNDER THE CONDITIONS OF THE OPEN GOVERNMENT LICENCE found at:
http://www.nationalarchives.gov.uk/doc/open-government-licence/version/3
The following attribution statement MUST be cited in your products and applications when using this information.
Contains public sector information licensed under the Open Government license v3