{
  "spec": "quick-html/v0",
  "id": "timesheet",
  "version": "0.1.0",
  "name": "Timesheet",
  "description": "A4 weekly timesheet: hours per task across Mon–Sun with row totals, daily column totals and a grand total that reconcile, an optional rate strip that turns it into a pre-invoice, and a two-party sign-off. Use when hours must be submitted for approval.",
  "useWhen": [
    "timesheet",
    "weekly hours",
    "log my hours",
    "hours for approval",
    "billable hours record",
    "contractor hours",
    "urenregistratie",
    "urenbriefje",
    "Stundenzettel",
    "feuille de temps",
    "hoja de horas"
  ],
  "format": "printable",
  "theme": "business-finance",
  "audience": [
    "freelance",
    "admin",
    "finance"
  ],
  "tags": [
    "hours",
    "billing",
    "weekly",
    "approval",
    "consultant"
  ],
  "language": "en",
  "page": {
    "size": "A4",
    "orientation": "portrait"
  },
  "modules": [
    "edit-overlay",
    "print-helper"
  ],
  "slots": [
    {
      "name": "doc-title",
      "type": "text",
      "required": true,
      "example": "Timesheet week 36 — Tobias Reinders",
      "notes": "Browser tab title; used as the download filename."
    },
    {
      "name": "worker-name",
      "type": "text",
      "required": true,
      "example": "Tobias Reinders",
      "notes": "The person who worked the hours."
    },
    {
      "name": "worker-details",
      "type": "html",
      "required": true,
      "example": "<p>Interim Data Engineer · Reinders Data Works</p><p>Kanaaldijk-Noord 12, 5642 JA Eindhoven</p>",
      "notes": "2–3 short <p> lines: role and company, address, contact, registration number."
    },
    {
      "name": "week-number",
      "type": "text",
      "required": true,
      "example": "36",
      "notes": "ISO week number of the period, digits only."
    },
    {
      "name": "period-line",
      "type": "text",
      "required": true,
      "example": "31 Aug – 6 Sep 2026",
      "notes": "Monday to Sunday of the same week, en dash between the dates."
    },
    {
      "name": "doc-status",
      "type": "text",
      "required": true,
      "example": "Submitted for approval",
      "notes": "Short chip text, 2–4 words: 'Draft', 'Submitted for approval', 'Approved'."
    },
    {
      "name": "client-name",
      "type": "text",
      "required": true,
      "example": "Kempen Precision B.V.",
      "notes": "Organisation the hours are billed to."
    },
    {
      "name": "client-details",
      "type": "html",
      "required": true,
      "example": "<p>Attn. Lieke Doornbos — Manager Data &amp; Analytics</p><p>De Run 4302, 5503 LN Veldhoven</p>",
      "notes": "1–3 short <p> lines: approver, address, purchase order or cost centre."
    },
    {
      "name": "day-1-label",
      "type": "text",
      "required": true,
      "example": "31/08",
      "notes": "Date under the fixed 'Mon' heading, day/month as dd/mm. The seven weekday names are static, only the dates change."
    },
    {
      "name": "day-2-label",
      "type": "text",
      "required": true,
      "example": "01/09",
      "notes": "Tuesday's date, same dd/mm format."
    },
    {
      "name": "day-3-label",
      "type": "text",
      "required": true,
      "example": "02/09",
      "notes": "Wednesday's date, same dd/mm format."
    },
    {
      "name": "day-4-label",
      "type": "text",
      "required": true,
      "example": "03/09",
      "notes": "Thursday's date, same dd/mm format."
    },
    {
      "name": "day-5-label",
      "type": "text",
      "required": true,
      "example": "04/09",
      "notes": "Friday's date, same dd/mm format."
    },
    {
      "name": "day-6-label",
      "type": "text",
      "required": true,
      "example": "05/09",
      "notes": "Saturday's date, same dd/mm format."
    },
    {
      "name": "day-7-label",
      "type": "text",
      "required": true,
      "example": "06/09",
      "notes": "Sunday's date, same dd/mm format."
    },
    {
      "name": "total-d1",
      "type": "text",
      "required": true,
      "example": "8,0",
      "notes": "Monday column total: sum of entry-d1 over every row. Write '–' when nothing was worked."
    },
    {
      "name": "total-d2",
      "type": "text",
      "required": true,
      "example": "8,5",
      "notes": "Tuesday column total: sum of entry-d2 over every row."
    },
    {
      "name": "total-d3",
      "type": "text",
      "required": true,
      "example": "8,0",
      "notes": "Wednesday column total: sum of entry-d3 over every row."
    },
    {
      "name": "total-d4",
      "type": "text",
      "required": true,
      "example": "9,0",
      "notes": "Thursday column total: sum of entry-d4 over every row."
    },
    {
      "name": "total-d5",
      "type": "text",
      "required": true,
      "example": "6,0",
      "notes": "Friday column total: sum of entry-d5 over every row."
    },
    {
      "name": "total-d6",
      "type": "text",
      "required": true,
      "example": "–",
      "notes": "Saturday column total: sum of entry-d6 over every row; '–' if the day is empty."
    },
    {
      "name": "total-d7",
      "type": "text",
      "required": true,
      "example": "–",
      "notes": "Sunday column total: sum of entry-d7 over every row; '–' if the day is empty."
    },
    {
      "name": "total-hours",
      "type": "text",
      "required": true,
      "example": "39,5",
      "notes": "Grand total. Must equal both the sum of all entry-total values and the sum of total-d1…total-d7."
    },
    {
      "name": "hourly-rate",
      "type": "text",
      "required": false,
      "example": "€ 82,50",
      "notes": "Inside the rates optional block. Agreed rate per hour, excl. VAT."
    },
    {
      "name": "billable-hours",
      "type": "text",
      "required": false,
      "example": "39,5",
      "notes": "Inside the rates optional block. Defaults to total-hours; lower only if some lines are non-billable."
    },
    {
      "name": "amount-due",
      "type": "text",
      "required": false,
      "example": "€ 3.258,75",
      "notes": "Inside the rates optional block. Computed: hourly-rate × billable-hours, excl. VAT."
    },
    {
      "name": "timesheet-notes",
      "type": "html",
      "required": false,
      "example": "<p>Thursday includes 1,0 h of unplanned support during the line 3 stoppage.</p>",
      "notes": "Inside the notes optional block: overtime, travel, absence or anything that explains an unusual day."
    },
    {
      "name": "worker-signatory",
      "type": "text",
      "required": true,
      "example": "Tobias Reinders",
      "notes": "Printed name under the contractor signature line; usually the same as worker-name."
    },
    {
      "name": "worker-sign-date",
      "type": "date",
      "required": true,
      "example": "7 Sep 2026",
      "notes": "Date of submission, format '7 Sep 2026'."
    },
    {
      "name": "approver-signatory",
      "type": "text",
      "required": true,
      "example": "Lieke Doornbos",
      "notes": "Printed name of the client-side approver; leave a placeholder if unknown."
    },
    {
      "name": "approver-sign-date",
      "type": "date",
      "required": true,
      "example": "8 Sep 2026",
      "notes": "Approval date, format '8 Sep 2026'; leave empty or placeholder if not yet approved."
    },
    {
      "name": "footer-line",
      "type": "text",
      "required": false,
      "example": "Reinders Data Works · Eindhoven · KvK 92184760 · VAT NL003941822B47",
      "notes": "One muted line: business name, city, registration or VAT number."
    }
  ],
  "repeats": [
    {
      "name": "entry",
      "description": "One row per task or project line, with the hours booked on each of the seven days and the row total.",
      "min": 1,
      "max": 14,
      "slots": [
        {
          "name": "entry-task",
          "type": "text",
          "required": true,
          "example": "Data platform migration — ETL rebuild",
          "notes": "Keep under ~40 characters so it stays on one line."
        },
        {
          "name": "entry-code",
          "type": "text",
          "required": true,
          "example": "KP-2411",
          "notes": "Short project, PO or cost-code, ≤10 characters; repeat the same code on related rows."
        },
        {
          "name": "entry-d1",
          "type": "text",
          "required": true,
          "example": "3,5",
          "notes": "Monday hours, one decimal with a comma; '–' when no hours were worked."
        },
        {
          "name": "entry-d2",
          "type": "text",
          "required": true,
          "example": "3,0",
          "notes": "Tuesday hours, same convention."
        },
        {
          "name": "entry-d3",
          "type": "text",
          "required": true,
          "example": "2,0",
          "notes": "Wednesday hours, same convention."
        },
        {
          "name": "entry-d4",
          "type": "text",
          "required": true,
          "example": "4,0",
          "notes": "Thursday hours, same convention."
        },
        {
          "name": "entry-d5",
          "type": "text",
          "required": true,
          "example": "1,5",
          "notes": "Friday hours, same convention."
        },
        {
          "name": "entry-d6",
          "type": "text",
          "required": true,
          "example": "–",
          "notes": "Saturday hours, same convention; usually '–'."
        },
        {
          "name": "entry-d7",
          "type": "text",
          "required": true,
          "example": "–",
          "notes": "Sunday hours, same convention; usually '–'."
        },
        {
          "name": "entry-total",
          "type": "text",
          "required": true,
          "example": "14,0",
          "notes": "Row total: sum of entry-d1…entry-d7 for this row."
        }
      ]
    }
  ],
  "optionals": [
    {
      "name": "rates",
      "description": "Rate strip below the grid (hourly rate, billable hours, amount due) that turns the sheet into a pre-invoice. Drop it when the sheet only records hours."
    },
    {
      "name": "notes",
      "description": "Short notes block for overtime, travel, absence or anything that explains an unusual day."
    }
  ],
  "changelog": [
    {
      "version": "0.1.0",
      "date": "2026-08-19",
      "notes": "Initial release: A4 weekly timesheet with days-across matrix, reconciling row and column totals, optional rate strip and two-party sign-off."
    }
  ],
  "agentInstructions": "One 'entry' row per task line; delete the data-example rows (preview only). ARITHMETIC-CRITICAL: compute entry-total for each row (sum of its seven day cells), each day total (total-d1…total-d7 = that day summed down all rows), and total-hours — then verify that the sum of the row totals equals the sum of the column totals equals total-hours. If they disagree, correct the cells, never the totals. Use one decimal convention throughout and never mix: the placeholders use a comma and exactly one decimal ('7,5', '8,0'). Write '–' in every cell with no hours, including empty day totals, so zero reads differently from not-filled-in. Keep entry-task under ~40 chars. More than 12 h on one day is probably an error — flag it rather than entering it silently. In the rates strip, billable-hours defaults to total-hours and amount-due = hourly-rate × billable-hours, recomputed, never copied. Set day-1-label…day-7-label to the Mon–Sun dates (dd/mm), consistent with week-number and period-line; other dates as '7 Sep 2026'. Drop the rates or notes optional when there is nothing real to say. Leave the two signature lines empty for hand-signing. If the rate, codes or client details are unknown, leave placeholders like [YOUR HOURLY RATE] and tell the user to fill them via the built-in Edit button.",
  "license": "MIT",
  "authors": [
    {
      "github": "bvrln"
    }
  ]
}
