Add calendar app — shared events calendar with departments, staff tagging, bank holidays and two-way phone sync

Fastify/Postgres backend + React frontend matching the stack's app conventions, plus
a hand-rolled RFC 4791 CalDAV server (caldav-adapter turned out Koa-only in practice)
so calendars subscribe as genuine two-way sync in Apple/Google/Outlook. v1 scope:
multiple colour-coded calendars, department/staff event tagging via live Workforce
lookups, month/week/day/list views, dashboard, file attachments, activity log, and
an auto-synced UK bank holidays calendar. Verified end-to-end locally against real
Postgres: REST CRUD, CalDAV discovery/PROPFIND/REPORT/PUT/sync-collection, all-day
date handling, system-calendar write protection, and activity logging across both
the web and CalDAV write paths.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
jtricerolph 2026-07-24 16:36:37 +00:00
commit bf5557d277
53 changed files with 12529 additions and 0 deletions

56
frontend/nginx.conf Normal file
View file

@ -0,0 +1,56 @@
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
client_max_body_size 12m;
location /calendar/api/auth/ {
proxy_pass http://10.10.10.101:3001/api/auth/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /calendar/api/ {
proxy_pass http://backend:3001/api/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
add_header Cache-Control "no-store";
}
# CalDAV WebDAV verbs (PROPFIND/REPORT/MKCALENDAR/PUT/DELETE/GET) proxied straight
# through to the backend, same upstream as /calendar/api/ but its own prefix so native
# calendar clients (Apple/Google/Outlook) get a clean, stable subscription URL.
location /calendar/caldav/ {
proxy_pass http://backend:3001/caldav/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Authorization $http_authorization;
proxy_pass_header Authorization;
}
location /.well-known/caldav {
return 301 /calendar/caldav/;
}
location /calendar/health {
proxy_pass http://backend:3001/health;
}
location ~* /calendar/.*\.(js|css|png|ico|svg|woff2?)$ {
expires 1y;
add_header Cache-Control "public, immutable";
try_files $uri =404;
}
location /calendar/ {
add_header Cache-Control "no-cache" always;
try_files $uri /calendar/index.html;
}
location = / {
return 301 /calendar/;
}
}