# 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 (001–056) │ └── 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.