|
|
1 hour ago | |
|---|---|---|
| .claude | 1 hour ago | |
| assets | 1 day ago | |
| bin | 1 hour ago | |
| doc | 1 hour ago | |
| migrations | 2 days ago | |
| public | 1 day ago | |
| src | 12 hours ago | |
| tests | 12 hours ago | |
| views | 12 hours ago | |
| .dockerignore | 2 weeks ago | |
| .env.example | 2 hours ago | |
| .gitignore | 1 day ago | |
| ACCEPTANCE.md | 2 days ago | |
| CHANGELOG.md | 1 hour ago | |
| Dockerfile | 1 day ago | |
| LICENSE | 2 days ago | |
| README.md | 1 hour ago | |
| SPEC.md | 1 hour ago | |
| appctl | 1 hour ago | |
| composer.json | 2 days ago | |
| composer.lock | 2 days ago | |
| docker-compose.dev.yml | 1 day ago | |
| docker-compose.yml | 2 hours ago | |
| package-lock.json | 2 days ago | |
| package.json | 2 days ago | |
| phpunit.xml | 2 weeks ago | |
| tailwind.config.js | 2 days ago |
Web replacement for an Excel-based sprint planning workbook used by a ~15-person ops/dev team. One sprint per page: an Arbeitstage matrix (working-days availability per worker per week) on top, a task list with per-worker day allocations on the bottom. Proper auth, database, and a per-cell audit trail.
For a development or pilot install on a single host:
# 1. Clone and enter the repo
git clone <repository-url> sprint_planer_web
cd sprint_planer_web
# 2. Create the .env file from the template
cp .env.example .env
# 3. Generate a hash for the local-admin password. The app verifies sign-ins
# with password_verify() against LOCAL_ADMIN_PASSWORD_HASH, so the
# plaintext password never lands on disk. Pick the snippet that matches
# what you have installed:
#
# a) Host PHP 8 (any minor):
# php -r 'echo password_hash(readline("Password: "), PASSWORD_DEFAULT), PHP_EOL;'
#
# b) No host PHP — use the Docker image you already build with:
# docker run --rm -it php:8.3-cli php -r \
# 'echo password_hash(readline("Password: "), PASSWORD_DEFAULT), PHP_EOL;'
#
# Both prompt for the password (no echo on most TTYs) and print a
# bcrypt string starting with `$2y$`. Paste it into .env as:
# LOCAL_ADMIN_EMAIL='you@example.com'
# LOCAL_ADMIN_PASSWORD_HASH='$2y$...'
# Use single quotes — the `$` in the hash will otherwise be eaten by the
# shell on `docker compose up`.
#
# For Entra-based sign-in, fill ENTRA_TENANT_ID / ENTRA_CLIENT_ID /
# ENTRA_CLIENT_SECRET instead (or in addition).
chmod 600 .env
# 4. Build and start the container (compose maps host port HTTP_PORT
# from .env → container 80; default 8080, change in .env to taste)
docker compose up -d --build
# Equivalent shortcut: `./appctl prod start`
# 5. Open the app
xdg-open http://localhost:8080 # substitute your HTTP_PORT if changed
If you signed in via the local-admin fallback you are immediately the
administrator (audit-logged as BOOTSTRAP_ADMIN with via=local). For
an OIDC-only deploy, nominate the first admin up front via
BOOTSTRAP_ADMIN_OID or BOOTSTRAP_ADMIN_EMAIL in .env — without one
of them set the OIDC path will not auto-promote anyone (this closes
finding R01-N03 in doc/REVIEW_01.md). Subsequent admin promotions
happen through the Users page in the hamburger menu.
The SQLite database is created at ./data/app.sqlite on the host
(mounted into the container at /var/www/data/app.sqlite). Migrations
run from the Docker entrypoint (bin/docker-entrypoint.sh → php
bin/migrate.php) BEFORE Apache binds the port — a failed migration
aborts container start instead of leaving a half-applied schema
(R01-N22). The web request path only checks schema_version and
returns 503 Service Unavailable when something is pending. Wiping
./data/ resets the application to a blank slate.
For everything else — Entra app registration, backups, troubleshooting,
upgrades — see doc/admin-manual.md.
For iterating on code (vs. running the prod-shaped image you set up
above), use the dev compose overlay. Source dirs are bind-mounted from
the host and a sidecar runs tailwindcss --watch, so Twig / PHP edits
are picked up on the next request and CSS changes appear without a
container rebuild:
./appctl dev start # foreground; equivalent to:
# HOST_UID=$(id -u) HOST_GID=$(id -g) \
# docker compose -f docker-compose.yml -f docker-compose.dev.yml up
Rebuild the dev images only when Dockerfile, composer.json/.lock, or
package.json/.lock change:
./appctl dev build
./appctl help lists every command. The first ./appctl invocation
in an interactive shell offers to wire up bash completion (a source
line into ~/.bashrc); answer n to skip — re-asking is suppressed
via a marker in ~/.config/appctl/. Full architecture (overlay
rationale, dev edit-cycle table, tests Docker stage) lives in
SPEC.md §11.
public/ front controller (index.php) + web root
src/ application code (App\ namespace, PSR-4)
views/ PHP templates
migrations/ numbered .sql files applied by Migrator
assets/ Tailwind source (compiled into public/assets/css/app.css)
data/ SQLite + sessions (volume-mounted; gitignored)
doc/ operator-facing documentation (admin manual)
doc/admin-manual.md — administrator setup,
configuration, and operations guide.SPEC.md — full specification: schema, routes, capacity
math, build phase history. Read this if you intend to modify the code.ACCEPTANCE.md — manual acceptance checklist used to
validate releases.The preferred path is the tests Docker stage — same PHP version,
extensions, and composer state as prod, plus the dev composer deps
layered in:
./appctl check # lint + phpunit, in a one-shot --rm container
./appctl test # phpunit only
./appctl lint # php -l on src/ + tests/
First run of any of these cold-builds the tests image (~30–60s);
subsequent runs reuse it. No host PHP / composer needed. From inside
Claude Code, the /check slash command runs the same pipeline via
a Haiku-powered subagent that returns only the pass/fail summary —
verbose phpunit output stays out of the conversation context.
Direct vendor/bin/phpunit on the host still works if you have PHP +
composer locally and want the fastest possible loop, but the Phase 20
parser tests then auto-skip on hosts missing ext-gd / ext-zip /
ext-xmlreader etc. See SPEC.md §11.3 for the full table.