A web application for the United Nations Political Unit (EOSG) to manage and create daily morning briefing entries. Built with Next.js 16, React 19, TypeScript, and Tailwind CSS.
- Entry Management: Create, edit, view, and delete morning briefing entries
- Rich Text Editor: Tiptap-based editor with formatting, links, images, and more
- Mobile-First Design: Fully responsive interface optimized for mobile and desktop
- Smart Editor Mode: Auto-detects device and defaults to plain text on mobile, rich text on desktop
- Draft Functionality: Save drafts and continue editing later
- Filter & Search: Advanced filtering by region, category, priority, and text search
- Approval Workflow: Mark entries as approved for export
- Export Options: Export daily briefings as Word documents or JSON
- Authentication: NextAuth.js with password-based authentication
- Database: PostgreSQL with Azure support
- Image Storage: Azure Blob Storage integration for image management
- Frontend: Next.js 16, React 19, TypeScript
- Styling: Tailwind CSS v4.1, shadcn/ui components
- Database: PostgreSQL
- Authentication: NextAuth.js
- Rich Text: Tiptap editor
- File Storage: Azure Blob Storage
- Export: DOCX generation and JSON
- Node.js 18+
- PostgreSQL database
- Azure Blob Storage account (optional, for image storage)
- Clone the repository:
git clone https://github.com/UN-EOSG-Analytics/un-morning-briefings.git
cd un-morning-briefings- Install dependencies:
npm install- Set up environment variables:
cp .env.example .env.localEdit .env.local with your configuration:
# Database
DATABASE_URL="postgresql://user:password@host:5432/database"
# Authentication
NEXTAUTH_SECRET=<generate-with: openssl rand -base64 32>
NEXTAUTH_URL=http://localhost:3000
SITE_PASSWORD=your-secure-password
# Azure Blob Storage
BLOB_STORAGE_TYPE=azure
AZURE_STORAGE_ACCOUNT=your-account
AZURE_STORAGE_KEY=your-key
AZURE_STORAGE_CONTAINER=container-name- Initialize the database:
npx ts-node sql/init.sql- Start the development server:
npm run devOpen http://localhost:3000 in your browser.
The application uses a pu_morning_briefings schema. Initialize with:
psql -U username -d database_name -f sql/init.sqlKey tables:
entries- Morning briefing entriesimages- Associated images
npm run dev # Start development server
npm run build # Build for production
npm start # Start production server
npm run lint # Run ESLint
npm run type-check # Run TypeScript type checkingsrc/
├── app/
│ ├── api/ # API routes (entries, auth, images)
│ ├── form/ # Form page for creating/editing entries
│ ├── list/ # List page to view entries
│ ├── drafts/ # Drafts page
│ ├── login/ # Login page
│ └── page.tsx # Homepage
├── components/
│ ├── ui/ # shadcn/ui components
│ ├── MorningMeetingForm.tsx
│ ├── MorningMeetingList.tsx
│ ├── RichTextEditor.tsx
│ ├── EntriesTable.tsx
│ ├── Navbar.tsx
│ └── ...other components
├── lib/
│ ├── db.ts # Database queries
│ ├── storage.ts # Entry management
│ ├── auth-helper.ts # Authentication utilities
│ └── ...other utilities
└── types/
└── morning-meeting.ts # TypeScript interfaces
The application uses NextAuth.js with a single shared password:
- Login Page:
/login - Site Password: Configure
SITE_PASSWORDin.env.local - Session Duration: 30 days
For details, see AUTHENTICATION.md
The application is fully responsive with mobile-first design:
- Editor Mode: Automatically switches between plain text (mobile) and rich text (desktop)
- Navigation: Hamburger menu on mobile
- Layout: Responsive grid layout that stacks on small screens
- Touch Targets: Optimized for mobile interaction
Fetch morning briefing entries with optional filters
Query Parameters:
date- Filter by date (YYYY-MM-DD)status- Filter by status (draft/submitted)author- Filter by author
Response:
[
{
"id": "uuid",
"headline": "Entry headline",
"entry": "Entry content",
"date": "2026-01-12T10:30:00",
"category": "category-name",
"priority": "sg-attention|situational-awareness",
"region": "region-name",
"country": "country-name",
"sourceUrl": "https://...",
"puNote": "Political unit note",
"status": "draft|submitted",
"approved": false,
"images": []
}
]Create a new morning briefing entry
Get a specific entry by ID
Update an entry
Delete an entry
Upload an image (multipart form)
- Use TypeScript for type safety
- Follow ESLint configuration
- Use Prettier for formatting
- Component names in PascalCase
- Use shadcn/ui components for consistency
npx shadcn@latest add component-nameEnsure your environment variables are set:
npm run check-env- Server Components for SSR where possible
- Client Components only for interactive elements
- Image optimization with Next.js Image component
- Code splitting and lazy loading
- Tailwind CSS purging unused styles
- Create a feature branch:
git checkout -b feature/your-feature - Commit changes:
git commit -am 'Add feature' - Push to branch:
git push origin feature/your-feature - Open a pull request
Proprietary - United Nations
For issues or questions, contact the Political Unit (EOSG).