|
|
@@ -0,0 +1,510 @@
|
|
|
+{% extends "layout.twig" %}
|
|
|
+
|
|
|
+{% block content %}
|
|
|
+<section class="space-y-12" x-data="screenshotModal">
|
|
|
+
|
|
|
+ {# --------------- Hero --------------- #}
|
|
|
+ <header class="text-center max-w-3xl mx-auto pt-2">
|
|
|
+ <div class="flex justify-center mb-4">
|
|
|
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="96" height="96" aria-hidden="true" class="block" fill="none">
|
|
|
+ <defs>
|
|
|
+ <radialGradient id="brand-cycle-glow-about" cx="32" cy="32" r="20" gradientUnits="userSpaceOnUse">
|
|
|
+ <stop offset="0" stop-color="#6366f1" stop-opacity="0.55"/>
|
|
|
+ <stop offset="0.6" stop-color="#6366f1" stop-opacity="0.12"/>
|
|
|
+ <stop offset="1" stop-color="#6366f1" stop-opacity="0"/>
|
|
|
+ </radialGradient>
|
|
|
+ </defs>
|
|
|
+ <circle cx="32" cy="32" r="20" fill="url(#brand-cycle-glow-about)"/>
|
|
|
+ <path d="M52 32 A20 20 0 1 1 32 12" stroke="currentColor" stroke-width="3.5" stroke-linecap="round"/>
|
|
|
+ <path d="M44 8 L52 12 L48 20" stroke="currentColor" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
|
+ <circle cx="32" cy="32" r="5" fill="#6366f1"/>
|
|
|
+ <circle cx="48" cy="20" r="2.5" fill="currentColor" opacity="0.55"/>
|
|
|
+ <circle cx="52" cy="40" r="2.5" fill="currentColor" opacity="0.55"/>
|
|
|
+ <circle cx="40" cy="50" r="2.5" fill="currentColor" opacity="0.55"/>
|
|
|
+ <circle cx="20" cy="48" r="2.5" fill="currentColor" opacity="0.55"/>
|
|
|
+ <circle cx="14" cy="32" r="2.5" fill="#10b981"/>
|
|
|
+ </svg>
|
|
|
+ </div>
|
|
|
+ <h1 class="text-4xl font-bold tracking-tight">Sprint Planner</h1>
|
|
|
+ <p class="mt-3 text-lg text-slate-600 dark:text-slate-300">
|
|
|
+ One shared sprint board for the whole team — replacing the
|
|
|
+ spreadsheet that everybody copies and nobody keeps in sync.
|
|
|
+ </p>
|
|
|
+ </header>
|
|
|
+
|
|
|
+ {# --------------- What it is --------------- #}
|
|
|
+ <div class="rounded-lg border bg-white p-6 dark:bg-slate-800 dark:border-slate-700">
|
|
|
+ <h2 class="text-2xl font-semibold tracking-tight">What it is</h2>
|
|
|
+ <p class="mt-3 text-slate-700 dark:text-slate-300">
|
|
|
+ Sprint Planner is a small web app for ops/dev teams that plan their
|
|
|
+ work in two- to four-week sprints. It replaces an Excel sprint
|
|
|
+ workbook with a proper website: shared by everyone, edited live,
|
|
|
+ backed by a database, and protected with sign-in. Every change is
|
|
|
+ recorded so it is always clear who moved a number and when.
|
|
|
+ </p>
|
|
|
+ <p class="mt-3 text-slate-700 dark:text-slate-300">
|
|
|
+ Each sprint has its own page. The top of the page is a
|
|
|
+ <em>working-days matrix</em> — for every week of the sprint, every
|
|
|
+ team member tells the planner how many days they will be available.
|
|
|
+ The bottom is the <em>task list</em> — every piece of work the
|
|
|
+ team will tackle, with the days each person is going to spend on
|
|
|
+ it. The page sums these numbers up live so the team can see
|
|
|
+ whether they are over- or under-committed for the sprint.
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {# --------------- How it works --------------- #}
|
|
|
+ <div class="space-y-6">
|
|
|
+ <h2 class="text-2xl font-semibold tracking-tight text-center">How a sprint runs end-to-end</h2>
|
|
|
+
|
|
|
+ <ol class="grid gap-4 md:grid-cols-2">
|
|
|
+ <li class="rounded-lg border bg-white p-5 dark:bg-slate-800 dark:border-slate-700">
|
|
|
+ <span class="inline-flex items-center justify-center w-8 h-8 rounded-full bg-indigo-100 text-indigo-700 font-semibold dark:bg-indigo-900 dark:text-indigo-200">1</span>
|
|
|
+ <h3 class="mt-3 font-semibold">Create the sprint</h3>
|
|
|
+ <p class="mt-1 text-sm text-slate-600 dark:text-slate-400">
|
|
|
+ An admin gives the sprint a name and picks a start and end
|
|
|
+ date. The planner splits that range into calendar weeks
|
|
|
+ automatically — up to twenty-six.
|
|
|
+ </p>
|
|
|
+ </li>
|
|
|
+
|
|
|
+ <li class="rounded-lg border bg-white p-5 dark:bg-slate-800 dark:border-slate-700">
|
|
|
+ <span class="inline-flex items-center justify-center w-8 h-8 rounded-full bg-indigo-100 text-indigo-700 font-semibold dark:bg-indigo-900 dark:text-indigo-200">2</span>
|
|
|
+ <h3 class="mt-3 font-semibold">Pick the team</h3>
|
|
|
+ <p class="mt-1 text-sm text-slate-600 dark:text-slate-400">
|
|
|
+ Add the people who will work on this sprint, set the
|
|
|
+ reserve buffer (how much capacity to keep aside for
|
|
|
+ interruptions), and tick the public holidays so the
|
|
|
+ available-days count is right out of the box.
|
|
|
+ </p>
|
|
|
+ </li>
|
|
|
+
|
|
|
+ <li class="rounded-lg border bg-white p-5 dark:bg-slate-800 dark:border-slate-700">
|
|
|
+ <span class="inline-flex items-center justify-center w-8 h-8 rounded-full bg-indigo-100 text-indigo-700 font-semibold dark:bg-indigo-900 dark:text-indigo-200">3</span>
|
|
|
+ <h3 class="mt-3 font-semibold">Capture the work</h3>
|
|
|
+ <p class="mt-1 text-sm text-slate-600 dark:text-slate-400">
|
|
|
+ Add tasks with a title, an owner, a priority, and an
|
|
|
+ estimate of total days. Re-order them by drag-and-drop;
|
|
|
+ filter by owner, priority, or text search.
|
|
|
+ </p>
|
|
|
+ </li>
|
|
|
+
|
|
|
+ <li class="rounded-lg border bg-white p-5 dark:bg-slate-800 dark:border-slate-700">
|
|
|
+ <span class="inline-flex items-center justify-center w-8 h-8 rounded-full bg-indigo-100 text-indigo-700 font-semibold dark:bg-indigo-900 dark:text-indigo-200">4</span>
|
|
|
+ <h3 class="mt-3 font-semibold">Allocate days</h3>
|
|
|
+ <p class="mt-1 text-sm text-slate-600 dark:text-slate-400">
|
|
|
+ For every task, type how many days each person will spend.
|
|
|
+ The planner re-totals the row, deducts the reserve, and
|
|
|
+ shows what each person still has free — in green when
|
|
|
+ there is room, in red when overcommitted.
|
|
|
+ </p>
|
|
|
+ </li>
|
|
|
+
|
|
|
+ <li class="rounded-lg border bg-white p-5 dark:bg-slate-800 dark:border-slate-700">
|
|
|
+ <span class="inline-flex items-center justify-center w-8 h-8 rounded-full bg-indigo-100 text-indigo-700 font-semibold dark:bg-indigo-900 dark:text-indigo-200">5</span>
|
|
|
+ <h3 class="mt-3 font-semibold">Track progress</h3>
|
|
|
+ <p class="mt-1 text-sm text-slate-600 dark:text-slate-400">
|
|
|
+ Mark each cell as <em>started</em>, <em>done</em>, or
|
|
|
+ <em>cancelled</em> as the sprint runs. Use the focus
|
|
|
+ filter to look at one person's plate at a time without
|
|
|
+ losing the rest.
|
|
|
+ </p>
|
|
|
+ </li>
|
|
|
+
|
|
|
+ <li class="rounded-lg border bg-white p-5 dark:bg-slate-800 dark:border-slate-700">
|
|
|
+ <span class="inline-flex items-center justify-center w-8 h-8 rounded-full bg-indigo-100 text-indigo-700 font-semibold dark:bg-indigo-900 dark:text-indigo-200">6</span>
|
|
|
+ <h3 class="mt-3 font-semibold">Present and audit</h3>
|
|
|
+ <p class="mt-1 text-sm text-slate-600 dark:text-slate-400">
|
|
|
+ A big-screen view trims the chrome down for the daily
|
|
|
+ stand-up or the sprint review. The audit log captures
|
|
|
+ every edit — who, when, before, after — so questions
|
|
|
+ like “wait, who changed that number?” have a
|
|
|
+ factual answer.
|
|
|
+ </p>
|
|
|
+ </li>
|
|
|
+ </ol>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {# --------------- Tour of the interface (gallery) --------------- #}
|
|
|
+ <div class="space-y-6">
|
|
|
+ <h2 class="text-2xl font-semibold tracking-tight text-center">A tour of the interface</h2>
|
|
|
+ <p class="text-center text-slate-600 dark:text-slate-400 max-w-2xl mx-auto text-sm">
|
|
|
+ Click any picture to enlarge it.
|
|
|
+ </p>
|
|
|
+
|
|
|
+ <div class="grid gap-6 md:grid-cols-2">
|
|
|
+
|
|
|
+ {# 1. Sprints overview #}
|
|
|
+ <figure class="rounded-lg border bg-white overflow-hidden flex flex-col dark:bg-slate-800 dark:border-slate-700">
|
|
|
+ <button type="button"
|
|
|
+ x-on:click="open($event)"
|
|
|
+ data-src="/assets/img/screenshots/Sprints_view.png"
|
|
|
+ data-alt="Sprints overview"
|
|
|
+ aria-label="Enlarge: Sprints overview"
|
|
|
+ class="block w-full bg-slate-50 dark:bg-slate-900/50 focus:outline-none focus:ring-2 focus:ring-indigo-400 group">
|
|
|
+ <img src="/assets/img/screenshots/Sprints_view.png"
|
|
|
+ alt="Sprints overview"
|
|
|
+ class="w-full h-56 object-cover object-top transition group-hover:opacity-90">
|
|
|
+ </button>
|
|
|
+ <figcaption class="p-4 flex-1 flex flex-col">
|
|
|
+ <div class="flex items-baseline justify-between gap-3">
|
|
|
+ <h3 class="font-semibold">Sprints overview</h3>
|
|
|
+ <button type="button"
|
|
|
+ x-on:click="open($event)"
|
|
|
+ data-src="/assets/img/screenshots/Sprints_view.png"
|
|
|
+ data-alt="Sprints overview"
|
|
|
+ class="text-xs text-indigo-700 hover:underline dark:text-indigo-400 whitespace-nowrap">Click to enlarge</button>
|
|
|
+ </div>
|
|
|
+ <p class="mt-1 text-sm text-slate-600 dark:text-slate-400">
|
|
|
+ The home page lists every sprint with its dates, worker
|
|
|
+ count, task count, and reserve percentage. Click a row
|
|
|
+ to open it.
|
|
|
+ </p>
|
|
|
+ </figcaption>
|
|
|
+ </figure>
|
|
|
+
|
|
|
+ {# 2. Sprint settings #}
|
|
|
+ <figure class="rounded-lg border bg-white overflow-hidden flex flex-col dark:bg-slate-800 dark:border-slate-700">
|
|
|
+ <button type="button"
|
|
|
+ x-on:click="open($event)"
|
|
|
+ data-src="/assets/img/screenshots/Sprint_settings.png"
|
|
|
+ data-alt="Sprint settings"
|
|
|
+ aria-label="Enlarge: Sprint settings"
|
|
|
+ class="block w-full bg-slate-50 dark:bg-slate-900/50 focus:outline-none focus:ring-2 focus:ring-indigo-400 group">
|
|
|
+ <img src="/assets/img/screenshots/Sprint_settings.png"
|
|
|
+ alt="Sprint settings"
|
|
|
+ class="w-full h-56 object-cover object-top transition group-hover:opacity-90">
|
|
|
+ </button>
|
|
|
+ <figcaption class="p-4 flex-1 flex flex-col">
|
|
|
+ <div class="flex items-baseline justify-between gap-3">
|
|
|
+ <h3 class="font-semibold">Sprint settings</h3>
|
|
|
+ <button type="button"
|
|
|
+ x-on:click="open($event)"
|
|
|
+ data-src="/assets/img/screenshots/Sprint_settings.png"
|
|
|
+ data-alt="Sprint settings"
|
|
|
+ class="text-xs text-indigo-700 hover:underline dark:text-indigo-400 whitespace-nowrap">Click to enlarge</button>
|
|
|
+ </div>
|
|
|
+ <p class="mt-1 text-sm text-slate-600 dark:text-slate-400">
|
|
|
+ Edit the dates and reserve buffer, add or remove team
|
|
|
+ members, mark which weekdays are working days for each
|
|
|
+ week, and set a per-person reserve.
|
|
|
+ </p>
|
|
|
+ </figcaption>
|
|
|
+ </figure>
|
|
|
+
|
|
|
+ {# 3. Working-days matrix #}
|
|
|
+ <figure class="rounded-lg border bg-white overflow-hidden flex flex-col dark:bg-slate-800 dark:border-slate-700">
|
|
|
+ <button type="button"
|
|
|
+ x-on:click="open($event)"
|
|
|
+ data-src="/assets/img/screenshots/Sprint_recources_view.png"
|
|
|
+ data-alt="Working-days matrix (Arbeitstage)"
|
|
|
+ aria-label="Enlarge: Working-days matrix"
|
|
|
+ class="block w-full bg-slate-50 dark:bg-slate-900/50 focus:outline-none focus:ring-2 focus:ring-indigo-400 group">
|
|
|
+ <img src="/assets/img/screenshots/Sprint_recources_view.png"
|
|
|
+ alt="Working-days matrix (Arbeitstage)"
|
|
|
+ class="w-full h-56 object-cover object-top transition group-hover:opacity-90">
|
|
|
+ </button>
|
|
|
+ <figcaption class="p-4 flex-1 flex flex-col">
|
|
|
+ <div class="flex items-baseline justify-between gap-3">
|
|
|
+ <h3 class="font-semibold">Working-days matrix</h3>
|
|
|
+ <button type="button"
|
|
|
+ x-on:click="open($event)"
|
|
|
+ data-src="/assets/img/screenshots/Sprint_recources_view.png"
|
|
|
+ data-alt="Working-days matrix (Arbeitstage)"
|
|
|
+ class="text-xs text-indigo-700 hover:underline dark:text-indigo-400 whitespace-nowrap">Click to enlarge</button>
|
|
|
+ </div>
|
|
|
+ <p class="mt-1 text-sm text-slate-600 dark:text-slate-400">
|
|
|
+ For every team member, type the number of days they
|
|
|
+ will be available each week. Half-day steps are
|
|
|
+ allowed. The summary row at the top shows the total
|
|
|
+ capacity for the whole sprint.
|
|
|
+ </p>
|
|
|
+ </figcaption>
|
|
|
+ </figure>
|
|
|
+
|
|
|
+ {# 4. Task list #}
|
|
|
+ <figure class="rounded-lg border bg-white overflow-hidden flex flex-col dark:bg-slate-800 dark:border-slate-700">
|
|
|
+ <button type="button"
|
|
|
+ x-on:click="open($event)"
|
|
|
+ data-src="/assets/img/screenshots/Sprint_task_view.png"
|
|
|
+ data-alt="Task list with per-worker allocations"
|
|
|
+ aria-label="Enlarge: Task list"
|
|
|
+ class="block w-full bg-slate-50 dark:bg-slate-900/50 focus:outline-none focus:ring-2 focus:ring-indigo-400 group">
|
|
|
+ <img src="/assets/img/screenshots/Sprint_task_view.png"
|
|
|
+ alt="Task list with per-worker allocations"
|
|
|
+ class="w-full h-56 object-cover object-top transition group-hover:opacity-90">
|
|
|
+ </button>
|
|
|
+ <figcaption class="p-4 flex-1 flex flex-col">
|
|
|
+ <div class="flex items-baseline justify-between gap-3">
|
|
|
+ <h3 class="font-semibold">Task list</h3>
|
|
|
+ <button type="button"
|
|
|
+ x-on:click="open($event)"
|
|
|
+ data-src="/assets/img/screenshots/Sprint_task_view.png"
|
|
|
+ data-alt="Task list with per-worker allocations"
|
|
|
+ class="text-xs text-indigo-700 hover:underline dark:text-indigo-400 whitespace-nowrap">Click to enlarge</button>
|
|
|
+ </div>
|
|
|
+ <p class="mt-1 text-sm text-slate-600 dark:text-slate-400">
|
|
|
+ Every task is one row: title, owner, priority, total
|
|
|
+ days, and one cell per team member. Search, sort,
|
|
|
+ filter by owner or priority, hide the columns you
|
|
|
+ don't need, and drag rows to reorder.
|
|
|
+ </p>
|
|
|
+ </figcaption>
|
|
|
+ </figure>
|
|
|
+
|
|
|
+ {# 5. Cell time + status picker #}
|
|
|
+ <figure class="rounded-lg border bg-white overflow-hidden flex flex-col dark:bg-slate-800 dark:border-slate-700">
|
|
|
+ <button type="button"
|
|
|
+ x-on:click="open($event)"
|
|
|
+ data-src="/assets/img/screenshots/Task_user_time_status.png"
|
|
|
+ data-alt="Per-cell time and status picker"
|
|
|
+ aria-label="Enlarge: Per-cell time and status picker"
|
|
|
+ class="block w-full bg-slate-50 dark:bg-slate-900/50 focus:outline-none focus:ring-2 focus:ring-indigo-400 group">
|
|
|
+ <img src="/assets/img/screenshots/Task_user_time_status.png"
|
|
|
+ alt="Per-cell time and status picker"
|
|
|
+ class="w-full h-56 object-contain transition group-hover:opacity-90">
|
|
|
+ </button>
|
|
|
+ <figcaption class="p-4 flex-1 flex flex-col">
|
|
|
+ <div class="flex items-baseline justify-between gap-3">
|
|
|
+ <h3 class="font-semibold">Cell time & status</h3>
|
|
|
+ <button type="button"
|
|
|
+ x-on:click="open($event)"
|
|
|
+ data-src="/assets/img/screenshots/Task_user_time_status.png"
|
|
|
+ data-alt="Per-cell time and status picker"
|
|
|
+ class="text-xs text-indigo-700 hover:underline dark:text-indigo-400 whitespace-nowrap">Click to enlarge</button>
|
|
|
+ </div>
|
|
|
+ <p class="mt-1 text-sm text-slate-600 dark:text-slate-400">
|
|
|
+ Click a cell to slide the day count and tag progress
|
|
|
+ — assigned, started, done, or cancelled. The cell tints
|
|
|
+ yellow / green / red so the team can scan progress at
|
|
|
+ a glance.
|
|
|
+ </p>
|
|
|
+ </figcaption>
|
|
|
+ </figure>
|
|
|
+
|
|
|
+ {# 6. Task menu #}
|
|
|
+ <figure class="rounded-lg border bg-white overflow-hidden flex flex-col dark:bg-slate-800 dark:border-slate-700">
|
|
|
+ <button type="button"
|
|
|
+ x-on:click="open($event)"
|
|
|
+ data-src="/assets/img/screenshots/Task_edit_menu.png"
|
|
|
+ data-alt="Task menu — edit, move, copy, delete"
|
|
|
+ aria-label="Enlarge: Task menu"
|
|
|
+ class="block w-full bg-slate-50 dark:bg-slate-900/50 focus:outline-none focus:ring-2 focus:ring-indigo-400 group">
|
|
|
+ <img src="/assets/img/screenshots/Task_edit_menu.png"
|
|
|
+ alt="Task menu — edit, move, copy, delete"
|
|
|
+ class="w-full h-56 object-contain transition group-hover:opacity-90">
|
|
|
+ </button>
|
|
|
+ <figcaption class="p-4 flex-1 flex flex-col">
|
|
|
+ <div class="flex items-baseline justify-between gap-3">
|
|
|
+ <h3 class="font-semibold">Task menu</h3>
|
|
|
+ <button type="button"
|
|
|
+ x-on:click="open($event)"
|
|
|
+ data-src="/assets/img/screenshots/Task_edit_menu.png"
|
|
|
+ data-alt="Task menu — edit, move, copy, delete"
|
|
|
+ class="text-xs text-indigo-700 hover:underline dark:text-indigo-400 whitespace-nowrap">Click to enlarge</button>
|
|
|
+ </div>
|
|
|
+ <p class="mt-1 text-sm text-slate-600 dark:text-slate-400">
|
|
|
+ Each task carries a small menu: edit the title and
|
|
|
+ description, attach a link, move or copy the task to
|
|
|
+ another sprint, or delete it. The right-hand pane
|
|
|
+ shows the read-only details.
|
|
|
+ </p>
|
|
|
+ </figcaption>
|
|
|
+ </figure>
|
|
|
+
|
|
|
+ {# 7. Presenter view #}
|
|
|
+ <figure class="rounded-lg border bg-white overflow-hidden flex flex-col dark:bg-slate-800 dark:border-slate-700">
|
|
|
+ <button type="button"
|
|
|
+ x-on:click="open($event)"
|
|
|
+ data-src="/assets/img/screenshots/Sprint_presenter_screen.png"
|
|
|
+ data-alt="Big-screen presenter view"
|
|
|
+ aria-label="Enlarge: Big-screen presenter view"
|
|
|
+ class="block w-full bg-slate-50 dark:bg-slate-900/50 focus:outline-none focus:ring-2 focus:ring-indigo-400 group">
|
|
|
+ <img src="/assets/img/screenshots/Sprint_presenter_screen.png"
|
|
|
+ alt="Big-screen presenter view"
|
|
|
+ class="w-full h-56 object-cover object-top transition group-hover:opacity-90">
|
|
|
+ </button>
|
|
|
+ <figcaption class="p-4 flex-1 flex flex-col">
|
|
|
+ <div class="flex items-baseline justify-between gap-3">
|
|
|
+ <h3 class="font-semibold">Big-screen presenter</h3>
|
|
|
+ <button type="button"
|
|
|
+ x-on:click="open($event)"
|
|
|
+ data-src="/assets/img/screenshots/Sprint_presenter_screen.png"
|
|
|
+ data-alt="Big-screen presenter view"
|
|
|
+ class="text-xs text-indigo-700 hover:underline dark:text-indigo-400 whitespace-nowrap">Click to enlarge</button>
|
|
|
+ </div>
|
|
|
+ <p class="mt-1 text-sm text-slate-600 dark:text-slate-400">
|
|
|
+ A stripped-down view tuned for the projector at a
|
|
|
+ stand-up. Worker columns can rotate to fit a wide
|
|
|
+ team into one screen without scrolling.
|
|
|
+ </p>
|
|
|
+ </figcaption>
|
|
|
+ </figure>
|
|
|
+
|
|
|
+ {# 8. Audit log #}
|
|
|
+ <figure class="rounded-lg border bg-white overflow-hidden flex flex-col dark:bg-slate-800 dark:border-slate-700">
|
|
|
+ <button type="button"
|
|
|
+ x-on:click="open($event)"
|
|
|
+ data-src="/assets/img/screenshots/Auditlog.png"
|
|
|
+ data-alt="Audit log"
|
|
|
+ aria-label="Enlarge: Audit log"
|
|
|
+ class="block w-full bg-slate-50 dark:bg-slate-900/50 focus:outline-none focus:ring-2 focus:ring-indigo-400 group">
|
|
|
+ <img src="/assets/img/screenshots/Auditlog.png"
|
|
|
+ alt="Audit log"
|
|
|
+ class="w-full h-56 object-cover object-top transition group-hover:opacity-90">
|
|
|
+ </button>
|
|
|
+ <figcaption class="p-4 flex-1 flex flex-col">
|
|
|
+ <div class="flex items-baseline justify-between gap-3">
|
|
|
+ <h3 class="font-semibold">Audit log</h3>
|
|
|
+ <button type="button"
|
|
|
+ x-on:click="open($event)"
|
|
|
+ data-src="/assets/img/screenshots/Auditlog.png"
|
|
|
+ data-alt="Audit log"
|
|
|
+ class="text-xs text-indigo-700 hover:underline dark:text-indigo-400 whitespace-nowrap">Click to enlarge</button>
|
|
|
+ </div>
|
|
|
+ <p class="mt-1 text-sm text-slate-600 dark:text-slate-400">
|
|
|
+ Every create, update, and delete is logged with user,
|
|
|
+ time, and a before/after snapshot. Filter by user,
|
|
|
+ action, entity, or date range — useful when something
|
|
|
+ looks off and someone wants to know what happened.
|
|
|
+ </p>
|
|
|
+ </figcaption>
|
|
|
+ </figure>
|
|
|
+
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {# --------------- Quickstart --------------- #}
|
|
|
+ <div class="rounded-lg border bg-white p-6 dark:bg-slate-800 dark:border-slate-700">
|
|
|
+ <h2 class="text-2xl font-semibold tracking-tight">Quickstart</h2>
|
|
|
+ <p class="mt-2 text-sm text-slate-600 dark:text-slate-400">
|
|
|
+ For a pilot install on one host. You need <strong>Docker</strong>
|
|
|
+ (with the <code>docker compose</code> plugin) and not much else.
|
|
|
+ </p>
|
|
|
+
|
|
|
+ <ol class="mt-5 space-y-5 text-sm">
|
|
|
+ <li>
|
|
|
+ <p class="font-semibold">1. Clone the repository.</p>
|
|
|
+ <pre class="mt-2 p-3 rounded bg-slate-900 text-slate-100 text-xs overflow-x-auto"><code>git clone https://git.chiapparini.org/chiappa/sprint_planer_web.git
|
|
|
+cd sprint_planer_web</code></pre>
|
|
|
+ </li>
|
|
|
+
|
|
|
+ <li>
|
|
|
+ <p class="font-semibold">2. Make a config file.</p>
|
|
|
+ <pre class="mt-2 p-3 rounded bg-slate-900 text-slate-100 text-xs overflow-x-auto"><code>cp .env.example .env
|
|
|
+chmod 600 .env</code></pre>
|
|
|
+ <p class="mt-2 text-slate-600 dark:text-slate-400">
|
|
|
+ Open <code>.env</code> and either fill in the
|
|
|
+ <code>ENTRA_*</code> values (to sign in with a Microsoft
|
|
|
+ work account) or set
|
|
|
+ <code>LOCAL_ADMIN_EMAIL</code> and
|
|
|
+ <code>LOCAL_ADMIN_PASSWORD_HASH</code> for a local sign-in.
|
|
|
+ </p>
|
|
|
+ </li>
|
|
|
+
|
|
|
+ <li>
|
|
|
+ <p class="font-semibold">3. Generate the local-admin password hash (only if you use the local fallback).</p>
|
|
|
+ <pre class="mt-2 p-3 rounded bg-slate-900 text-slate-100 text-xs overflow-x-auto"><code>docker run --rm -it php:8.3-cli php -r \
|
|
|
+ 'echo password_hash(readline("Password: "), PASSWORD_DEFAULT), PHP_EOL;'</code></pre>
|
|
|
+ <p class="mt-2 text-slate-600 dark:text-slate-400">
|
|
|
+ Paste the resulting <code>$2y$…</code> string into
|
|
|
+ <code>.env</code> as <code>LOCAL_ADMIN_PASSWORD_HASH</code>
|
|
|
+ — keep the single quotes around it.
|
|
|
+ </p>
|
|
|
+ </li>
|
|
|
+
|
|
|
+ <li>
|
|
|
+ <p class="font-semibold">4. Build and start the stack.</p>
|
|
|
+ <pre class="mt-2 p-3 rounded bg-slate-900 text-slate-100 text-xs overflow-x-auto"><code>docker compose up -d --build</code></pre>
|
|
|
+ <p class="mt-2 text-slate-600 dark:text-slate-400">
|
|
|
+ The default port is <code>8080</code>; change
|
|
|
+ <code>HTTP_PORT</code> in <code>.env</code> if you need
|
|
|
+ something else.
|
|
|
+ </p>
|
|
|
+ </li>
|
|
|
+
|
|
|
+ <li>
|
|
|
+ <p class="font-semibold">5. Open the app and sign in.</p>
|
|
|
+ <pre class="mt-2 p-3 rounded bg-slate-900 text-slate-100 text-xs overflow-x-auto"><code>http://localhost:8080</code></pre>
|
|
|
+ <p class="mt-2 text-slate-600 dark:text-slate-400">
|
|
|
+ The first person to sign in via local admin (or whoever
|
|
|
+ you nominated through <code>BOOTSTRAP_ADMIN_*</code> on
|
|
|
+ the Microsoft path) becomes the administrator.
|
|
|
+ Subsequent admin promotions happen on the
|
|
|
+ <strong>Users</strong> page.
|
|
|
+ </p>
|
|
|
+ </li>
|
|
|
+ </ol>
|
|
|
+
|
|
|
+ <p class="mt-5 text-xs text-slate-500 dark:text-slate-400">
|
|
|
+ Backups, upgrades, reverse-proxy setup, Microsoft Entra
|
|
|
+ registration: see <code>doc/admin-manual.md</code> in the
|
|
|
+ repository.
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {# --------------- Source / license / version --------------- #}
|
|
|
+ <div class="rounded-lg border bg-slate-50 p-6 dark:bg-slate-800/60 dark:border-slate-700 text-sm">
|
|
|
+ <div class="grid gap-6 md:grid-cols-3">
|
|
|
+ <div>
|
|
|
+ <h3 class="font-semibold uppercase tracking-wider text-xs text-slate-500 dark:text-slate-400">Source</h3>
|
|
|
+ <a href="https://git.chiapparini.org/chiappa/sprint_planer_web"
|
|
|
+ class="mt-1 inline-block text-blue-700 hover:underline dark:text-blue-400 break-all"
|
|
|
+ rel="noopener noreferrer">
|
|
|
+ git.chiapparini.org/chiappa/sprint_planer_web
|
|
|
+ </a>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <h3 class="font-semibold uppercase tracking-wider text-xs text-slate-500 dark:text-slate-400">License</h3>
|
|
|
+ <p class="mt-1">
|
|
|
+ <a href="https://www.apache.org/licenses/LICENSE-2.0"
|
|
|
+ class="text-blue-700 hover:underline dark:text-blue-400"
|
|
|
+ rel="noopener noreferrer">Apache License 2.0</a><br>
|
|
|
+ <span class="text-slate-600 dark:text-slate-400">© 2026 {{ appCreator }}</span>
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <h3 class="font-semibold uppercase tracking-wider text-xs text-slate-500 dark:text-slate-400">Version</h3>
|
|
|
+ <p class="mt-1 font-mono">{{ appVersion }}</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {# --------------- Modal overlay --------------- #}
|
|
|
+ <div x-show="isOpen"
|
|
|
+ x-on:keydown.escape.window="close()"
|
|
|
+ x-cloak
|
|
|
+ role="dialog"
|
|
|
+ aria-modal="true"
|
|
|
+ aria-label="Enlarged screenshot"
|
|
|
+ class="fixed inset-0 z-50 flex items-center justify-center p-4 sm:p-8 bg-slate-900/85 backdrop-blur-sm">
|
|
|
+
|
|
|
+ {# Click-to-dismiss backdrop. Sits behind the image / close button so
|
|
|
+ clicks on either don't propagate. #}
|
|
|
+ <button type="button"
|
|
|
+ x-on:click="close()"
|
|
|
+ aria-label="Close enlarged screenshot"
|
|
|
+ tabindex="-1"
|
|
|
+ class="absolute inset-0 w-full h-full cursor-default focus:outline-none"></button>
|
|
|
+
|
|
|
+ {# Prominent close button — top-right, white pill. #}
|
|
|
+ <button type="button"
|
|
|
+ x-on:click="close()"
|
|
|
+ aria-label="Close"
|
|
|
+ class="absolute top-4 right-4 z-10 inline-flex items-center gap-2 rounded-full bg-white px-4 py-2 text-sm font-semibold text-slate-900 shadow-lg hover:bg-slate-100 focus:outline-none focus:ring-2 focus:ring-white">
|
|
|
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="18" height="18" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
|
|
|
+ <line x1="5" y1="5" x2="15" y2="15"></line>
|
|
|
+ <line x1="15" y1="5" x2="5" y2="15"></line>
|
|
|
+ </svg>
|
|
|
+ <span>Close</span>
|
|
|
+ </button>
|
|
|
+
|
|
|
+ {# The enlarged image itself — `pointer-events-none` would block our
|
|
|
+ backdrop button below from the image's footprint, so we leave it
|
|
|
+ interactive but it has no click handler — clicking it does nothing. #}
|
|
|
+ <img x-bind:src="src"
|
|
|
+ x-bind:alt="alt"
|
|
|
+ class="relative max-w-[95vw] max-h-[90vh] object-contain rounded shadow-2xl">
|
|
|
+ </div>
|
|
|
+</section>
|
|
|
+{% endblock %}
|