UMBRA/README.md
Kyle Pope 7903e454dc Strip detailed security internals from README
Reduces the security section to a brief summary without exposing
specific middleware names, rate limit thresholds, lockout parameters,
or implementation details that could aid threat actors.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 01:43:39 +08:00

239 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# UMBRA
A self-hosted, multi-user life administration app with a dark-themed UI and role-based access control. Manage your todos, calendar events, projects, reminders, contacts, and locations from a single dashboard.
## Features
- **Multi-user RBAC** — Admin and standard user roles, per-user data isolation, admin portal with IAM, system config, and audit logs
- **Dashboard** — Contextual greeting, week timeline, stat cards, upcoming events, weather widget, day briefing
- **Todos** — Task management with priorities, due dates, recurrence, and grouped sections (overdue/today/upcoming)
- **Calendar** — Multi-calendar system with month/week/day views, recurring events, drag-and-drop, event templates, shared calendars with permission-based access
- **Shared Calendars** — Invite connections to calendars with granular permissions (read-only, create/modify, full access). Event locking prevents concurrent edits. Near-real-time sync via 5s polling
- **Event Invitations** — Invite connections to individual events with RSVP (accept/tentative/decline), per-occurrence status overrides for recurring events, display calendar assignment, and optional edit access via can_modify toggle
- **Projects** — Project boards with kanban view, nested tasks/subtasks, comments, progress tracking
- **Reminders** — Time-based reminders with snooze, dismiss, recurrence, and real-time alert notifications (dashboard banner + toasts)
- **People & Connections** — Contact directory with avatar initials, favourites, birthday tracking. Social connections via umbral name search with bidirectional Person records on accept
- **Locations** — Location management with OSM search integration, category filtering, frequent locations
- **Weather** — Dashboard weather widget with temperature, conditions, and contextual rain warnings
- **Settings** — Accent color picker (8 presets), first day of week, weather city, ntfy push notifications, TOTP two-factor auth, auto-lock, password management
- **Notifications** — In-app notification centre with toast popups, plus ntfy push notifications for reminders (configurable per-user)
- **Admin Portal** — User management (create, delete, activate/deactivate, role assignment, password reset), system configuration (open registration, MFA enforcement), audit log viewer
## Tech Stack
| Layer | Technology |
|--------------|------------|
| Frontend | React 18, TypeScript, Vite 6, Tailwind CSS 3 |
| UI Components | Custom shadcn/ui-style components, FullCalendar 6, Lucide icons, Sonner toasts |
| Fonts | Sora (headings), DM Sans (body) via Google Fonts |
| State | TanStack Query v5, React Router v6 |
| Backend | FastAPI, Python 3.12, Pydantic v2 |
| Database | PostgreSQL 16, SQLAlchemy 2.0 (async), Alembic (56 migrations) |
| Auth | Argon2id hashing, DB-backed sessions (signed httpOnly cookies), TOTP MFA, CSRF middleware, role-based access control |
| Scheduler | APScheduler (async) for ntfy notification dispatch |
| Deployment | Docker Compose (3 services), Nginx reverse proxy |
## Quick Start
### Prerequisites
- [Docker](https://docs.docker.com/get-docker/) and [Docker Compose](https://docs.docker.com/compose/install/)
### Setup
1. **Clone the repository**
```bash
git clone https://your-gitea-instance/youruser/umbra.git
cd umbra
```
2. **Configure environment variables**
```bash
cp .env.example .env
```
Edit `.env` and set secure values (see [Production Hardening](#production-hardening) below for generation commands):
```env
POSTGRES_USER=umbra
POSTGRES_PASSWORD=your-secure-password
POSTGRES_DB=umbra
DATABASE_URL=postgresql+asyncpg://umbra:your-secure-password@db:5432/umbra
SECRET_KEY=your-random-secret-key
OPENWEATHERMAP_API_KEY=your-openweathermap-api-key
```
> **Weather widget**: The dashboard weather widget requires a free [OpenWeatherMap](https://openweathermap.org/api) API key. Set `OPENWEATHERMAP_API_KEY` in `.env`, then configure your city in Settings.
3. **Build and run**
```bash
docker-compose up --build
```
4. **Open the app**
Navigate to `http://localhost` in your browser. On first launch you'll be prompted to create an admin account.
## Architecture
```
+-----------+
| Browser |
+-----+-----+
|
port 80 (HTTP)
|
+-------+-------+
| Nginx |
| (frontend) |
| non-root:8080 |
+---+-------+---+
| |
static | | /api/*
files | | (rate-limited auth)
v v
+---+-------+---+
| FastAPI |
| (backend) |
| non-root |
+-------+-------+
|
+-------+-------+
| PostgreSQL |
| (db) |
| port 5432 |
+---------------+
```
- **Frontend** is built as static files and served by `nginxinc/nginx-unprivileged`. Nginx also reverse-proxies API requests to the backend with rate limiting on auth endpoints.
- **Backend** runs Alembic migrations on startup as a non-root user (`appuser`), then serves the FastAPI application with `--no-server-header`.
- **Database** uses a named Docker volume (`postgres_data`) for persistence.
- **Backend port 8000 is not exposed externally** — only accessible via the internal Docker network.
## Security
UMBRA is hardened by default with multi-user data isolation, role-based access control, CSRF protection, non-root containers, rate limiting, account lockout, optional TOTP MFA, and secure session management. Multiple penetration tests have been conducted with no exploitable findings.
### Production Hardening
Before deploying to production, generate secure values for your `.env`:
```bash
# Generate a secure SECRET_KEY (64-char hex string)
python3 -c "import secrets; print(secrets.token_hex(32))"
# Generate a secure database password
python3 -c "import secrets; print(secrets.token_urlsafe(24))"
```
Additionally for production:
- Set `ENVIRONMENT=production` — disables API docs and auto-enables HTTPS-only session cookies
- Place behind a reverse proxy with TLS termination (e.g., Caddy, Traefik, or nginx with Let's Encrypt)
- Set `CORS_ORIGINS` to your actual domain (e.g., `https://umbra.example.com`)
## API Overview
All endpoints require authentication (signed session cookie) except auth routes and the health check. Admin endpoints require the `admin` role.
| Endpoint | Description |
|-----------------------|-------------|
| `GET /health` | Health check |
| `/api/auth/*` | Login, logout, setup, register, status, password change, TOTP MFA |
| `/api/admin/*` | User management, system config, audit logs (admin only) |
| `/api/todos/*` | Todos CRUD + toggle completion |
| `/api/events/*` | Calendar events CRUD (incl. recurring) + event invitations |
| `/api/event-invitations/*` | Invitation responses, per-occurrence overrides, can_modify toggle, leave |
| `/api/event-templates/*` | Event templates CRUD |
| `/api/calendars/*` | User calendars CRUD + visibility |
| `/api/shared-calendars/*` | Shared calendar management, invitations, permissions, event locking |
| `/api/reminders/*` | Reminders CRUD + dismiss + snooze + due alerts |
| `/api/projects/*` | Projects + nested tasks + comments CRUD |
| `/api/people/*` | People CRUD |
| `/api/locations/*` | Locations CRUD + search |
| `/api/settings/*` | App settings + ntfy config |
| `/api/dashboard` | Dashboard aggregation |
| `/api/upcoming` | Unified upcoming items feed |
| `/api/weather/*` | Weather data proxy |
| `/api/connections/*` | Social connections (search, request, respond, manage) |
| `/api/notifications/*` | In-app notifications (list, read, delete) |
API documentation is available at `/api/docs` (Swagger UI) when `ENVIRONMENT=development`.
## Development
### Rebuild a single service
```bash
docker-compose up --build backend # Backend only
docker-compose up --build frontend # Frontend only
```
### View logs
```bash
docker-compose logs -f # All services
docker-compose logs -f backend # Backend only
```
### Reset database
```bash
docker-compose down -v && docker-compose up --build
```
### Stop all services
```bash
docker-compose down
```
## Project Structure
```
umbra/
├── docker-compose.yaml
├── .env / .env.example
├── backend/
│ ├── Dockerfile
│ ├── requirements.txt
│ ├── alembic.ini
│ ├── alembic/versions/ # 56 migrations (001056)
│ └── app/
│ ├── main.py # FastAPI app, CSRF middleware, router registration, health endpoint
│ ├── config.py # Pydantic BaseSettings (DATABASE_URL, SECRET_KEY, CORS, etc.)
│ ├── database.py # Async SQLAlchemy engine + session factory
│ ├── models/ # 20 SQLAlchemy ORM models (incl. User, UserSession, EventInvitation, CalendarMember)
│ ├── schemas/ # 14 Pydantic v2 request/response schema modules
│ ├── routers/ # 16 API route handlers (incl. auth, admin, event_invitations, shared_calendars)
│ ├── services/ # Auth (Argon2id), recurrence, TOTP, ntfy, audit, calendar_sharing, event_invitation, notification
│ └── jobs/ # APScheduler notification dispatch
└── frontend/
├── Dockerfile
├── nginx.conf
├── proxy-params.conf # Shared proxy settings (DRY include)
├── package.json
└── src/
├── App.tsx # Routes, ProtectedRoute, AdminRoute auth guards
├── lib/ # api.ts (axios + 401 interceptor), date-utils.ts, utils.ts
├── hooks/ # useAuth, useAdmin, useSettings, useTheme, useCalendars, useConfirmAction, useConnections, useNotifications, useEventInvitations
├── types/ # TypeScript interfaces
└── components/
├── ui/ # 18 base components (Button, Dialog, Sheet, Card, Input, Select, Switch, DatePicker, ...)
├── shared/ # EntityTable, EntityDetailPanel, CategoryFilterBar, CategoryAutocomplete, CopyableField
├── layout/ # AppLayout, Sidebar, LockOverlay
├── auth/ # LockScreen, AmbientBackground
├── admin/ # AdminPortal, IAMPage, ConfigPage, AdminDashboardPage, CreateUserDialog, UserActionsMenu
├── dashboard/ # DashboardPage + 8 widgets
├── calendar/ # CalendarPage, CalendarSidebar, EventDetailPanel, InviteeSection, LeaveEventDialog, CalendarForm, EventForm, TemplateForm
├── todos/ # TodosPage, TodoList, TodoItem, TodoForm, TodoDetailPanel
├── reminders/ # RemindersPage, ReminderList, ReminderItem, ReminderForm, SnoozeDropdown, AlertBanner
├── projects/ # ProjectsPage, ProjectCard, ProjectDetail, ProjectForm, KanbanBoard, TaskRow, TaskForm, TaskDetailPanel
├── people/ # PeoplePage, PersonForm
├── connections/ # ConnectionSearch, ConnectionRequestCard, ConnectionsTab
├── notifications/ # NotificationsPage, NotificationToaster
├── locations/ # LocationsPage, LocationForm
└── settings/ # SettingsPage, NtfySettingsSection, TotpSetupSection
```
## License
This project is for personal use. Feel free to fork and adapt for your own needs.