Replaces the earlier sidebar+small-phone mock with D9's real layout: App/
Website/Email tabs (App is the only one with real content, so these are
static labels not a working control), a full-size phone mock, and a public-
site mock, plus the "Where the brand shows up" list. The phone's "Next up"
card now uses primary, not secondary -- it's a notice, not a call to action,
so it shouldn't compete visually with an actual accent-coloured button.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ECGMEwrc2k4D8VQuwjstj9
- club.website (URLField, blank) editable from both the club's own Identity
page and the platform control panel's club form.
- Colours card rebuilt from the design canvas's literal D9 markup rather
than the prior in-between version: swatch + mono hex merged into one
bordered row (the swatch input and hex text input are the same real form
field, just laid out together), and a contrast-check row of two colour-
filled boxes instead of a plain text list -- labelled dynamically
("Black"/"White" on primary/secondary) since a club can pick a colour
light enough that black, not white, is the real computed text colour.
- Logo card restyled to D9's dashed drop-zone look.
- Live preview gains a mobile app mock (marked "Coming soon") alongside the
existing sidebar mock, using the same primary/secondary colours, ahead of
that surface actually being built.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ECGMEwrc2k4D8VQuwjstj9
Two columns (form left, preview right, matching D9) with a mini mock of this
app's own sidebar + a sample button -- primary_color/secondary_color are
what those actually control (base.html's --tenant-* properties), so the
preview reflects a real surface rather than D9's aspirational App/Website/
Email tabs. Colour swatch pickers sync with the existing hex text fields in
both directions, and a contrast-ratio row mirrors Club._content_color_for's
exact WCAG math client-side, so the ✓/⚠ shown is the real number the server
computes on save.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ECGMEwrc2k4D8VQuwjstj9
Member detail: a 12-bar season attendance sparkline (present/absent/upcoming)
beside Present/Absent/No-reply totals, shown for any rostered non-guardian
member with events this season (events.services.attendance.member_attendance_
sparkline/_counts). News list: rows are one dense line (status pill inline
with the headline, everything else folded into a single meta line) instead
of the previous multi-line stacked layout that read as a small card per item.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ECGMEwrc2k4D8VQuwjstj9
Replaces the flat news list with a D8-style two-pane layout: a filterable
list on the left (All/Drafts/Scheduled/Published chips with counts) and a
preview of whichever item is selected on the right, reusing the same
article/photos/publish markup news_detail.html already had (now factored
into _news_preview.html so both pages share it). Adds an NL/EN language
toggle to the article preview -- the club's two content languages are now
switchable in place, with a fallback note when a translation is missing,
instead of a separate "English" card that only appeared once translated.
The standalone news_detail.html permalink page is unchanged behaviourally.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ECGMEwrc2k4D8VQuwjstj9
Adds the Week/Month/Season calendar to the Events page (team/group-scoped
visibility, kind-colored blocks, a repeating-series indicator) alongside the
existing table as a List view, and redesigns event/event-series creation
around a kind-first picker with progressive disclosure instead of one long
flat form. Also: an accessible radio-based kind picker (no redundant
select-next-to-cards), a fixed week-grid layout bug, a filterable single-list
redesign of the event detail page's RSVP/responses modal, a tidied-up
recurrence field layout, and assorted button/field height and width fixes
across the referee panel and event forms.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ECGMEwrc2k4D8VQuwjstj9
Large uncommitted body of work accumulated across sessions on this branch --
committing as a checkpoint so it's tracked and future worktree-isolated agents
see the real codebase instead of a stale ancestor commit. Covers the
management app's dedicated Tailwind theme and templates, the club onboarding
requirement/signup workflow (club/services/onboarding.py, requirement/status
models, sign-up dashboard), fee/status auto-activation decoupling, referee
management, and the new events calendar grid service layer.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ECGMEwrc2k4D8VQuwjstj9
Replace the mobile nav's horizontal scroll strip (which wrapped into
an unreadable jumble because daisyUI's .menu sets flex-wrap: wrap and
.menu-horizontal never resets it) with a hamburger button that opens
a proper left-side drawer, mirrored in controlpanel for the same bug.
Move the theme toggle, "Management", and "Django admin" controls into
that drawer below `lg`, leaving only the account icon in the navbar,
so the club name has room to render in full instead of truncating to
initials.
Add a reusable `.table-cards` CSS pattern (app.css) that turns a list
table into a stack of labelled cards below `md`, and apply it to every
list/detail table in the management app -- members, families, teams,
memberships, events, groups, locations, opponents, positions, referee
levels/list, roles, sponsors, news, parent claims, team roster/staff,
and the shared family-members table. Tables revert to normal desktop
layout at `md` and up.
Member list gets extra passes: search submits icon-only below `sm` so
it fits next to the input, the Members/Guardians/Both tabs go
full-width, and last/first name merge into one column. Action-button
rows across every page stack full-width on mobile instead of wrapping
mid-button (shared fix in base.html). Home dashboard's upcoming-events
and news mini-tables become simple lists instead of overflowing
tables. Also: brand truncates instead of overflowing on a long club
name, a stray invalid xmlns attribute removed, a wrapping UUID badge
hidden below `sm` on team detail.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The Docker image's CSS build stage only COPYed assets, templates,
controlpanel and billing before running npm run build -- management
and club were never in that build context, even though assets/app.css's
@source lines already listed (or, for club, should have listed) them.
Any utility class used only inside those two apps' templates was
silently absent from the compiled static/css/app.css in production,
while working fine locally since `npm run build` there scans the full
checkout rather than a Docker COPY subset.
This is what made management/home.html's md:grid-cols-5 (the dashboard
KPI grid fix from earlier) never take effect on the server: the class
just didn't exist in production's CSS, so the grid silently fell back
to sm:grid-cols-2 at every width.
Verified by reproducing the exact Docker build context outside Docker:
md:grid-cols-5 is absent from the compiled CSS with the old COPY list,
present with the new one.
club/templates has no live bug today (everything it uses is also used
elsewhere), but it's the same gap and cheap to close before it bites.
Gives clubs a self-service /manage/ area for members, families, teams,
roles, and season memberships, alongside real fee-payment tracking
(FeePayment, record_payment/mark_as_paid/remaining_balance) so a
membership's paid status reflects actual money received instead of a
single manually-set flag.
Wraps the uploaded logo in the same avatar shape as the initials
fallback (so the header doesn't jump in size depending on whether a
club has one) and adds a ring in the club's own primary colour as a
plain border around it.
Also hints the browser to use its higher-quality image scaler: a
club's raster logo is often much smaller than the badge it's shown in,
and the default upscaling in some engines reads as pixelated. Doesn't
affect SVG logos, which scale losslessly regardless.
One server now, the same image and env vars for many later: point
DJANGO_DATABASE_URL / DJANGO_REDIS_URL at central services, set a bucket, drop the
db and redis services, run several web containers behind a load balancer. No code
changes.
The wildcard certificate is what shapes this. Subdomain tenancy needs
*.rosterchief.app, and Let's Encrypt will not issue a wildcard over HTTP-01 -- only
DNS-01 -- so Caddy is built with a DNS provider plugin and needs an API token. That
single constraint is why the proxy is Caddy rather than the usual nginx+certbot.
The image apt-installs libpango and friends, which is what WeasyPrint binds to. The
PDF invoices that cannot render on a Mac without Homebrew work in the container by
construction.
Migrations are NOT run by the entrypoint: with more than one web container they
would race, and a starting gunicorn worker is a bad place to discover a failed
migration. Deploy runs them once, explicitly.
Two things the local build check caught, either of which would have failed the
image build at collectstatic (manifest storage treats a missing referenced file as
fatal):
- chart.js ended with a sourceMappingURL pointing at a .map we never vendored.
Stripped, with an npm script so re-vendoring cannot bring it back.
- The Tailwind INPUT file lived at static/src/app.css, inside the served static
tree, so collectstatic collected it and then choked on its @import "tailwindcss".
It belongs outside: it is a build input, not an asset. Now assets/app.css.
Verified locally under gunicorn + WhiteNoise + manifest storage: pages serve and
the CSS comes back hashed. The image itself is unverified -- there is no container
runtime on this machine.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>