2
CannaManage 06 Wireframes
Patrick Plate edited this page 2026-04-06 13:19:28 +02:00
This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

CannaManage — Wireframes & UI Mockups

Phase 4a | Document 6 of 7
Date: 2026-04-06
Stack: Spring Boot 3.x · React/Vite SPA · PostgreSQL


Table of Contents

  1. Design System Overview
  2. Admin Portal Screens
  3. Member Portal Screens
  4. Navigation & Information Architecture
  5. Responsive Design Notes
  6. Accessibility

1. Design System Overview

1.1 Color Palette

Token Hex Usage
--color-primary #2D5016 Sidebar background, primary buttons, active nav items
--color-primary-medium #4A7C28 Hover states, section headers, badge outlines
--color-accent #8BC34A Highlights, progress bars filled, success indicators
--color-bg #F5F5F5 Page background, card backgrounds
--color-text #1A1A1A Body text, table cell content
--color-warning #FF6B35 Quota >80%, low stock, warnings
--color-error #D32F2F Quota exceeded, recalled batches, destructive actions
--color-white #FFFFFF Sidebar text, button labels on dark bg, card surfaces

1.2 Typography

Element Font Size Weight
H1 — Page title Inter 24px 600
H2 — Section heading Inter 18px 600
H3 — Card title Inter 14px 600
Body / table rows Inter 14px 400
Caption / label Inter 12px 400
Mono (codes, IDs) JetBrains Mono 13px 400

1.3 Component Library

The frontend is a React/Vite SPA with no PrimeFaces or JSF dependency. Component primitives come from shadcn/ui (Radix UI + Tailwind CSS). This gives full control over styling, accessibility, and mobile responsiveness without JSF's lifecycle overhead.

Why not PrimeFaces? JSF/PrimeFaces is a server-side component model ill-suited to the modern REST API backend we're building. It tightly couples UI lifecycle to the backend, makes mobile responsiveness painful, and creates a hiring bottleneck. React is the right tool here. PrimeFaces is a fine choice for internal enterprise apps — not for a commercial SaaS.

Component Library Usage
Card / Panel shadcn/ui Section containers
DataTable TanStack Table v8 Distributions, members, batches — virtualized
Pagination shadcn/ui Pagination All tables
Input shadcn/ui Input Single-line text fields
NumberInput react-number-format Weight inputs (gram precision, min/max)
Select shadcn/ui Select Dropdown selects (member, strain, batch)
DatePicker shadcn/ui Calendar Date range pickers for reports
Progress shadcn/ui Progress Quota consumption bar
Button shadcn/ui Button Primary and secondary actions
AlertDialog shadcn/ui AlertDialog Dangerous actions (recall)
Toast sonner Success/error notifications
Badge shadcn/ui Badge Status indicators (AVAILABLE, LOW, RECALLED)
Sheet shadcn/ui Sheet Mobile nav drawer
Dialog shadcn/ui Dialog Modal overlays

1.4 Layout Grid

┌────────────────────────────────────────────────────┐
│  TOP NAVBAR (56px)  club name · avatar · logout    │
├──────────────┬─────────────────────────────────────┤
│              │                                     │
│   SIDEBAR    │         MAIN CONTENT                │
│   (240px)    │         (fluid, min 784px)          │
│   fixed      │                                     │
│              │                                     │
└──────────────┴─────────────────────────────────────┘
  • Sidebar: fixed left, #2D5016 background, white nav labels with #8BC34A icons
  • Top Navbar: #FFFFFF with bottom border #E0E0E0, breadcrumb left, user controls right
  • Main Content: #F5F5F5 background, 24px padding, max content width 1200px centered

2. Admin Portal Screens

Screen 1 — Admin Dashboard

Admin Dashboard

ASCII Wireframe

┌─────────────────────────────────────────────────────────────────────┐
│  🌿 CannaManage          Grüne Oase Berlin e.V.   👤 Max M.  [⏻]   │
├────────────┬────────────────────────────────────────────────────────┤
│            │  Dashboard                           🗓 April 2026     │
│  📊 Dashboard◄│                                                      │
│            │  ┌──────────────┐ ┌──────────────┐ ┌───────────────┐  │
│  👥 Members│  │ Total Members│ │  Distributions│ │ Stock Available│ │
│            │  │              │ │  This Month   │ │               │  │
│  📋 Distrib│  │     142      │ │      87       │ │   3,240 g     │  │
│            │  │  ▲ +3 MoM   │ │  ▲ +12 MoM   │ │  ▼ -800g MoM │  │
│  📦 Stock  │  └──────────────┘ └──────────────┘ └───────────────┘  │
│            │                                                         │
│  📄 Reports│  Recent Distributions                    [+ New Entry] │
│            │  ┌─────────────────────────────────────────────────┐   │
│  ✅ Complian│  │ Member      │ Strain      │  Qty  │ Date  │ ✓  │   │
│            │  ├─────────────┼─────────────┼───────┼───────┼────┤   │
│  ⚙ Settings│  │ Müller, A.  │ OG Kush B12 │  5.0g │ 06.04 │ ✓  │   │
│            │  │ Schmidt, K. │ Amnesia H09 │  3.5g │ 06.04 │ ✓  │   │
│            │  │ Weber, T.   │ OG Kush B12 │  7.0g │ 05.04 │ ✓  │   │
│            │  │ …           │             │       │       │    │   │
└────────────┴──┴─────────────────────────────────────────────────────┘

Components & Behavior

Component Library Behavior
KPI Cards shadcn/ui Card Auto-refreshed via useQuery (react-query, 60s stale)
Recent Distributions table TanStack Table (5 rows) Row click → navigate to distribution detail
Member column link React Router <Link> Navigate to /admin/members/{id}
+ New Entry button shadcn/ui Button variant="default" Navigate to /admin/distributions/new
Trend indicators Tailwind text-green-600 / text-red-600 ▲/▼ with delta value

Screen 2 — Distribution Recording Form

Distribution Form

ASCII Wireframe

┌─────────────────────────────────────────────────────────────────────┐
│  🌿 CannaManage          Grüne Oase Berlin e.V.   👤 Max M.  [⏻]   │
├────────────┬────────────────────────────────────────────────────────┤
│            │  Distributions  New Distribution                      │
│  📊 Dashbrd│                                                         │
│            │  ┌──────────────────────────────────────────────────┐  │
│  👥 Members│  │  Member *                                         │  │
│            │  │  ┌──────────────────────────────────────────┐    │  │
│  📋 Distrib◄│  │  │  🔍 Search by name or member no.         │    │  │
│            │  │  └──────────────────────────────────────────┘    │  │
│  📦 Stock  │  │                                                    │  │
│            │  │  Strain / Batch *                                 │  │
│  📄 Reports│  │  ┌──────────────────────────────────────────┐    │  │
│            │  │  │  Select available batch           ▼      │    │  │
│  ✅ Complian│  │  └──────────────────────────────────────────┘    │  │
│            │  │                                                    │  │
│  ⚙ Settings│  │  Weight (grams) *                                 │  │
│            │  │  ┌──────────┐                                     │  │
│            │  │  │   0.0 g  │  ← p:inputNumber min=0.1 max=25    │  │
│            │  │  └──────────┘                                     │  │
│            │  │                                                    │  │
│            │  │  Monthly Quota — Müller, Anna                     │  │
│            │  │  ████████████░░░░░░░░  32.5g / 50g  65%          │  │
│            │  │  [████████████████░░░] <- p:progressBar           │  │
│            │  │                                                    │  │
│            │  │  [    Record Distribution    ]  [Cancel]          │  │
│            │  └──────────────────────────────────────────────────┘  │
└────────────┴────────────────────────────────────────────────────────┘

Compliance UX — Real-Time Quota Indicator

The quota progress bar updates live as the weight field changes (via f:ajax event="keyup"):

Quota Used After Distribution Bar Color Submit Button Message
079% #8BC34A (green) Enabled
8099% #FF6B35 (orange) Enabled "⚠ Approaching monthly limit"
100% #D32F2F (red) Disabled "🚫 Monthly limit reached (50g)"
Over-21 member, >30g monthly #D32F2F (red) Disabled "🚫 Under-21 limit reached (30g)"

Components & Behavior

Component Library Behavior
Member search shadcn/ui Combobox useQuery debounced search; shows name + member no.
Strain/Batch dropdown shadcn/ui Select Populated after member selection; filters AVAILABLE batches
Weight input react-number-format min=0.1 max=25.0 step=0.1; triggers quota recalculation via onChange
Quota bar shadcn/ui Progress Color class via cn() utility computed in component state
Submit shadcn/ui Button disabled={quotaExceeded} from react state
Cancel React Router <Link> Returns to distribution log without saving

Screen 3 — Stock Management

Stock Management

ASCII Wireframe

┌─────────────────────────────────────────────────────────────────────┐
│  🌿 CannaManage          Grüne Oase Berlin e.V.   👤 Max M.  [⏻]   │
├────────────┬────────────────────────────────────────────────────────┤
│            │  Stock Management                    [+ Add Batch]     │
│  📊 Dashbrd│                                                         │
│            │  ┌──────────────────────┐  ┌────────────────────┐     │
│  👥 Members│  │ 🔍 Filter by strain   │  │ Status: All     ▼  │     │
│            │  └──────────────────────┘  └────────────────────┘     │
│  📋 Distrib│                                                         │
│            │  ┌───────────────────────────────────────────────────┐ │
│  📦 Stock ◄│  │ Strain       │Batch│THC% │CBD%│  Qty  │Status│Act │ │
│            │  ├──────────────┼─────┼─────┼────┼───────┼──────┼────┤ │
│  📄 Reports│  │ OG Kush      │B-12 │ 19% │ 1% │ 850g  │  ●   │[R] │ │
│            │  │ Amnesia Haze │H-09 │ 22% │<1% │  72g  │  ⚠   │[R] │ │
│  ✅ Complian│  │ Blue Dream   │D-05 │ 17% │ 2% │    0g │  —   │[R] │ │
│            │  │ Hindu Kush   │K-21 │  8% │15% │ 340g  │  ✓   │[R] │ │
│  ⚙ Settings│  │ AK-47 #4    │A-03 │ 20% │ 1% │  RECALLED  │ ⛔ │[R] │ │
│            │  └───────────────────────────────────────────────────┘ │
│            │  [◄ 1 2 3 … ►]                        Showing 1-10/42 │
└────────────┴────────────────────────────────────────────────────────┘

Status Badges

Badge Color Icon Condition
AVAILABLE #4A7C28 bg ✓ checkmark qty > 100g and not recalled
LOW #FF6B35 bg ⚠ warning 0 < qty ≤ 100g
EXHAUSTED #9E9E9E bg — dash qty = 0
RECALLED #D32F2F bg stop recall_date IS NOT NULL

Components & Behavior

Component Library Behavior
Strain filter shadcn/ui Input Filters TanStack table client-side via columnFilters state
Status filter shadcn/ui Select Filters table rows by status value
Batch table TanStack Table Server-side pagination via manualPagination, 10 rows/page
Status badge shadcn/ui Badge variant mapped Icon + text label (not color alone)
Recall button shadcn/ui Button variant="destructive" Opens shadcn/ui AlertDialog before executing
Confirm dialog shadcn/ui AlertDialog "Recall batch B-12 (OG Kush, 850g)? This cannot be undone."
Add Batch shadcn/ui Button Opens shadcn/ui Dialog with batch entry form

Screen 4 — Compliance Report Generation

Compliance Report

ASCII Wireframe

┌─────────────────────────────────────────────────────────────────────┐
│  🌿 CannaManage          Grüne Oase Berlin e.V.   👤 Max M.  [⏻]   │
├────────────┬────────────────────────────────────────────────────────┤
│            │  Reports  Monthly Compliance Report                   │
│  📊 Dashbrd│                                                         │
│            │  ┌─────────────────────────────────────────────────┐  │
│  👥 Members│  │  Reporting Period                                │  │
│            │  │  Month: [ March ▼ ]   Year: [ 2026 ▼ ]          │  │
│  📋 Distrib│  │                         [ Generate Report ]      │  │
│            │  └─────────────────────────────────────────────────┘  │
│  📦 Stock  │                                                         │
│            │  ┌─────────────────────────────────────────────────┐  │
│  📄 Reports◄│  │  PDF PREVIEW                                    │  │
│            │  │  ┌─────────────────────────────────────────┐    │  │
│  ✅ Complian│  │  │ 🌿 CannaManage — Monthly Report Mar 2026 │    │  │
│            │  │  │ Club: Grüne Oase Berlin e.V.            │    │  │
│  ⚙ Settings│  │  │ ─────────────────────────────────────── │    │  │
│            │  │  │ Total Members:              142          │    │  │
│            │  │  │ Active Members (distributed): 87        │    │  │
│            │  │  │ Total Distributed:         435.5g       │    │  │
│            │  │  └─────────────────────────────────────────┘    │  │
│            │  │                                                    │  │
│            │  │  [⬇ Download PDF]   [⬇ Download CSV]             │  │
│            │  └─────────────────────────────────────────────────┘  │
│            │                                                         │
│            │  Summary Table                                         │
│            │  ┌────────────────────────────────────────────────┐   │
│            │  │ Metric               │ Value     │ Limit        │   │
│            │  ├──────────────────────┼───────────┼─────────────┤   │
│            │  │ Members >50g/month   │     0     │ Must be 0   │   │
│            │  │ Members >30g (U21)   │     0     │ Must be 0   │   │
│            │  │ Recalled Batches     │     1     │ — (info)    │   │
│            │  │ Avg grams / member   │   5.0g    │ —           │   │
│            │  └────────────────────────────────────────────────┘   │
└────────────┴────────────────────────────────────────────────────────┘

Components & Behavior

Component Library Behavior
Month selector shadcn/ui Select Months JanDec
Year selector shadcn/ui Select Current year ± 2
Generate button shadcn/ui Button Calls report API; shows loading spinner; renders PDF thumbnail
PDF preview <iframe> embedding /api/v1/reports/preview?month=3&year=2026 Generated by iText 7 backend
Download PDF shadcn/ui Button window.open(reportUrl) — streams PDF from REST endpoint
Download CSV shadcn/ui Button window.open(csvUrl) — streams CSV from REST endpoint
Summary table TanStack Table Compliance metrics; zero violations row has text-green-600

3. Member Portal Screens

Screen 5 — Member Dashboard / Quota View

Member Quota

ASCII Wireframe

┌────────────────────────────────────────────────────┐
│  🌿 CannaManage           Anna Müller  #M-0042     │
│  ──────────────────────────────────────────────    │
│                                                    │
│           Monthly Quota Remaining                  │
│                                                    │
│               ╭───────────────╮                    │
│               │               │                    │
│               │   17.5 g      │                    │
│               │  remaining    │                    │
│               │               │                    │
│               │  of 50g/month │                    │
│               ╰───────────────╯                    │
│          ▓▓▓▓▓▓▓▓▓▓▓░░░░░░░ 65% used              │
│                                                    │
│  Distribution History                              │
│  ┌────────────────────────────────────────────┐   │
│  │ Date       │ Strain       │ Quantity       │   │
│  ├────────────┼──────────────┼────────────────┤   │
│  │ 06.04.2026 │ OG Kush      │ 5.0g           │   │
│  │ 02.04.2026 │ Amnesia Haze │ 12.5g          │   │
│  │ 28.03.2026 │ OG Kush      │ 15.0g          │   │
│  └────────────┴──────────────┴────────────────┘   │
│                                                    │
│  Available Strains                                 │
│  ┌────────────────────────────────────────────┐   │
│  │ Strain       │ Availability               │   │
│  ├──────────────┼─────────────────────────────┤   │
│  │ OG Kush      │ ● Available                │   │
│  │ Amnesia Haze │ ⚠ Limited                  │   │
│  │ Hindu Kush   │ ● Available                │   │
│  └────────────────────────────────────────────┘   │
│                                                    │
└────────────────────────────────────────────────────┘

Compliance Note — Available Strains Display

Per CanG §§67, members may NOT see specific batch quantities or total stock levels. The Available Strains table shows only:

  • Strain name
  • Availability status (Available / Limited / Unavailable)

Quantities, batch codes, and THC/CBD percentages are not exposed in the member portal.

Components & Behavior

Component Library Behavior
Quota circle Custom CSS radial progress (conic-gradient) Computed from monthly total; color matches threshold rules
Quota bar shadcn/ui Progress Same color logic as admin distribution form
History table TanStack Table Last 10 distributions; sorted newest first; no pagination in MVP
Strains table TanStack Table status column: text + icon only, no quantities

Screen 6 — Member Login

No mockup image — ASCII wireframe only.


Screen 7 — Staff Management (Admin)

Core feature — not deferred to v2.

ASCII Wireframe

┌─────────────────────────────────────────────────────────────────────┐
│  🌿 CannaManage          Grüne Oase Berlin e.V.   👤 Max M.  [⏻]   │
├────────────┬────────────────────────────────────────────────────────┤
│            │  Settings  Staff Members             [+ Add Staff]    │
│  📊 Dashbrd│                                                         │
│            │  ┌──────────────────────────────────────────────────┐  │
│  👥 Members│  │  Name           │ Role Template │ Permissions │ Act│ │
│            │  ├─────────────────┼───────────────┼─────────────┼────┤ │
│  📋 Distrib│  │ Lisa Schmidt    │ Ausgabe       │ 3 of 8      │[✎][⛔]│
│            │  │ Tom Weber       │ Lager         │ 4 of 8      │[✎][⛔]│
│  📦 Stock  │  │ Sandra Müller   │ Vorstand      │ 7 of 8      │[✎][⛔]│
│            │  └──────────────────────────────────────────────────┘  │
│  📄 Reports│                                                         │
│            │  ┌─── Add / Edit Staff ──────────────────────────────┐ │
│  ✅ Complian│  │  Name: _______________  Email: _______________    │ │
│            │  │                                                    │ │
│  👤 Staff  │  │  Role Template: [ Ausgabe ▼ ]  (pre-fills below)  │ │
│            │  │                                                    │ │
│  ⚙ Settings│  │  Permissions:                                      │ │
│            │  │  ☑ Record Distribution    ☑ View Member List      │ │
│            │  │  ☑ View Member Quota      ☐ Add Member            │ │
│            │  │  ☐ View Stock             ☐ Record Stock In       │ │
│            │  │  ☐ View Compliance Report ☐ Manage Grow Calendar  │ │
│            │  │                                                    │ │
│            │  │  [ Save Staff Member ]  [ Cancel ]                │ │
│            │  └────────────────────────────────────────────────────┘ │
└────────────┴────────────────────────────────────────────────────────┘

Design Decisions

  • Admin sees everything. The staff management screen is only accessible with ROLE_CLUB_ADMIN. Staff accounts cannot modify their own permissions.
  • DSGVO principle of least privilege. Each staff member only sees the data their role requires. A distribution desk worker (Ausgabe) does not see cultivation calendar or full stock levels — only what they need to hand out product.
  • Pre-created role templates reduce admin setup time. Templates are editable — they just pre-fill the permission checkboxes.
  • Staff ≠ reduced admin. Staff accounts do not have access to billing, club settings, or staff management. Even a "Vorstand" staff member cannot create other staff accounts.
  • Audit trail. All distributions recorded by staff include recorded_by = staffUserId so it's clear who did what.

Components & Behavior

Component Library Behavior
Staff table TanStack Table Shows name, role template, permission count, actions
Role template dropdown shadcn/ui Select Pre-populates permission checkboxes on selection
Permission checkboxes shadcn/ui Checkbox Individual overrides after template selection
Save shadcn/ui Button POST/PUT /api/v1/staff with { permissions: [...] }
Deactivate shadcn/ui Button variant="destructive" Soft-deletes staff account; data retained for audit

ASCII Wireframe

┌──────────────────────────────────────────┐
│                                          │
│            🌿 CannaManage                │
│                                          │
│   ┌──────────────────────────────────┐   │
│   │  E-Mail Address                  │   │
│   │  ┌────────────────────────────┐  │   │
│   │  │ you@example.com            │  │   │
│   │  └────────────────────────────┘  │   │
│   │                                  │   │
│   │  Password                        │   │
│   │  ┌────────────────────────────┐  │   │
│   │  │ ••••••••••••               │  │   │
│   │  └────────────────────────────┘  │   │
│   │                                  │   │
│   │  [ ████ Log In ████████████ ]   │   │
│   └──────────────────────────────────┘   │
│                                          │
│   Problems logging in?                   │
│   Contact your club administrator.       │
│                                          │
└──────────────────────────────────────────┘

Design Decisions

  • No self-registration link — member accounts are created exclusively by admins via the admin portal. The login page has no "Create account" or "Sign up" flow.
  • No forgot-password link — password resets are initiated by the club admin only. The login page directs users to contact their admin, avoiding email-based reset flows that would require verified email infrastructure in MVP.
  • No social login — DSGVO compliance and club accountability require traceable credential management.
  • Form submission: POST to /login (Spring Security form login), redirect to /member/dashboard on success.

Components & Behavior

Component Library Behavior
Email field shadcn/ui Input type="email" HTML5 validation + react-hook-form @Email
Password field shadcn/ui Input type="password" No strength meter on login
Login button shadcn/ui Button Submit via react-hook-form; shows error toast on failure
Error message sonner toast "Invalid email or password." (never specific about which field failed)

4. Navigation & Information Architecture

graph TD
    Root["CannaManage Root"]
    Root --> AdminPortal["Admin Portal /admin/"]
    Root --> MemberPortal["Member Portal /member/"]
    Root --> StaffPortal["Staff Portal /staff/"]

    AdminPortal --> AdminDash["Dashboard (default)"]
    AdminPortal --> Members["Members"]
    Members --> MemberList["Member List"]
    Members --> MemberDetail["Member Detail"]
    AdminPortal --> Distributions["Distributions"]
    Distributions --> DistLog["Distribution Log"]
    Distributions --> NewDist["New Distribution"]
    AdminPortal --> Stock["Stock"]
    Stock --> Strains["Strains"]
    Stock --> Batches["Batches"]
    AdminPortal --> Reports["Reports"]
    Reports --> MonthlyReport["Monthly Compliance"]
    Reports --> MemberExport["Member Export"]
    Reports --> RecallReport["Batch Recall Report"]
    AdminPortal --> Compliance["Compliance"]
    Compliance --> PreventionOfficer["Prevention Officer Info"]
    AdminPortal --> StaffMgmt["Staff Members"]
    StaffMgmt --> StaffList["Staff List"]
    StaffMgmt --> StaffNew["Add/Edit Staff"]
    AdminPortal --> Settings["Settings"]
    Settings --> ClubProfile["Club Profile"]

    StaffPortal --> StaffDash["Staff Dashboard\n(permissions-filtered)"]

    MemberPortal --> MemberDash["Dashboard / Quota"]
    MemberPortal --> DistHistory["Distribution History"]
    MemberPortal --> StockAvail["Stock Availability"]

URL Structure

Path Description Role
/login Login page Public
/admin/dashboard Admin home ROLE_ADMIN
/admin/members Member list ROLE_ADMIN
/admin/members/{id} Member detail ROLE_ADMIN
/admin/distributions Distribution log ROLE_ADMIN
/admin/distributions/new New distribution form ROLE_ADMIN
/admin/stock/strains Strain catalog ROLE_ADMIN
/admin/stock/batches Batch management ROLE_ADMIN
/admin/reports/monthly Compliance reports ROLE_ADMIN
/admin/reports/members Member data export ROLE_ADMIN
/admin/reports/recall Recall report ROLE_ADMIN
/admin/compliance Prevention officer ROLE_ADMIN
/admin/staff Staff list ROLE_ADMIN
/admin/staff/new Create staff account ROLE_ADMIN
/admin/staff/{id} Edit staff permissions ROLE_ADMIN
/admin/settings Club settings ROLE_ADMIN
/staff/dashboard Staff home (permissions-filtered) ROLE_STAFF
/member/dashboard Member quota view ROLE_MEMBER
/member/distributions Personal history ROLE_MEMBER
/member/stock Strain availability ROLE_MEMBER

5. Responsive Design Notes

MVP (v1) — Tailwind Breakpoints

The React/Vite SPA uses Tailwind CSS breakpoints throughout. The switch from PrimeFaces means we no longer depend on JSF's ui-g-* responsive grid — Tailwind's sm: / md: / lg: utilities apply cleanly to every component.

Breakpoint Tailwind prefix Admin Portal Member Portal
≥ 1280px xl: Full layout — sidebar + content Two-column: quota left, history right
10241279px lg: Sidebar collapses to icons (60px) Two-column (narrower)
7681023px md: Sidebar hidden; hamburger sheet Single-column, full-width cards
< 768px sm: / base Admin: horizontal table scroll Member: compact quota ring, condensed table

Member Portal — Mobile-First from Day One

Members will typically check quota status on their phone. The member portal uses flex-col mobile-first layout with md:flex-row for wider viewports — no breakpoint-specific class sprawl.

Responsive Conventions (React/Tailwind)

  • No inline styles — use Tailwind utilities exclusively
  • cn() utility (clsx + tailwind-merge) for conditional class composition
  • Tables on mobile: horizontal scroll wrapper overflow-x-auto on <div> wrapping <table>
  • All modals and sheets use shadcn/ui Dialog / Sheet — these are already mobile-friendly (viewport-aware positioning)
  • Touch targets: all interactive elements min-h-[44px] and min-w-[44px] per WCAG 2.5.5

v2 Roadmap

  • PWA manifest + service worker (offline quota display)
  • Push notifications for low quota warnings
  • Per-club subdomain routing (clubname.cannamanage.de)

6. Accessibility

CannaManage targets WCAG 2.1 AA compliance across both portals.

Keyboard Navigation

Element Keyboard Behavior
Navigation sidebar Tab navigates items; Enter activates
Data tables Tab to table; arrow keys for row navigation
Dropdown menus Enter/Space to open; arrow keys to navigate; Escape to close
Modal dialogs Focus trapped inside; Escape to close; first focusable element receives focus on open
Confirmation dialogs Tab between Confirm and Cancel; Enter on focused button

Screen Reader Support

  • All Input / NumberInput fields have <label> with htmlFor (React) — Radix UI enforces this automatically for shadcn/ui form fields
  • aria-label set on icon-only buttons (e.g., recall action column)
  • aria-live="polite" region on quota bar — announces percentage changes
  • aria-describedby links compliance warning messages to the weight input
  • TanStack Table exposes role="grid" and aria-rowcount via getTableProps()

Color Independence

Status badges must never rely on color alone:

Status Color Icon Text label
AVAILABLE Green "Available"
LOW Orange "Low Stock"
RECALLED Red "Recalled"
EXHAUSTED Gray "Exhausted"

Quota progress bar additionally shows numeric percentage text alongside color change.

Contrast Ratios

Foreground Background Ratio AA pass
#FFFFFF #2D5016 9.1:1
#1A1A1A #F5F5F5 16.0:1
#1A1A1A #FFFFFF 19.0:1
#FFFFFF #D32F2F 5.1:1
#FFFFFF #FF6B35 3.1:1 ⚠ verify at large text only

Next: 07-CODING-STANDARDS.md