Code changes (S-01, S-02, S-05):
- DRY nginx proxy blocks via shared proxy-params.conf include
- Add ENVIRONMENT and CORS_ORIGINS to .env.example
- Remove unused X-Requested-With from CORS allow_headers
Documentation updates:
- README.md: reflect auth upgrade, security hardening, production
deployment guide with secret generation commands, updated architecture
diagram, current project structure and feature list
- CLAUDE.md: codify established dev workflow (branch → implement →
test → QA → merge), update auth/infra/stack sections, add authority
links for progress.md and ntfy.md
- progress.md: add Phase 11 (auth upgrade) and Phase 12 (pentest
remediation), update file inventory, fix outstanding items
- ui_refresh.md: update current status line
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 20:36:12 +08:00
6 changed files with 130 additions and 90 deletions
- **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 (5 presets), first day of week, weather city, ntfy push notifications, TOTP two-factor auth, auto-lock, password management
- **Notifications** - ntfy push notifications for reminders (configurable per-user)
@ -48,7 +47,7 @@ A self-hosted personal life administration app with a dark-themed UI. Manage you
```bash
cp .env.example .env
```
Edit `.env` and set secure values:
Edit `.env` and set secure values (see [Production Hardening](#production-hardening) below for generation commands):
```env
POSTGRES_USER=umbra
POSTGRES_PASSWORD=your-secure-password
@ -67,7 +66,7 @@ A self-hosted personal life administration app with a dark-themed UI. Manage you
4. **Open the app**
Navigate to `http://localhost` in your browser. On first launch you'll be prompted to create a PIN.
Navigate to `http://localhost` in your browser. On first launch you'll be prompted to create a username and password.
## Architecture
@ -81,15 +80,16 @@ A self-hosted personal life administration app with a dark-themed UI. Manage you
+-------+-------+
| Nginx |
| (frontend) |
| non-root:8080 |
+---+-------+---+
| |
static | | /api/*
files | |
files | | (rate-limited auth)
v v
+---+-------+---+
| FastAPI |
| (backend) |
| port 8000 |
| non-root |
+-------+-------+
|
+-------+-------+
@ -99,29 +99,77 @@ A self-hosted personal life administration app with a dark-themed UI. Manage you
+---------------+
```
- **Frontend** is built as static files and served by Nginx. Nginx also reverse-proxies API requests to the backend.
- **Backend** runs Alembic migrations on startup, then serves the FastAPI application.
- **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
### Hardened by default
- **Non-root containers** — both backend (`appuser:1000`) and frontend (`nginx-unprivileged`) run as non-root
- **No external backend port** — port 8000 is internal-only; all traffic flows through nginx
- **Server version suppression** — `server_tokens off` (nginx) and `--no-server-header` (uvicorn)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.