Files
omsorg/CLAUDE.md
T
2026-06-13 20:03:22 +02:00

7.9 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

This is the OMSORG website plus OMSORG Connect, an internal employee web app ("Mitarbeiter-App") for a German nursing care company. There is no build system — everything is plain PHP, HTML, CSS, and vanilla JS deployed directly to a web server (htdocs).

Deployment

Upload the full directory contents to the server's htdocs folder and overwrite existing files. After deploying, clear the browser cache or test in an incognito window.

There are no build steps, package managers, or test runners.

Architecture

Public website (/)

Static HTML with a contact form:

  • index.html — main landing page
  • send-form.php — handles the public contact form, sends email via PHP mail()
  • send-status-template.php — reusable status page template for form results
  • datenschutz.html, impressum.html — legal pages

Employee app (/mitarbeiter-app/)

A session-based PHP app with no framework, backed by a MySQL database (PDO).

Entry point

  • index.php — login page. Redirects to pages/dashboard.php if already logged in. Includes rate limiting: 5 failed attempts trigger a 10-minute lockout.
  • setup.php — one-time setup script (run once after first deploy to bootstrap the DB)

Library (lib/)

  • auth.php — included at the top of every protected page. Provides require_login(), require_admin(), is_logged_in(), is_admin(), current_user(), current_name(), current_username(), csrf_token(), csrf_field(), verify_csrf(), e(). Users are stored in the users DB table. Login is case-insensitive on username.
  • db.php — provides db(): PDO (singleton). Reads credentials from config.php, runs pending migrations on first connection, and sets PDO::ERRMODE_EXCEPTION.
  • config.php — returns array with MySQL DSN/credentials, SMTP settings, and mail recipient addresses. Import with $config = require __DIR__ . '/config.php';.
  • layout.php — shared sidebar layout. Call layout_start($title, $current_page) and layout_end() to wrap page content. Renders the sidebar nav, user avatar, and injects the service worker.
  • mail.php — provides smtp_send($cfg, $to, $subject, $body, $attach = []). Raw SMTP implementation (no PHPMailer), supports SSL (port 465) and STARTTLS (port 587), and optional file attachments.

Pages (pages/)

Each page is a standalone PHP file using layout_start/layout_end:

  • dashboard.php — main landing page after login; shows news and quick links
  • stundennachweis.php — upload monthly timesheet (PDF/image)
  • urlaubsantrag.php — vacation request form
  • abwesenheitsantrag.php — absence request form (sick leave, etc.)
  • benefitsantrag.php — employee benefits request
  • fortbildungsantrag.php — training request with optional file upload
  • einsatzbewertung.php — rate a deployment/assignment
  • einsatzanweisung.php — view/download personal assignment instructions (PDF)
  • dokumentenarchiv.php — personal document archive (upload/view own documents)
  • downloads.php — company-wide file downloads (admin-managed)
  • dienstplan.php — view personal shift schedule
  • werben.php — refer a new employee
  • settings.php — profile settings: change password, upload avatar
  • admin.php — admin-only: tabs for Anträge, Nutzer, Dienstplan, Downloads, Fortbildungsmaterial, Stundennachweis, Bewertungen, News, Einsatzanweisung, Login-Versuche (failed login attempts: lists recent attempts, shows currently locked IPs, and clears the login_attempts table)
  • admin-dienstplan.php — admin shift planner view
  • Serve pages (*-serve.php, dokument-serve.php, download-serve.php, etc.) — stream protected files from uploads/, downloads/, fortbildung-materials/ with auth check

Actions (actions/)

POST-only endpoints, each does one thing and redirects back:

  • submit-urlaubsantrag.php, submit-abwesenheitsantrag.php, submit-benefitsantrag.php, submit-fortbildungsantrag.php, submit-stundennachweis.php, submit-einsatzbewertung.php, submit-werben.php — insert into the matching requests_* DB table, send notification email via smtp_send()
  • admin-action.php — admin status updates (accept/reject requests), user management (add/delete/reset password), news CRUD
  • save-dienstplan.php — admin saves shift entries
  • downloads-action.php, downloads-reorder.php — admin manages downloadable files
  • fortbildung-material-action.php, fortbildung-material-reorder.php — admin manages training materials
  • einsatzanweisung-action.php — admin uploads/assigns personal instruction PDFs
  • upload-dokument.php, delete-dokument.php — user document archive management
  • upload-avatar.php — user uploads profile picture (stored in assets/avatars/)
  • save-profile.php — user changes own password
  • logout.php — destroys session, redirects to ../index.php

Frontend

  • app.css — all styles (no framework)
  • manifest.webmanifest + service-worker.js — PWA support ("Add to Home Screen")

Database schema (MySQL)

Managed via migrations in migrations/. Key tables:

  • users — id, username, name, role, password_hash, active, created_at, email, telefon, avatar
  • requests_urlaubsantrag — vacation requests (von, bis, vertretung, nachricht, status, admin_note)
  • requests_abwesenheitsantrag — absence requests (von, bis, grund, vertretung, nachricht, status, admin_note)
  • requests_benefitsantrag — benefits requests
  • requests_fortbildungsantrag — training requests (with optional file upload)
  • requests_stundennachweis — timesheet uploads (monat, filename)
  • requests_werben — employee referrals
  • dienstplan — shift schedule (user_id, date, schicht; UNIQUE on user_id+date)
  • downloads — company download files (title, filename, sort_order)
  • fortbildung_materials — training material files (title, filename, sort_order)
  • dokumente — user personal document archive (user_id, kategorie, filename)
  • einsatzbewertungen — deployment ratings
  • einsatzanweisung — one PDF per user (UNIQUE on user_id)
  • news — company news posts (title, text, date)
  • schema_migrations — tracks applied migrations

Migration system

db.php runs _run_migrations() on every connection. Migrations are PHP files in migrations/ returning ['description' => ..., 'up' => [...SQL...]]. They are applied in filename order and tracked in schema_migrations. Already-existing DBs without the migrations table are stamped as fully applied on first run.

File storage

Uploaded files are stored outside webroot or protected by .htaccess:

  • uploads/ — user form attachments (stundennachweis, fortbildung, einsatzanweisung). Filename pattern: {date}_{username}_{type}_{randomhex}.{ext}
  • downloads/ — admin-managed company downloads (hashed filenames)
  • fortbildung-materials/ — admin-managed training materials (hashed filenames)
  • assets/avatars/ — user profile pictures ({username}_{randomhex}.{ext})

Allowed upload types: pdf, doc, docx, jpg, jpeg, png. Max size: 12 MB.

Security conventions

  • lib/ is blocked from direct HTTP access via lib/.htaccess
  • uploads/, downloads/, fortbildung-materials/, data/, migrations/ all have .htaccess denying direct access; files are served only through *-serve.php pages with auth checks
  • All output uses e() (alias for htmlspecialchars) to prevent XSS
  • Every POST form includes a CSRF token (csrf_field() in form, verify_csrf() in action)
  • Login rate-limiting: 5 failures → 10-minute session lockout
  • Uploads are renamed to random hex filenames before storage

Email (configured in config.php)

  • SMTP via smtp_send() in lib/mail.php; credentials in config.php
  • mail_infoinfo@omsorg-pflegedienste.de (Geschäftsführung)
  • mail_sabrinas.berggoetz@omsorg-pflegedienste.de (Disposition)
  • mail_fromno-reply@omsorg-pflegedienste.de