Skip to content

UN-EOSG-Analytics/un80-sg-reports-survey

Repository files navigation

UN Website Boilerplate (with Auth)

A Next.js template with UN branding and magic link authentication.

Based on: https://github.com/kleinlennart/un-website-boilerplate

Features

  • UN branding (logo, colors, Roboto font)
  • Magic link authentication (configurable email domains via DB)
  • Rate limiting on magic link requests (2 min cooldown)
  • 30-day session duration
  • PostgreSQL session/user storage
  • Configurable database schema per app
  • Entity selection on first login (with "Other" option)
  • Entity change dialog (click entity badge in header)
  • Public landing page (/about) + protected dashboard (/)

Setup

1. Install dependencies

npm install

2. Configure environment

cp .env.template .env.local

Edit .env.local:

  • DATABASE_URL - PostgreSQL connection string
  • DB_SCHEMA - Schema for auth tables (e.g. sg_reports_surveysg_reports_survey.users, sg_reports_survey.magic_tokens)
  • AUTH_SECRET - Generate with openssl rand -hex 32
  • SMTP_* - Mail server for magic links
  • BASE_URL - Your app URL (for magic link emails)

3. Create database tables

Edit sql/auth_tables.sql and replace sg_reports_survey with your schema name (must match DB_SCHEMA), then:

psql $DATABASE_URL -f sql/auth_tables.sql

The schema includes an allowed_domains table pre-populated with UN system domains (un.org, undp.org, unicef.org, who.int, etc.). Edit the SQL to remove domains you don't need, or add custom ones:

-- Add a custom domain
INSERT INTO myapp.allowed_domains (entity, domain) VALUES
  ('*', 'example.org'),        -- global: allow for all entities
  ('PARTNER', 'partner.org');  -- entity-specific

4. Run

npm run dev

Open http://localhost:3000 with your browser.

Auth Flow

  1. User visits /about (public landing page)
  2. User clicks "Sign In" → /login
  3. User enters email, magic link sent (rate limited: 2 min cooldown)
  4. User clicks link → /verify?token=...
  5. First login: select entity (combobox with "Other" option); returning users: direct sign-in
  6. Session cookie set (30 days)
  7. Header shows user email, clickable entity badge (to change), and logout
  8. Unauthenticated users accessing protected routes → redirect to /about

Customization

  • Site title/subtitle: Edit SITE_TITLE and SITE_SUBTITLE in src/components/Header.tsx
  • Allowed email domains: Add to allowed_domains table in database
  • Entity list: Query in fetchEntities() in src/app/api/entities/route.ts
  • Document search: Query in src/app/api/documents/search/route.ts
  • Protected routes: Edit PUBLIC_PATHS in src/middleware.ts
  • Auth schema: Set DB_SCHEMA env var and update sql/auth_tables.sql

File Structure

src/
├── app/
│   ├── about/                # Public landing page
│   ├── api/
│   │   ├── auth/             # Auth API routes (backup, actions preferred)
│   │   ├── documents/search/ # Document search
│   │   └── entities/         # Entity list + fetchEntities()
│   ├── login/                # Login page + layout
│   ├── verify/               # Token verification + entity selection
│   └── page.tsx              # Protected dashboard
├── components/
│   ├── DocumentSearch.tsx    # Document autocomplete
│   ├── EntityChangeDialog.tsx # Dialog to change entity
│   ├── EntityCombobox.tsx    # Entity dropdown with "Other" option
│   ├── EntitySearch.tsx      # Entity autocomplete (for search)
│   ├── Footer.tsx            # Site footer
│   ├── Header.tsx            # Site header with maxWidth, hideAbout props
│   ├── LoginForm.tsx         # Login form (uses server actions)
│   ├── UserMenu.tsx          # Email + entity badge + logout
│   └── VerifyForm.tsx        # Verify form with returning user detection
├── lib/
│   ├── actions.ts            # Server actions for auth
│   ├── auth.ts               # Auth logic (isAllowedDomain, sessions, etc.)
│   ├── config.ts             # DB_SCHEMA config + table names
│   ├── db.ts                 # PostgreSQL pool
│   ├── mail.ts               # Magic link emails
│   └── utils.ts              # Tailwind cn() helper
└── middleware.ts             # Route protection
sql/
└── auth_tables.sql           # Database schema (users, tokens, allowed_domains)

Maintenance

Check for issues

npm audit          # Security vulnerabilities
npm outdated       # Outdated packages
npm run lint       # ESLint errors
npx tsc --noEmit   # TypeScript errors

Update packages

npm update                                              # Safe patch/minor updates
npm install next@latest eslint-config-next@latest       # Update Next.js

Clean install (if issues occur)

rm -rf node_modules .next && npm install

Good to know

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •