docs(design): add design system with typography, colors, and mobile specs

Industrial/utilitarian aesthetic with amber accent, Space Grotesk + DM Sans +
JetBrains Mono stack, full dark mode, and dedicated mobile design including
bottom nav and card-based order views. Updates CLAUDE.md to enforce DESIGN.md
compliance on all visual work.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-03-27 10:29:13 +00:00
parent 7a1fa16fef
commit 9f2fd24d93
3 changed files with 350 additions and 71 deletions

View File

@@ -106,6 +106,13 @@ python3 scripts/sync_vending_to_mariusm.py --apply --yes
Sincronizează via SSH din VENDING (prod Windows) în MARIUSM_AUTO (dev ROA_CENTRAL):
nom_articole (noi by codmat, codmat updatat) + articole_terti (noi, modificate, soft-delete).
## Design System
Always read DESIGN.md before making any visual or UI decisions.
All font choices, colors, spacing, and aesthetic direction are defined there.
Do not deviate without explicit user approval.
In QA mode, flag any code that doesn't match DESIGN.md.
## Deploy Windows
Vezi [README.md](README.md#deploy-windows)

318
DESIGN.md Normal file
View File

@@ -0,0 +1,318 @@
# Design System — GoMag Vending
## Product Context
- **What this is:** Internal admin dashboard for importing web orders from GoMag e-commerce into ROA Oracle ERP
- **Who it's for:** Ops/admin team who monitor order sync daily, fix SKU mappings, check import errors
- **Space/industry:** Internal tools, B2B operations, ERP integration
- **Project type:** Data-heavy admin dashboard (tables, status indicators, sync controls)
## Aesthetic Direction
- **Direction:** Industrial/Utilitarian — function-first, data-dense, quietly confident
- **Decoration level:** Minimal — typography and color do the work. No illustrations, gradients, or decorative elements. The data IS the decoration.
- **Mood:** Command console. This tool says "built by someone who respects the operator." Serious, efficient, warm.
- **Anti-patterns:** No purple gradients, no 3-column icon grids, no centered-everything layouts, no decorative blobs, no stock-photo heroes
## Typography
### Font Stack
- **Display/Headings:** Space Grotesk — geometric, slightly techy, distinctive `a` and `g`. Says "engineered."
- **Body/UI:** DM Sans — clean, excellent readability, good tabular-nums for inline numbers
- **Data/Tables:** JetBrains Mono — order IDs, CODMATs, status codes align perfectly. Tables become scannable.
- **Code:** JetBrains Mono
### Loading
```html
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700;1,9..40,400&family=JetBrains+Mono:wght@400;500;600&family=Space+Grotesk:wght@400;500;600;700&display=swap" rel="stylesheet">
```
### CSS Variables
```css
--font-display: 'Space Grotesk', sans-serif;
--font-body: 'DM Sans', sans-serif;
--font-data: 'JetBrains Mono', monospace;
```
### Type Scale
| Level | Size | Weight | Font | Usage |
|-------|------|--------|------|-------|
| Page title | 18px | 600 | Display | "Panou de Comanda" |
| Section title | 16px | 600 | Display | Card headers |
| Label/uppercase | 12px | 500 | Display | Column headers, section labels (letter-spacing: 0.04em) |
| Body | 14px | 400 | Body | Paragraphs, descriptions |
| UI/Button | 13px | 500 | Body | Buttons, nav links, form labels |
| Data cell | 13px | 400 | Data | Table cells, order IDs |
| Data small | 12px | 400 | Data | Timestamps, secondary data |
| Code/mono | 11px | 400 | Data | Inline code, debug info |
## Color
### Approach: Restrained with warm accent
Every admin tool is blue. This one uses amber — reads as "operational" and "attention-worthy."
### Light Mode (default)
```css
:root {
/* Surfaces */
--bg: #F8F7F5; /* warm off-white, not clinical gray */
--surface: #FFFFFF;
--surface-raised: #F3F2EF; /* hover states, table headers */
--card-shadow: 0 1px 3px rgba(28,25,23,0.1), 0 1px 2px rgba(28,25,23,0.06);
/* Text */
--text-primary: #1C1917; /* warm black */
--text-secondary: #57534E; /* warm gray */
--text-muted: #78716C; /* labels, timestamps */
/* Borders */
--border: #E7E5E4;
--border-subtle: #F0EFED;
/* Accent — amber */
--accent: #D97706;
--accent-hover: #B45309;
--accent-light: #FEF3C7; /* amber backgrounds */
--accent-text: #92400E; /* text on amber bg */
/* Semantic */
--success: #16A34A;
--success-light: #DCFCE7;
--success-text: #166534;
--warning: #CA8A04;
--warning-light: #FEF9C3;
--warning-text: #854D0E;
--error: #DC2626;
--error-light: #FEE2E2;
--error-text: #991B1B;
--info: #2563EB;
--info-light: #DBEAFE;
--info-text: #1E40AF;
--cancelled: #78716C;
--cancelled-light: #F5F5F4;
}
```
### Dark Mode
Strategy: invert surfaces, reduce accent saturation ~15%, keep semantic colors recognizable.
```css
[data-theme="dark"] {
--bg: #121212;
--surface: #1E1E1E;
--surface-raised: #2A2A2A;
--card-shadow: 0 1px 3px rgba(0,0,0,0.4), 0 1px 2px rgba(0,0,0,0.3);
--text-primary: #E8E4DD; /* warm bone white */
--text-secondary: #A8A29E;
--text-muted: #78716C;
--border: #333333;
--border-subtle: #262626;
--accent: #F59E0B;
--accent-hover: #D97706;
--accent-light: rgba(245,158,11,0.12);
--accent-text: #FCD34D;
--success: #16A34A;
--success-light: rgba(22,163,74,0.15);
--success-text: #4ADE80;
--warning: #CA8A04;
--warning-light: rgba(202,138,4,0.15);
--warning-text: #FACC15;
--error: #DC2626;
--error-light: rgba(220,38,38,0.15);
--error-text: #FCA5A5;
--info: #2563EB;
--info-light: rgba(37,99,235,0.15);
--info-text: #93C5FD;
--cancelled: #78716C;
--cancelled-light: rgba(120,113,108,0.15);
}
```
### Status Color Mapping
| Status | Dot Color | Badge BG | Glow |
|--------|-----------|----------|------|
| IMPORTED | `--success` | `--success-light` | none (quiet when healthy) |
| ERROR | `--error` | `--error-light` | `0 0 8px 2px rgba(220,38,38,0.35)` |
| SKIPPED | `--warning` | `--warning-light` | `0 0 6px 2px rgba(202,138,4,0.3)` |
| ALREADY_IMPORTED | `--info` | `--info-light` | none |
| CANCELLED | `--cancelled` | `--cancelled-light` | none |
| DELETED_IN_ROA | `--cancelled` | `--cancelled-light` | none |
**Design rule:** Problems glow, success is calm. The operator's eye is pulled to rows that need action.
## Spacing
- **Base unit:** 4px
- **Density:** Comfortable — not cramped, not wasteful
- **Scale:**
| Token | Value | Usage |
|-------|-------|-------|
| 2xs | 2px | Tight internal gaps |
| xs | 4px | Icon-text gap, badge padding |
| sm | 8px | Compact card padding, table cell padding |
| md | 16px | Standard card padding, section gaps |
| lg | 24px | Section spacing |
| xl | 32px | Major section gaps |
| 2xl | 48px | Page-level spacing |
| 3xl | 64px | Hero spacing (rarely used) |
## Layout
### Approach: Grid-disciplined, full-width
Tables with 8+ columns and hundreds of rows need every pixel of width.
- **Nav:** Horizontal top bar, fixed, 48px height. Active tab has amber underline (2px).
- **Content max-width:** None on desktop (full-width for tables), 1200px for non-table content
- **Grid:** Single-column layout, cards stack vertically
- **Breakpoints:**
| Name | Width | Columns | Behavior |
|------|-------|---------|----------|
| Desktop | >= 1024px | Full width | All features visible |
| Tablet | 768-1023px | Full width | Nav labels abbreviated, tables scroll horizontally |
| Mobile | < 768px | Single column | Bottom nav, cards stack, condensed views |
### Border Radius
| Token | Value | Usage |
|-------|-------|-------|
| sm | 4px | Buttons, inputs, badges, status dots |
| md | 8px | Cards, dropdowns, modals |
| lg | 12px | Large containers, mockup frames |
| full | 9999px | Pills, avatar circles |
## Motion
- **Approach:** Minimal-functional only transitions that aid comprehension
- **Easing:** enter(ease-out) exit(ease-in) move(ease-in-out)
- **Duration:**
| Token | Value | Usage |
|-------|-------|-------|
| micro | 50-100ms | Button hover, focus ring |
| short | 150-250ms | Dropdown open, tab switch, color transitions |
| medium | 250-400ms | Modal open/close, page transitions |
| long | 400-700ms | Only for sync pulse animation |
- **Sync pulse:** The live sync dot uses a 2s infinite pulse (opacity 1 0.4 1)
- **No:** entrance animations, scroll effects, decorative motion
## Mobile Design
### Navigation
- **Bottom tab bar** replaces top horizontal nav on screens < 768px
- 5 tabs: Dashboard, Mapari, Lipsa, Jurnale, Setari
- Each tab: icon (Bootstrap Icons) + short label below
- Active tab: amber accent color, inactive: `--text-muted`
- Height: 56px, safe-area padding for notched devices
- Fixed position bottom, with `padding-bottom: env(safe-area-inset-bottom)`
```css
@media (max-width: 767px) {
.top-navbar { display: none; }
.bottom-nav {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 56px;
padding-bottom: env(safe-area-inset-bottom);
background: var(--surface);
border-top: 1px solid var(--border);
display: flex;
justify-content: space-around;
align-items: center;
z-index: 1000;
}
.main-content {
padding-bottom: 72px; /* clear bottom nav */
padding-top: 8px; /* no top navbar */
}
}
```
### Dashboard — Mobile
- **Sync card:** Full width, stacked vertically
- Status + controls row wraps to 2 lines
- Sync button full-width at bottom of card
- Last sync info wraps naturally
- **Orders table:** Condensed card view instead of horizontal table
- Each order = a compact card showing: status dot + ID + client name + total
- Tap to expand: shows date, factura, full details
- Swipe left on card: quick action (view error details)
- **Filter bar:** Horizontal scrollable chips instead of dropdowns
- Period selector: pill chips (1zi, 7zi, 30zi, Toate)
- Status filter: colored chips matching status colors
- **Touch targets:** Minimum 44x44px for all interactive elements
### Orders Mobile Card Layout
```
┌────────────────────────────────┐
│ ● CMD-47832 2,450.00 RON│
│ SC Automate Express SRL │
│ 27.03.2026 · FCT-2026-1847 │
└────────────────────────────────┘
```
- Status dot (8px, left-aligned with glow for errors)
- Order ID in JetBrains Mono, amount right-aligned
- Client name in DM Sans
- Date + factura in muted data font
### SKU Mappings — Mobile
- Each mapping = expandable card
- Collapsed: SKU + product name + type badge (KIT/SIMPLU)
- Expanded: Full CODMAT list with quantities
- Search: Full-width sticky search bar at top
- Filter: Horizontal scrollable type chips
### Logs — Mobile
- Timeline view instead of table
- Each log entry = timestamp + status icon + summary
- Tap to expand full log details
- Infinite scroll with date separators
### Settings — Mobile
- Standard stacked form layout
- Full-width inputs
- Toggle switches for boolean settings (min 44px touch target)
- Save button sticky at bottom
### Gestures
- **Pull to refresh** on Dashboard: triggers sync status check
- **Swipe left** on order card: reveal quick actions
- **Long press** on SKU mapping: copy CODMAT to clipboard
- **No swipe navigation** between pages (use bottom tabs)
### Mobile Typography Adjustments
| Level | Desktop | Mobile |
|-------|---------|--------|
| Page title | 18px | 16px |
| Body | 14px | 14px (no change) |
| Data cell | 13px | 13px (no change) |
| Data small | 12px | 12px (no change) |
| Table header | 12px | 11px |
### Responsive Images & Icons
- Use Bootstrap Icons throughout (already loaded via CDN)
- Icon size: 16px desktop, 20px mobile (larger touch targets)
- No images in the admin interface (data-only)
## Decisions Log
| Date | Decision | Rationale |
|------|----------|-----------|
| 2026-03-27 | Initial design system created | Created by /design-consultation. Industrial/utilitarian aesthetic with amber accent, Space Grotesk + DM Sans + JetBrains Mono. |
| 2026-03-27 | Amber accent over blue | Every admin tool is blue. Amber reads as "operational" and gives the tool its own identity. Confirmed by Claude subagent ("Control Room Noir" also converged on amber). |
| 2026-03-27 | JetBrains Mono for data tables | Both primary analysis and subagent independently recommended monospace for data tables. Scannability win outweighs the ~15% wider columns. |
| 2026-03-27 | Warm tones throughout | Off-white (#F8F7F5) instead of clinical gray. Warm black text instead of blue-gray. Makes the tool feel handcrafted. |
| 2026-03-27 | Glowing status dots for errors | Problems glow (box-shadow), success is calm. Operator's eye is pulled to rows that need action. Inspired by subagent's "LED indicator" concept. |
| 2026-03-27 | Full mobile design | Bottom nav, card-based order views, touch-optimized gestures. Supports quick-glance usage from phone. |

View File

@@ -1,74 +1,3 @@
-- ====================================================================
-- PACK_IMPORT_COMENZI
-- Package pentru importul comenzilor din platforme web (GoMag, etc.)
-- in sistemul ROA Oracle.
--
-- Dependinte:
-- Packages: PACK_COMENZI (adauga_comanda, adauga_articol_comanda)
-- pljson (pljson_list, pljson) - instalat in CONTAFIN_ORACLE,
-- accesat prin PUBLIC SYNONYM
-- Tabele: ARTICOLE_TERTI (mapari SKU -> CODMAT)
-- NOM_ARTICOLE (nomenclator articole ROA)
-- COMENZI (verificare duplicat comanda_externa)
-- CRM_POLITICI_PRETURI (flag PRETURI_CU_TVA per politica)
-- CRM_POLITICI_PRET_ART (preturi componente kituri)
--
-- Proceduri publice:
--
-- importa_comanda(...)
-- Importa o comanda completa: creeaza comanda + adauga articolele.
-- p_json_articole accepta:
-- - array JSON: [{"sku":"X","quantity":"1","price":"10","vat":"19"}, ...]
-- - obiect JSON: {"sku":"X","quantity":"1","price":"10","vat":"19"}
-- Optional per articol: "id_pol":"5" — politica de pret specifica
-- (pentru transport/discount cu politica separata de cea a comenzii)
-- Valorile sku, quantity, price, vat sunt extrase ca STRING si convertite.
-- Daca comanda exista deja (comanda_externa), nu se dubleaza.
-- La eroare ridica RAISE_APPLICATION_ERROR(-20001, mesaj).
-- Returneaza v_id_comanda (OUT) = ID-ul comenzii create.
--
-- Parametri kit pricing:
-- p_kit_mode — 'distributed' | 'separate_line' | NULL
-- distributed: discountul fata de suma componentelor se distribuie
-- proportional in pretul fiecarei componente
-- separate_line: componentele se insereaza la pret plin +
-- linii discount separate per-kit sub componente, grupate pe cota TVA
-- p_id_pol_productie — politica de pret pentru articole de productie
-- (cont in 341/345); NULL = nu se foloseste
-- p_kit_discount_codmat — CODMAT-ul articolului discount (Mode separate_line)
-- p_kit_discount_id_pol — id_pol pentru liniile discount (Mode separate_line)
--
-- Logica cautare articol per SKU:
-- 1. Mapari speciale din ARTICOLE_TERTI (reimpachetare, seturi compuse)
-- - daca SKU are >1 rand si p_kit_mode IS NOT NULL: kit pricing logic
-- - altfel (1 rand sau kit_mode NULL): pret web / cantitate_roa direct
-- 2. Fallback: cautare directa in NOM_ARTICOLE dupa CODMAT = SKU
--
-- get_last_error / clear_error
-- Management erori pentru orchestratorul VFP.
--
-- Exemplu utilizare:
-- DECLARE
-- v_id NUMBER;
-- BEGIN
-- PACK_IMPORT_COMENZI.importa_comanda(
-- p_nr_comanda_ext => '479317993',
-- p_data_comanda => SYSDATE,
-- p_id_partener => 1424,
-- p_json_articole => '[{"sku":"5941623003366","quantity":"1.00","price":"40.99","vat":"21"}]',
-- p_id_pol => 39,
-- v_id_comanda => v_id);
-- DBMS_OUTPUT.PUT_LINE('ID comanda: ' || v_id);
-- END;
-- 20.03.2026 - dual policy vanzare/productie, kit pricing distributed/separate_line, SKU→CODMAT via ARTICOLE_TERTI
-- 20.03.2026 - kit discount deferred cross-kit (separate_line, merge-on-collision)
-- 20.03.2026 - merge_or_insert_articol: merge cantitati cand kit+individual au acelasi articol/pret
-- 20.03.2026 - kit pricing extins pt reambalari single-component (cantitate_roa > 1)
-- 21.03.2026 - diagnostic detaliat discount kit (id_pol, id_art, codmat in eroare)
-- 21.03.2026 - fix discount amount: v_disc_amt e per-kit, nu se imparte la v_cantitate_web
-- 25.03.2026 - skip negative kit discount (markup), ROUND prices to nzecimale_pretv
-- 25.03.2026 - kit discount inserat per-kit sub componente (nu deferred cross-kit)
-- ====================================================================
CREATE OR REPLACE PACKAGE PACK_IMPORT_COMENZI AS
-- Variabila package pentru ultima eroare (pentru orchestrator VFP)
@@ -98,6 +27,31 @@ END PACK_IMPORT_COMENZI;
/
CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_COMENZI AS
-- ====================================================================
-- PACK_IMPORT_COMENZI
-- Package pentru importul comenzilor din platforme web (GoMag, etc.)
-- in sistemul ROA Oracle.
--
-- Dependinte:
-- Packages: PACK_COMENZI (adauga_comanda, adauga_articol_comanda)
-- pljson (pljson_list, pljson) - instalat in CONTAFIN_ORACLE,
-- accesat prin PUBLIC SYNONYM
-- Tabele: ARTICOLE_TERTI (mapari SKU -> CODMAT)
-- NOM_ARTICOLE (nomenclator articole ROA)
-- COMENZI (verificare duplicat comanda_externa)
-- CRM_POLITICI_PRETURI (flag PRETURI_CU_TVA per politica)
-- CRM_POLITICI_PRET_ART (preturi componente kituri)
-- 20.03.2026 - dual policy vanzare/productie, kit pricing distributed/separate_line, SKU→CODMAT via ARTICOLE_TERTI
-- 20.03.2026 - kit discount deferred cross-kit (separate_line, merge-on-collision)
-- 20.03.2026 - merge_or_insert_articol: merge cantitati cand kit+individual au acelasi articol/pret
-- 20.03.2026 - kit pricing extins pt reambalari single-component (cantitate_roa > 1)
-- 21.03.2026 - diagnostic detaliat discount kit (id_pol, id_art, codmat in eroare)
-- 21.03.2026 - fix discount amount: v_disc_amt e per-kit, nu se imparte la v_cantitate_web
-- 25.03.2026 - skip negative kit discount (markup), ROUND prices to nzecimale_pretv
-- 25.03.2026 - kit discount inserat per-kit sub componente (nu deferred cross-kit)
-- ====================================================================
-- Constante pentru configurare
c_id_util CONSTANT NUMBER := -3; -- Sistem
c_interna CONSTANT NUMBER := 2; -- Comenzi de la client (web)