- PROJECT_PLAN: register D-044, re-revise D-025 to "tunnel OR setup code",
update A13, O-8, §5.1, §12 and the change log.
- SPEC-003 §4/§7/§9/§12: the gate now serves the wizard to the tunnel OR an
unlocked request; AC-7/AC-10 reworded ("refused the wizard" — the boilerplate
may still answer `/` and `/setup`), AC-14 added.
- SPEC-005 §3/§4/§6/§9: the boilerplate, the unlock action, the code rules and
the ACs; AC-7 added for single-use/rate-limit/redaction.
- deploy-zoraxy §1/§3/§5/§7 + README: the LXC/Proxmox topology, how to read the
code (journalctl · pct exec 11020), the code gate replacing the tunnel-only
bootstrap (the tunnel stays as gate a); firewall and Zoraxy sections kept.
6.3 KiB
MyDay
A self-hosted employee time, absence & reporting app by Sechpoint. Delivered as a PWA for mobile and desktop. Single-tenant — one company per instance.
Status: 🚧 M0 + M0.1 implemented — the auth & routing foundation and the web/PWA layer
(the SPEC-002…009 slices) are built: routing · identity/sessions · the door · /setup ·
enroll/login (+ the passkey nudge) · roles/chain/recovery · the module registry · the web shell.
Next milestone: M1 — org structure. The design of record is
PROJECT_PLAN.md.
What it will do
| Area | |
|---|---|
| Org structure | users, the manager hierarchy, departments, positions |
| Time | presence and timesheets (a per-user mode) |
| Absence | leave requests, approvals, balances |
| Reporting | rollups and aggregations |
Built as one Go binary: a small core (MyDay.auth — identity, sessions, the door) plus
drop-in modules.
Running it
# 1. configure
cp config.example.yaml config.yaml # then edit; config.yaml is gitignored
# 2. build
go build -o myday ./cmd/myday
# 3. run
./myday
⚠️ First run — the setup code
The first user becomes the top admin (the root of the chain). MyDay bootstraps through a
/setup wizard that is gated — never first-visitor-wins (D-025/D-044). On first start it
prints a one-time 128-bit SETUP CODE in its startup log:
======================================================================
MyDay is NOT set up yet — no admin exists.
======================================================================
Open the setup wizard at:
https://myday.sechpoint.app/setup
SETUP CODE: 9f3a-1b2c-…
Open the domain (or http://localhost:8080) and enter that code at /setup. Until then every
page is a friendly first-run page — never a bare 404 — and every other route answers 404. Read
the code again with:
journalctl -u myday # inside the container
pct exec 11020 -- journalctl -u myday # from the Proxmox host
Why a code, not a tunnel? MyDay's reference deployment is an LXC container behind Proxmox + Zoraxy. An SSH tunnel is impractical there:
pct enter/SSH lands on the container gateway, not loopback, so a tunnel to127.0.0.1:8080cannot be formed. The setup code closes first-visitor-wins instead. A direct SSH tunnel to the app's loopback port still works as a second gate and needs no code (D-025 gate a).
Note: the code is single-use and the entry form is rate-limited. Complete the wizard, then restart so the app adopts the
config.yamlthe wizard wrote.
Bonus: to use the tunnel gate, reach the app over
localhost/127.0.0.1— only a loopback origin counts as a secure context for the browser's WebAuthn dialogs. Over plain http the cookies are sent withoutSecure(required by the tunnel bootstrap); behind the proxy (https) they are hardened — see Deployment.
Only after the top admin exists should you put MyDay behind a reverse proxy and expose it.
Deployment — behind Zoraxy (TLS at the proxy)
Full walkthrough:
docs/deploy-zoraxy.md— topology · config · the Zoraxy ProxyHost · the firewall rule · the first-run setup code (no tunnel needed) · systemd · the misconfig warnings. This section is the summary.
The reference deployment terminates TLS at Zoraxy at
10.1.0.10; the app itself speaks plain HTTP. Config (config.example.yaml →
config.yaml, D-043):
- App —
server.listen: "0.0.0.0:8080"; the app binds any address (there is no setup-mode bind refusal, D-025 revised). - Proxy — Zoraxy terminates TLS and forwards to
http://<app-host>:8080, settingX-Forwarded-ForandX-Forwarded-Proto. trusted_proxies—["10.1.0.10"](Zoraxy). The app honoursX-Forwarded-Protofrom a trusted proxy to decide a request ishttps, and then sets the session cookieSecure+__Host-and sends HSTS. Over plain http (the tunnel) it keeps the bare, non-Securecookie so the bootstrap works. A wrong value fails silently — noSecurecookie, no HSTS.base_url—https://myday.sechpoint.app: the public origin, used in invite/recovery links.- Firewall —
:8080MUST be reachable only from10.1.0.10. Anything else that can reach the port bypasses the proxy and its TLS; the app would then serve plain HTTP to that client.
# read the one-time setup code, then open the domain and enter it at /setup
journalctl -u myday # inside the container
pct exec 11020 -- journalctl -u myday # from the Proxmox host
# (or, for the no-code tunnel gate: ssh -L 8080:127.0.0.1:8080 user@server)
What /setup writes — and the restart
The wizard persists config.yaml (setup: false, the base URL, mail/locale, and the secrets)
next to the loaded file — never over the committed config.example.yaml. If the file is not
writable it prints the values for you to save by hand, and setup still completes.
The secrets are generated at startup when a value is still CHANGE_ME…, so the wizard's
ceremony is never signed with a known key. The persisted file then holds those same values —
so a restart adopts them and the admin's TOTP secret (sealed with the generated key) keeps
working. Boot a productive instance from the written config.yaml, not from the example:
config.example.yaml's placeholders fail closed in productive mode by design.
Documentation
PROJECT_PLAN.md |
the plan & decision log of record |
AGENT.md |
instructions for AI agents working here |
docs/specs/ |
implementation specs |
docs/deploy-zoraxy.md |
the Zoraxy deployment guide (D-043) |
config.example.yaml |
configuration template |
Security
- Secrets live in
config.yaml(gitignored) — never commit them. - Auth is Passkey (primary) + TOTP (fallback).
- See
PROJECT_PLAN.md§10 for the deferred-security register and its beta gate.
License
TBD.